aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/efficiency_guide/functions.xml
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/efficiency_guide/functions.xml')
-rw-r--r--system/doc/efficiency_guide/functions.xml141
1 files changed, 76 insertions, 65 deletions
diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml
index ec1a45eaa9..9616df554e 100644
--- a/system/doc/efficiency_guide/functions.xml
+++ b/system/doc/efficiency_guide/functions.xml
@@ -8,17 +8,17 @@
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
</legalnotice>
<title>Functions</title>
@@ -30,17 +30,18 @@
</header>
<section>
- <title>Pattern matching</title>
- <p>Pattern matching in function head and in <c>case</c> and <c>receive</c>
- clauses are optimized by the compiler. With a few exceptions, there is nothing
- to gain by rearranging clauses.</p>
+ <title>Pattern Matching</title>
+ <p>Pattern matching in function head as well as in <c>case</c> and
+ <c>receive</c> 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 <em>last</em> will usually
- be slightly faster than placing it <em>first</em>.</p>
+ does not rearrange clauses that match binaries. Placing the
+ clause that matches against the empty binary <em>last</em> is usually
+ slightly faster than placing it <em>first</em>.</p>
- <p>Here is a rather contrived example to show another exception:</p>
+ <p>The following is a rather unnatural example to show another
+ exception:</p>
<p><em>DO NOT</em></p>
<code type="erl">
@@ -53,27 +54,30 @@ atom_map1(five) -> 5;
atom_map1(six) -> 6.</code>
<p>The problem is the clause with the variable <c>Int</c>.
- Since a variable can match anything, including the atoms
- <c>four</c>, <c>five</c>, and <c>six</c> that the following clauses
- also will match, the compiler must generate sub-optimal code that will
- execute as follows:</p>
+ As a variable can match anything, including the atoms
+ <c>four</c>, <c>five</c>, and <c>six</c>, which the following clauses
+ also match, the compiler must generate suboptimal code that
+ executes as follows:</p>
- <p>First the input value is compared to <c>one</c>, <c>two</c>, and
+ <list type="bulleted">
+ <item>First, the input value is compared to <c>one</c>, <c>two</c>, and
<c>three</c> (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>
+ one of the first three clauses to execute (if any).</item>
+
+ <item>>If none of the first three clauses match, the fourth clause
+ match as a variable always matches.</item>
- <p>If none of the first three clauses matched, the fourth clause
- will match since a variable always matches. If the guard test
- <c>is_integer(Int)</c> succeeds, the fourth clause will be
- executed.</p>
+ <item>If the guard test <c>is_integer(Int)</c> succeeds, the fourth
+ clause is executed.</item>
- <p>If the guard test failed, the input value is compared to
+ <item>If the guard test fails, the input value is compared to
<c>four</c>, <c>five</c>, and <c>six</c>, and the appropriate clause
- is selected. (There will be a <c>function_clause</c> exception if
- none of the values matched.)</p>
+ is selected. (There is a <c>function_clause</c> exception if none of
+ the values matched.)</item>
+ </list>
- <p>Rewriting to either</p>
+ <p>Rewriting to either:</p>
<p><em>DO</em></p>
<code type="erl"><![CDATA[
@@ -85,7 +89,7 @@ atom_map2(five) -> 5;
atom_map2(six) -> 6;
atom_map2(Int) when is_integer(Int) -> Int.]]></code>
- <p>or</p>
+ <p>or:</p>
<p><em>DO</em></p>
<code type="erl"><![CDATA[
@@ -97,9 +101,9 @@ atom_map3(four) -> 4;
atom_map3(five) -> 5;
atom_map3(six) -> 6.]]></code>
- <p>will give slightly more efficient matching code.</p>
+ <p>gives slightly more efficient matching code.</p>
- <p>Here is a less contrived example:</p>
+ <p>Another example:</p>
<p><em>DO NOT</em></p>
<code type="erl"><![CDATA[
@@ -116,7 +120,8 @@ map_pairs1(Map, [X|Xs], [Y|Ys]) ->
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>If the function is rewritten as follows, the compiler is free to
+ rearrange the clauses:</p>
<p><em>DO</em></p>
<code type="erl"><![CDATA[
@@ -127,8 +132,7 @@ map_pairs2(_Map, [_|_]=Xs, [] ) ->
map_pairs2(Map, [X|Xs], [Y|Ys]) ->
[Map(X, Y)|map_pairs2(Map, Xs, Ys)].]]></code>
- <p>the compiler is free to rearrange the clauses. It will generate code
- similar to this</p>
+ <p>The compiler will generate code similar to this:</p>
<p><em>DO NOT (already done by the compiler)</em></p>
<code type="erl"><![CDATA[
@@ -145,31 +149,35 @@ explicit_map_pairs(Map, Xs0, Ys0) ->
Ys0
end.]]></code>
- <p>which should be slightly faster for presumably the most common case
+ <p>This is slightly faster for probably 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 <c>Xs</c>.)</p>
+ (Another advantage is that Dialyzer can deduce a better type
+ for the <c>Xs</c> variable.)</p>
</section>
<section>
- <title>Function Calls </title>
+ <title>Function Calls</title>
- <p>Here is an intentionally rough guide to the relative costs of
- different kinds of calls. It is based on benchmark figures run on
+ <p>This is an intentionally rough guide to the relative costs of
+ different calls. It is based on benchmark figures run on
Solaris/Sparc:</p>
<list type="bulleted">
<item>Calls to local or external functions (<c>foo()</c>, <c>m:foo()</c>)
- are the fastest kind of calls.</item>
+ are the fastest calls.</item>
+
<item>Calling or applying a fun (<c>Fun()</c>, <c>apply(Fun, [])</c>)
- is about <em>three times</em> as expensive as calling a local function.</item>
+ is about <em>three times</em> as expensive as calling a local
+ function.</item>
+
<item>Applying an exported function (<c>Mod:Name()</c>,
- <c>apply(Mod, Name, [])</c>) is about twice as expensive as calling a fun,
- or about <em>six times</em> as expensive as calling a local function.</item>
+ <c>apply(Mod, Name, [])</c>) is about twice as expensive as calling
+ a fun or about <em>six times</em> as expensive as calling a local
+ function.</item>
</list>
<section>
- <title>Notes and implementation details</title>
+ <title>Notes and Implementation Details</title>
<p>Calling and applying a fun does not involve any hash-table lookup.
A fun contains an (indirect) pointer to the function that implements
@@ -178,42 +186,44 @@ explicit_map_pairs(Map, Xs0, Ys0) ->
<warning><p><em>Tuples are not fun(s)</em>.
A "tuple fun", <c>{Module,Function}</c>, is not a fun.
The cost for calling a "tuple fun" is similar to that
- of <c>apply/3</c> or worse. Using "tuple funs" is <em>strongly discouraged</em>,
- as they may not be supported in a future release,
- and because there exists a superior alternative since the R10B
- release, namely the <c>fun Module:Function/Arity</c> syntax.</p></warning>
+ of <c>apply/3</c> or worse.
+ Using "tuple funs" is <em>strongly discouraged</em>,
+ as they might not be supported in a future Erlang/OTP release,
+ and because there exists a superior alternative from R10B,
+ namely the <c>fun Module:Function/Arity</c> syntax.</p></warning>
<p><c>apply/3</c> must look up the code for the function to execute
- in a hash table. Therefore, it will always be slower than a
+ in a hash table. It is therefore always 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>
+ whether you write:</p>
<code type="erl">
Module:Function(Arg1, Arg2)</code>
- <p>or</p>
+ <p>or:</p>
<code type="erl">
apply(Module, Function, [Arg1,Arg2])</code>
- <p>(The compiler internally rewrites the latter code into the former.)</p>
+ <p>The compiler internally rewrites the latter code into the
+ former.</p>
- <p>The following code</p>
+ <p>The following code is slightly slower because the shape of the
+ list of arguments is unknown at compile time.</p>
<code type="erl">
apply(Module, Function, Arguments)</code>
- <p>is slightly slower because the shape of the list of arguments
- is not known at compile time.</p>
</section>
</section>
<section>
- <title>Memory usage in recursion</title>
- <p>When writing recursive functions it is preferable to make them
- tail-recursive so that they can execute in constant memory space.</p>
+ <title>Memory Usage in Recursion</title>
+ <p>When writing recursive functions, it is preferable to make them
+ tail-recursive so that they can execute in constant memory space:</p>
+
<p><em>DO</em></p>
<code type="none">
list_length(List) ->
@@ -224,13 +234,14 @@ list_length([], AccLen) ->
list_length([_|Tail], AccLen) ->
list_length(Tail, AccLen + 1). % Tail-recursive</code>
+
<p><em>DO NOT</em></p>
+
<code type="none">
list_length([]) ->
0. % Base case
list_length([_ | Tail]) ->
list_length(Tail) + 1. % Not tail-recursive</code>
</section>
-
</chapter>