~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to system/doc/efficiency_guide/functions.xml

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?xml version="1.0" encoding="latin1" ?>
 
2
<!DOCTYPE chapter SYSTEM "chapter.dtd">
 
3
 
 
4
<chapter>
 
5
  <header>
 
6
    <copyright>
 
7
      <year>2001</year><year>2010</year>
 
8
      <holder>Ericsson AB. All Rights Reserved.</holder>
 
9
    </copyright>
 
10
    <legalnotice>
 
11
      The contents of this file are subject to the Erlang Public License,
 
12
      Version 1.1, (the "License"); you may not use this file except in
 
13
      compliance with the License. You should have received a copy of the
 
14
      Erlang Public License along with this software. If not, it can be
 
15
      retrieved online at http://www.erlang.org/.
 
16
 
 
17
      Software distributed under the License is distributed on an "AS IS"
 
18
      basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 
19
      the License for the specific language governing rights and limitations
 
20
      under the License.
 
21
 
 
22
    </legalnotice>
 
23
 
 
24
    <title>Functions</title>
 
25
    <prepared>Bjorn Gustavsson</prepared>
 
26
    <docno></docno>
 
27
    <date>2007-11-22</date>
 
28
    <rev></rev>
 
29
    <file>functions.xml</file>
 
30
  </header>
 
31
 
 
32
  <section>
 
33
    <title>Pattern matching</title>
 
34
    <p>Pattern matching in function head and in <c>case</c> and <c>receive</c>
 
35
     clauses are optimized by the compiler. With a few exceptions, there is nothing
 
36
     to gain by rearranging clauses.</p>
 
37
 
 
38
    <p>One exception is pattern matching of binaries. The compiler
 
39
    will not rearrange clauses that match binaries. Placing the
 
40
    clause that matches against the empty binary <em>last</em> will usually
 
41
    be slightly faster than placing it <em>first</em>.</p>
 
42
 
 
43
    <p>Here is a rather contrived example to show another exception:</p>
 
44
 
 
45
    <p><em>DO NOT</em></p>
 
46
    <code type="erl">
 
47
atom_map1(one) -> 1;
 
48
atom_map1(two) -> 2;
 
49
atom_map1(three) -> 3;
 
50
atom_map1(Int) when is_integer(Int) -> Int;
 
51
atom_map1(four) -> 4;
 
52
atom_map1(five) -> 5;
 
53
atom_map1(six) -> 6.</code>
 
54
 
 
55
     <p>The problem is the clause with the variable <c>Int</c>.
 
56
     Since a variable can match anything, including the atoms
 
57
     <c>four</c>, <c>five</c>, and <c>six</c> that the following clauses
 
58
     also will match, the compiler must generate sub-optimal code that will
 
59
     execute as follows:</p>
 
60
 
 
61
     <p>First the input value is compared to <c>one</c>, <c>two</c>, and
 
62
     <c>three</c> (using a single instruction that does a binary search;
 
63
     thus, quite efficient even if there are many values) to select which
 
64
     one of the first three clauses to execute (if any).</p>
 
65
 
 
66
     <p>If none of the first three clauses matched, the fourth clause
 
67
     will match since a variable always matches. If the guard test
 
68
     <c>is_integer(Int)</c> succeeds, the fourth clause will be
 
69
     executed.</p>
 
70
 
 
71
     <p>If the guard test failed, the input value is compared to
 
72
     <c>four</c>, <c>five</c>, and <c>six</c>, and the appropriate clause
 
73
     is selected. (There will be a <c>function_clause</c> exception if
 
74
     none of the values matched.)</p>
 
75
 
 
76
     <p>Rewriting to either</p>
 
77
 
 
78
     <p><em>DO</em></p>
 
79
     <code type="erl"><![CDATA[
 
80
atom_map2(one) -> 1;
 
81
atom_map2(two) -> 2;
 
82
atom_map2(three) -> 3;
 
83
atom_map2(four) -> 4;
 
84
atom_map2(five) -> 5;
 
85
atom_map2(six) -> 6;
 
86
atom_map2(Int) when is_integer(Int) -> Int.]]></code>
 
87
 
 
88
     <p>or</p> 
 
89
 
 
90
     <p><em>DO</em></p>
 
91
     <code type="erl"><![CDATA[
 
92
atom_map3(Int) when is_integer(Int) -> Int;
 
93
atom_map3(one) -> 1;
 
94
atom_map3(two) -> 2;
 
95
atom_map3(three) -> 3;
 
96
atom_map3(four) -> 4;
 
97
atom_map3(five) -> 5;
 
98
atom_map3(six) -> 6.]]></code>
 
99
 
 
100
     <p>will give slightly more efficient matching code.</p>
 
101
 
 
102
     <p>Here is a less contrived example:</p>
 
103
 
 
104
     <p><em>DO NOT</em></p>
 
105
     <code type="erl"><![CDATA[
 
106
map_pairs1(_Map, [], Ys) ->
 
107
    Ys;
 
108
map_pairs1(_Map, Xs, [] ) ->
 
109
    Xs;
 
110
map_pairs1(Map, [X|Xs], [Y|Ys]) ->
 
111
    [Map(X, Y)|map_pairs1(Map, Xs, Ys)].]]></code>
 
112
 
 
113
     <p>The first argument is <em>not</em> a problem. It is variable, but it
 
114
     is a variable in all clauses. The problem is the variable in the second
 
115
     argument, <c>Xs</c>, in the middle clause. Because the variable can
 
116
     match anything, the compiler is not allowed to rearrange the clauses,
 
117
     but must generate code that matches them in the order written.</p>
 
118
 
 
119
     <p>If the function is rewritten like this</p>
 
120
 
 
121
     <p><em>DO</em></p>
 
122
     <code type="erl"><![CDATA[
 
123
map_pairs2(_Map, [], Ys) ->
 
124
    Ys;
 
125
map_pairs2(_Map, [_|_]=Xs, [] ) ->
 
126
    Xs;
 
127
map_pairs2(Map, [X|Xs], [Y|Ys]) ->
 
128
    [Map(X, Y)|map_pairs2(Map, Xs, Ys)].]]></code>
 
129
 
 
130
    <p>the compiler is free rearrange the clauses. It will generate code
 
131
    similar to this</p>
 
132
 
 
133
    <p><em>DO NOT (already done by the compiler)</em></p>
 
134
    <code type="erl"><![CDATA[
 
135
explicit_map_pairs(Map, Xs0, Ys0) ->
 
136
    case Xs0 of
 
137
        [X|Xs] ->
 
138
            case Ys0 of
 
139
                [Y|Ys] ->
 
140
                    [Map(X, Y)|explicit_map_pairs(Map, Xs, Ys)];
 
141
                [] ->
 
142
                    Xs0
 
143
            end;
 
144
        [] ->
 
145
            Ys0
 
146
    end.]]></code>
 
147
      
 
148
    <p>which should be slightly faster for presumably the most common case
 
149
    that the input lists are not empty or very short.
 
150
    (Another advantage is that Dialyzer is able to deduce a better type
 
151
    for the variable <c>Xs</c>.)</p>
 
152
  </section>
 
153
 
 
154
  <section>
 
155
    <title>Function Calls </title>
 
156
 
 
157
    <p>Here is an intentionally rough guide to the relative costs of
 
158
    different kinds of calls. It is based on benchmark figures run on
 
159
    Solaris/Sparc:</p>
 
160
 
 
161
    <list type="bulleted">
 
162
    <item>Calls to local or external functions (<c>foo()</c>, <c>m:foo()</c>)
 
163
    are the fastest kind of calls.</item>
 
164
    <item>Calling or applying a fun (<c>Fun()</c>, <c>apply(Fun, [])</c>)
 
165
    is about <em>three times</em> as expensive as calling a local function.</item>
 
166
    <item>Applying an exported function (<c>Mod:Name()</c>,
 
167
    <c>apply(Mod, Name, [])</c>) is about twice as expensive as calling a fun,
 
168
    or about <em>six times</em> as expensive as calling a local function.</item>
 
169
    </list>
 
170
 
 
171
    <section>
 
172
       <title>Notes and implementation details</title>
 
173
 
 
174
       <p>Calling and applying a fun does not involve any hash-table lookup.
 
175
       A fun contains an (indirect) pointer to the function that implements
 
176
       the fun.</p>
 
177
 
 
178
       <warning><p><em>Tuples are not fun(s)</em>.
 
179
       A "tuple fun", <c>{Module,Function}</c>, is not a fun.
 
180
       The cost for calling a "tuple fun" is similar to that
 
181
       of <c>apply/3</c> or worse. Using "tuple funs" is <em>strongly discouraged</em>,
 
182
       as they may not be supported in a future release,
 
183
       and because there exists a superior alternative since the R10B
 
184
       release, namely the <c>fun Module:Function/Arity</c> syntax.</p></warning>
 
185
 
 
186
       <p><c>apply/3</c> must look up the code for the function to execute
 
187
       in a hash table. Therefore, it will always be slower than a
 
188
       direct call or a fun call.</p>
 
189
 
 
190
       <p>It no longer matters (from a performance point of view)
 
191
       whether you write</p>
 
192
 
 
193
       <code type="erl">
 
194
Module:Function(Arg1, Arg2)</code>
 
195
 
 
196
       <p>or</p>
 
197
 
 
198
       <code type="erl">
 
199
apply(Module, Function, [Arg1,Arg2])</code>
 
200
 
 
201
       <p>(The compiler internally rewrites the latter code into the former.)</p>
 
202
 
 
203
       <p>The following code</p>
 
204
 
 
205
       <code type="erl">
 
206
apply(Module, Function, Arguments)</code>
 
207
 
 
208
       <p>is slightly slower because the shape of the list of arguments
 
209
       is not known at compile time.</p>
 
210
    </section>
 
211
  </section>
 
212
 
 
213
  <section>
 
214
    <title>Memory usage in recursion</title>
 
215
    <p>When writing recursive functions it is preferable to make them
 
216
      tail-recursive so that they can execute in constant memory space.</p>
 
217
    <p><em>DO</em></p>
 
218
    <code type="none">
 
219
list_length(List) ->
 
220
    list_length(List, 0).
 
221
 
 
222
list_length([], AccLen) -> 
 
223
    AccLen; % Base case
 
224
 
 
225
list_length([_|Tail], AccLen) ->
 
226
    list_length(Tail, AccLen + 1). % Tail-recursive</code>
 
227
    <p><em>DO NOT</em></p>
 
228
    <code type="none">
 
229
list_length([]) ->
 
230
    0. % Base case
 
231
list_length([_ | Tail]) ->
 
232
    list_length(Tail) + 1. % Not tail-recursive</code>
 
233
  </section>
 
234
 
 
235
</chapter>
 
236