Sophie

Sophie

distrib > Fedora > 17 > i386 > by-pkgid > 675c8c8167236dfcf8d66da674f931e8 > files > 48

erlang-doc-R15B-03.3.fc17.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns:fn="http://www.w3.org/2005/02/xpath-functions">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="../otp_doc.css" type="text/css">
<title>Erlang -- Functions</title>
</head>
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000"><div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="../js/flipmenu/flipmenu.js"></script><script id="js2" type="text/javascript" src="../js/erlresolvelinks.js"></script><script language="JavaScript" type="text/javascript">
            <!--
              function getWinHeight() {
                var myHeight = 0;
                if( typeof( window.innerHeight ) == 'number' ) {
                  //Non-IE
                  myHeight = window.innerHeight;
                } else if( document.documentElement && ( document.documentElement.clientWidth ||
                                                         document.documentElement.clientHeight ) ) {
                  //IE 6+ in 'standards compliant mode'
                  myHeight = document.documentElement.clientHeight;
                } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
                  //IE 4 compatible
                  myHeight = document.body.clientHeight;
                }
                return myHeight;
              }

              function setscrollpos() {
                var objf=document.getElementById('loadscrollpos');
                 document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2;
              }

              function addEvent(obj, evType, fn){
                if (obj.addEventListener){
                obj.addEventListener(evType, fn, true);
                return true;
              } else if (obj.attachEvent){
                var r = obj.attachEvent("on"+evType, fn);
                return r;
              } else {
                return false;
              }
             }

             addEvent(window, 'load', setscrollpos);

             //--></script><div id="leftnav"><div class="innertube">
<img alt="Erlang logo" src="../erlang-logo.png"><br><small><a href="users_guide.html">User's Guide</a><br><a href="../pdf/otp-system-documentation-5.9.3.1.pdf">PDF</a><br><a href="../index.html">Top</a></small><p><strong>Efficiency Guide</strong><br><strong>User's Guide</strong><br><small>Version 5.9.3.1</small></p>
<br><a href="javascript:openAllFlips()">Expand All</a><br><a href="javascript:closeAllFlips()">Contract All</a><p><small><strong>Chapters</strong></small></p>
<ul class="flipMenu" imagepath="../js/flipmenu">
<li id="no" title="Introduction" expanded="false">Introduction<ul>
<li><a href="introduction.html">
              Top of chapter
            </a></li>
<li title="Purpose"><a href="introduction.html#id62954">Purpose</a></li>
<li title="Prerequisites"><a href="introduction.html#id65420">Prerequisites</a></li>
</ul>
</li>
<li id="no" title="The Eight Myths of Erlang Performance" expanded="false">The Eight Myths of Erlang Performance<ul>
<li><a href="myths.html">
              Top of chapter
            </a></li>
<li title="Myth: Funs are slow"><a href="myths.html#id64448">Myth: Funs are slow</a></li>
<li title="Myth: List comprehensions are slow"><a href="myths.html#id61406">Myth: List comprehensions are slow</a></li>
<li title="Myth: Tail-recursive functions are MUCH faster
    than recursive functions"><a href="myths.html#id62291">Myth: Tail-recursive functions are MUCH faster
    than recursive functions</a></li>
<li title="Myth: '++' is always bad"><a href="myths.html#id60058">Myth: '++' is always bad</a></li>
<li title="Myth: Strings are slow"><a href="myths.html#id62534">Myth: Strings are slow</a></li>
<li title="Myth: Repairing a Dets file is very slow"><a href="myths.html#id61135">Myth: Repairing a Dets file is very slow</a></li>
<li title="Myth: BEAM is a stack-based byte-code virtual machine (and therefore slow)"><a href="myths.html#id64006">Myth: BEAM is a stack-based byte-code virtual machine (and therefore slow)</a></li>
<li title="Myth: Use '_' to speed up your program when a variable is not used"><a href="myths.html#id64026">Myth: Use '_' to speed up your program when a variable is not used</a></li>
</ul>
</li>
<li id="no" title="Common Caveats" expanded="false">Common Caveats<ul>
<li><a href="commoncaveats.html">
              Top of chapter
            </a></li>
<li title="The timer module"><a href="commoncaveats.html#id62547">The timer module</a></li>
<li title="list_to_atom/1"><a href="commoncaveats.html#id61885">list_to_atom/1</a></li>
<li title="length/1"><a href="commoncaveats.html#id60806">length/1</a></li>
<li title="setelement/3"><a href="commoncaveats.html#id58300">setelement/3</a></li>
<li title="size/1"><a href="commoncaveats.html#id65402">size/1</a></li>
<li title="split_binary/2"><a href="commoncaveats.html#id60836">split_binary/2</a></li>
<li title="The '--' operator"><a href="commoncaveats.html#id61766">The '--' operator</a></li>
</ul>
</li>
<li id="no" title="Constructing and matching binaries" expanded="false">Constructing and matching binaries<ul>
<li><a href="binaryhandling.html">
              Top of chapter
            </a></li>
<li title="How binaries are implemented"><a href="binaryhandling.html#id62932">How binaries are implemented</a></li>
<li title="Constructing binaries"><a href="binaryhandling.html#id66066">Constructing binaries</a></li>
<li title="Matching binaries"><a href="binaryhandling.html#id63610">Matching binaries</a></li>
</ul>
</li>
<li id="no" title="List handling" expanded="false">List handling<ul>
<li><a href="listHandling.html">
              Top of chapter
            </a></li>
<li title="Creating a list"><a href="listHandling.html#id66709">Creating a list</a></li>
<li title="List comprehensions"><a href="listHandling.html#id66805">List comprehensions</a></li>
<li title="Deep and flat lists"><a href="listHandling.html#id66875">Deep and flat lists</a></li>
<li title="Why you should not worry about recursive lists functions"><a href="listHandling.html#id67017">Why you should not worry about recursive lists functions</a></li>
</ul>
</li>
<li id="loadscrollpos" title="Functions" expanded="true">Functions<ul>
<li><a href="functions.html">
              Top of chapter
            </a></li>
<li title="Pattern matching"><a href="functions.html#id67142">Pattern matching</a></li>
<li title="Function Calls "><a href="functions.html#id67362">Function Calls </a></li>
<li title="Memory usage in recursion"><a href="functions.html#id67506">Memory usage in recursion</a></li>
</ul>
</li>
<li id="no" title="Tables and databases" expanded="false">Tables and databases<ul>
<li><a href="tablesDatabases.html">
              Top of chapter
            </a></li>
<li title="Ets, Dets and Mnesia"><a href="tablesDatabases.html#id67596">Ets, Dets and Mnesia</a></li>
<li title="Ets specific"><a href="tablesDatabases.html#id67983">Ets specific</a></li>
<li title="Mnesia specific"><a href="tablesDatabases.html#id68087">Mnesia specific</a></li>
</ul>
</li>
<li id="no" title="Processes" expanded="false">Processes<ul>
<li><a href="processes.html">
              Top of chapter
            </a></li>
<li title="Creation of an Erlang process"><a href="processes.html#id68191">Creation of an Erlang process</a></li>
<li title="Process messages"><a href="processes.html#id68339">Process messages</a></li>
<li title="The SMP emulator"><a href="processes.html#id68531">The SMP emulator</a></li>
</ul>
</li>
<li id="no" title="Drivers" expanded="false">Drivers<ul>
<li><a href="drivers.html">
              Top of chapter
            </a></li>
<li title="Drivers and concurrency"><a href="drivers.html#id68634">Drivers and concurrency</a></li>
<li title="Avoiding copying of binaries when calling a driver"><a href="drivers.html#id68675">Avoiding copying of binaries when calling a driver</a></li>
<li title="Returning small binaries from a driver"><a href="drivers.html#id68743">Returning small binaries from a driver</a></li>
<li title="Returning big binaries without copying from a driver"><a href="drivers.html#id68777">Returning big binaries without copying from a driver</a></li>
</ul>
</li>
<li id="no" title="Advanced" expanded="false">Advanced<ul>
<li><a href="advanced.html">
              Top of chapter
            </a></li>
<li title="Memory"><a href="advanced.html#id68919">Memory</a></li>
<li title="System limits"><a href="advanced.html#id69276">System limits</a></li>
</ul>
</li>
<li id="no" title="Profiling" expanded="false">Profiling<ul>
<li><a href="profiling.html">
              Top of chapter
            </a></li>
<li title="Do not guess about performance - profile"><a href="profiling.html#id69579">Do not guess about performance - profile</a></li>
<li title="Big systems"><a href="profiling.html#id69661">Big systems</a></li>
<li title="What to look for"><a href="profiling.html#id69681">What to look for</a></li>
<li title="Tools"><a href="profiling.html#id69738">Tools</a></li>
<li title="Benchmarking"><a href="profiling.html#id70245">Benchmarking</a></li>
</ul>
</li>
</ul>
</div></div>
<div id="content">
<div class="innertube">
<h1>6 Functions</h1>
  

  <h3><a name="id67142">6.1 
        Pattern matching</a></h3>
    
    <p>Pattern matching in function head and in <span class="code">case</span> and <span class="code">receive</span>
     clauses are optimized by the compiler. With a few exceptions, there is nothing
     to gain by rearranging clauses.</p>

    <p>One exception is pattern matching of binaries. The compiler
    will not rearrange clauses that match binaries. Placing the
    clause that matches against the empty binary <strong>last</strong> will usually
    be slightly faster than placing it <strong>first</strong>.</p>

    <p>Here is a rather contrived example to show another exception:</p>

    <p><strong>DO NOT</strong></p>
    <div class="example"><pre>
atom_map1(one) -&gt; 1;
atom_map1(two) -&gt; 2;
atom_map1(three) -&gt; 3;
atom_map1(Int) when is_integer(Int) -&gt; Int;
atom_map1(four) -&gt; 4;
atom_map1(five) -&gt; 5;
atom_map1(six) -&gt; 6.</pre></div>

     <p>The problem is the clause with the variable <span class="code">Int</span>.
     Since a variable can match anything, including the atoms
     <span class="code">four</span>, <span class="code">five</span>, and <span class="code">six</span> that the following clauses
     also will match, the compiler must generate sub-optimal code that will
     execute as follows:</p>

     <p>First the input value is compared to <span class="code">one</span>, <span class="code">two</span>, and
     <span class="code">three</span> (using a single instruction that does a binary search;
     thus, quite efficient even if there are many values) to select which
     one of the first three clauses to execute (if any).</p>

     <p>If none of the first three clauses matched, the fourth clause
     will match since a variable always matches. If the guard test
     <span class="code">is_integer(Int)</span> succeeds, the fourth clause will be
     executed.</p>

     <p>If the guard test failed, the input value is compared to
     <span class="code">four</span>, <span class="code">five</span>, and <span class="code">six</span>, and the appropriate clause
     is selected. (There will be a <span class="code">function_clause</span> exception if
     none of the values matched.)</p>

     <p>Rewriting to either</p>

     <p><strong>DO</strong></p>
     <div class="example"><pre>
atom_map2(one) -&gt; 1;
atom_map2(two) -&gt; 2;
atom_map2(three) -&gt; 3;
atom_map2(four) -&gt; 4;
atom_map2(five) -&gt; 5;
atom_map2(six) -&gt; 6;
atom_map2(Int) when is_integer(Int) -&gt; Int.</pre></div>

     <p>or</p> 

     <p><strong>DO</strong></p>
     <div class="example"><pre>
atom_map3(Int) when is_integer(Int) -&gt; Int;
atom_map3(one) -&gt; 1;
atom_map3(two) -&gt; 2;
atom_map3(three) -&gt; 3;
atom_map3(four) -&gt; 4;
atom_map3(five) -&gt; 5;
atom_map3(six) -&gt; 6.</pre></div>

     <p>will give slightly more efficient matching code.</p>

     <p>Here is a less contrived example:</p>

     <p><strong>DO NOT</strong></p>
     <div class="example"><pre>
map_pairs1(_Map, [], Ys) -&gt;
    Ys;
map_pairs1(_Map, Xs, [] ) -&gt;
    Xs;
map_pairs1(Map, [X|Xs], [Y|Ys]) -&gt;
    [Map(X, Y)|map_pairs1(Map, Xs, Ys)].</pre></div>

     <p>The first argument is <strong>not</strong> a problem. It is variable, but it
     is a variable in all clauses. The problem is the variable in the second
     argument, <span class="code">Xs</span>, in the middle clause. Because the variable can
     match anything, the compiler is not allowed to rearrange the clauses,
     but must generate code that matches them in the order written.</p>

     <p>If the function is rewritten like this</p>

     <p><strong>DO</strong></p>
     <div class="example"><pre>
map_pairs2(_Map, [], Ys) -&gt;
    Ys;
map_pairs2(_Map, [_|_]=Xs, [] ) -&gt;
    Xs;
map_pairs2(Map, [X|Xs], [Y|Ys]) -&gt;
    [Map(X, Y)|map_pairs2(Map, Xs, Ys)].</pre></div>

    <p>the compiler is free to rearrange the clauses. It will generate code
    similar to this</p>

    <p><strong>DO NOT (already done by the compiler)</strong></p>
    <div class="example"><pre>
explicit_map_pairs(Map, Xs0, Ys0) -&gt;
    case Xs0 of
	[X|Xs] -&gt;
	    case Ys0 of
		[Y|Ys] -&gt;
		    [Map(X, Y)|explicit_map_pairs(Map, Xs, Ys)];
		[] -&gt;
		    Xs0
	    end;
	[] -&gt;
	    Ys0
    end.</pre></div>
      
    <p>which should be slightly faster for presumably the most common case
    that the input lists are not empty or very short.
    (Another advantage is that Dialyzer is able to deduce a better type
    for the variable <span class="code">Xs</span>.)</p>
  

  <h3><a name="id67362">6.2 
        Function Calls </a></h3>
    

    <p>Here is an intentionally rough guide to the relative costs of
    different kinds of calls. It is based on benchmark figures run on
    Solaris/Sparc:</p>

    <ul>
    <li>Calls to local or external functions (<span class="code">foo()</span>, <span class="code">m:foo()</span>)
    are the fastest kind of calls.</li>
    <li>Calling or applying a fun (<span class="code">Fun()</span>, <span class="code">apply(Fun, [])</span>)
    is about <strong>three times</strong> as expensive as calling a local function.</li>
    <li>Applying an exported function (<span class="code">Mod:Name()</span>,
    <span class="code">apply(Mod, Name, [])</span>) is about twice as expensive as calling a fun,
    or about <strong>six times</strong> as expensive as calling a local function.</li>
    </ul>

    <h4>Notes and implementation details</h4>
       

       <p>Calling and applying a fun does not involve any hash-table lookup.
       A fun contains an (indirect) pointer to the function that implements
       the fun.</p>

       <div class="warning">
<div class="label">Warning</div>
<div class="content"><p><p><strong>Tuples are not fun(s)</strong>.
       A "tuple fun", <span class="code">{Module,Function}</span>, is not a fun.
       The cost for calling a "tuple fun" is similar to that
       of <span class="code">apply/3</span> or worse. Using "tuple funs" is <strong>strongly discouraged</strong>,
       as they may not be supported in a future release,
       and because there exists a superior alternative since the R10B
       release, namely the <span class="code">fun Module:Function/Arity</span> syntax.</p></p></div>
</div>

       <p><span class="code">apply/3</span> must look up the code for the function to execute
       in a hash table. Therefore, it will always be slower than a
       direct call or a fun call.</p>

       <p>It no longer matters (from a performance point of view)
       whether you write</p>

       <div class="example"><pre>
Module:Function(Arg1, Arg2)</pre></div>

       <p>or</p>

       <div class="example"><pre>
apply(Module, Function, [Arg1,Arg2])</pre></div>

       <p>(The compiler internally rewrites the latter code into the former.)</p>

       <p>The following code</p>

       <div class="example"><pre>
apply(Module, Function, Arguments)</pre></div>

       <p>is slightly slower because the shape of the list of arguments
       is not known at compile time.</p>
    
  

  <h3><a name="id67506">6.3 
        Memory usage in recursion</a></h3>
    
    <p>When writing recursive functions it is preferable to make them
      tail-recursive so that they can execute in constant memory space.</p>
    <p><strong>DO</strong></p>
    <div class="example"><pre>
list_length(List) -&gt;
    list_length(List, 0).

list_length([], AccLen) -&gt; 
    AccLen; % Base case

list_length([_|Tail], AccLen) -&gt;
    list_length(Tail, AccLen + 1). % Tail-recursive</pre></div>
    <p><strong>DO NOT</strong></p>
    <div class="example"><pre>
list_length([]) -&gt;
    0. % Base case
list_length([_ | Tail]) -&gt;
    list_length(Tail) + 1. % Not tail-recursive</pre></div>
  

</div>
<div class="footer">
<hr>
<p>Copyright © 2001-2012 Ericsson AB. All Rights Reserved.</p>
</div>
</div>
</div></body>
</html>