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

« back to all changes in this revision

Viewing changes to system/doc/efficiency_guide/listhandling.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>2009</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>List handling</title>
 
25
    <prepared>Bjorn Gustavsson</prepared>
 
26
    <docno></docno>
 
27
    <date>2007-11-16</date>
 
28
    <rev></rev>
 
29
    <file>listHandling.xml</file>
 
30
  </header>
 
31
 
 
32
  <section>
 
33
    <title>Creating a list</title>
 
34
    
 
35
    <p>Lists can only be built starting from the end and attaching
 
36
    list elements at the beginning. If you use the <c>++</c> operator
 
37
    like this</p>
 
38
 
 
39
    <code type="erl">
 
40
List1 ++ List2</code>
 
41
 
 
42
    <p>you will create a new list which is copy of the elements in <c>List1</c>,
 
43
    followed by <c>List2</c>. Looking at how <c>lists:append/1</c> or <c>++</c> would be
 
44
    implemented in plain Erlang, it can be seen clearly that the first list
 
45
    is copied:</p>
 
46
 
 
47
    <code type="erl">
 
48
append([H|T], Tail) ->
 
49
    [H|append(T, Tail)];
 
50
append([], Tail) ->
 
51
    Tail.</code>
 
52
 
 
53
    <p>So the important thing when recursing and building a list is to
 
54
    make sure that you attach the new elements to the beginning of the list,
 
55
    so that you build <em>a</em> list, and not hundreds or thousands of
 
56
    copies of the growing result list.</p>
 
57
 
 
58
    <p>Let us first look at how it should not be done:</p>
 
59
 
 
60
    <p><em>DO NOT</em></p>
 
61
    <code type="erl"><![CDATA[
 
62
bad_fib(N) ->
 
63
    bad_fib(N, 0, 1, []).
 
64
 
 
65
bad_fib(0, _Current, _Next, Fibs) ->
 
66
    Fibs;
 
67
bad_fib(N, Current, Next, Fibs) -> 
 
68
    bad_fib(N - 1, Next, Current + Next, Fibs ++ [Current]).]]></code>
 
69
 
 
70
    <p>Here we are not a building a list; in each iteration step we
 
71
    create a new list that is one element longer than the new previous list.</p>
 
72
 
 
73
    <p>To avoid copying the result in each iteration, we must build the list in
 
74
    reverse order and reverse the list when we are done:</p>
 
75
 
 
76
    <p><em>DO</em></p>
 
77
    <code type="erl"><![CDATA[
 
78
tail_recursive_fib(N) ->
 
79
    tail_recursive_fib(N, 0, 1, []).
 
80
 
 
81
tail_recursive_fib(0, _Current, _Next, Fibs) ->
 
82
    lists:reverse(Fibs);
 
83
tail_recursive_fib(N, Current, Next, Fibs) -> 
 
84
    tail_recursive_fib(N - 1, Next, Current + Next, [Current|Fibs]).]]></code>
 
85
 
 
86
  </section>
 
87
 
 
88
  <section>
 
89
    <title>List comprehensions</title>
 
90
 
 
91
    <p>Lists comprehensions still have a reputation for being slow.
 
92
    They used to be implemented using funs, which used to be slow.</p>
 
93
 
 
94
    <p>In recent Erlang/OTP releases (including R12B), a list comprehension</p>
 
95
 
 
96
    <code type="erl"><![CDATA[
 
97
[Expr(E) || E <- List]]]></code>
 
98
 
 
99
    <p>is basically translated to a local function</p>
 
100
 
 
101
    <code type="erl">
 
102
'lc^0'([E|Tail], Expr) ->
 
103
    [Expr(E)|'lc^0'(Tail, Expr)];
 
104
'lc^0'([], _Expr) -> [].</code>
 
105
 
 
106
    <p>In R12B, if the result of the list comprehension will <em>obviously</em> not be used,
 
107
    a list will not be constructed. For instance, in this code</p>
 
108
    
 
109
    <code type="erl"><![CDATA[
 
110
[io:put_chars(E) || E <- List],
 
111
ok.]]></code>
 
112
 
 
113
    <p>or in this code</p>
 
114
   
 
115
    <code type="erl"><![CDATA[
 
116
.
 
117
.
 
118
.
 
119
case Var of
 
120
    ... ->
 
121
        [io:put_chars(E) || E <- List];
 
122
    ... ->
 
123
end,
 
124
some_function(...),
 
125
.
 
126
.
 
127
.]]></code>
 
128
    
 
129
    <p>the value is neither assigned to a variable, nor passed to another function,
 
130
    nor returned, so there is no need to construct a list and the compiler will simplify
 
131
    the code for the list comprehension to</p>
 
132
 
 
133
    <code type="erl">
 
134
'lc^0'([E|Tail], Expr) ->
 
135
    Expr(E),
 
136
    'lc^0'(Tail, Expr);
 
137
'lc^0'([], _Expr) -> [].</code>
 
138
 
 
139
  </section>
 
140
 
 
141
  <section>
 
142
    <title>Deep and flat lists</title>
 
143
 
 
144
    <p><seealso marker="stdlib:lists#flatten/1">lists:flatten/1</seealso>
 
145
    builds an entirely new list. Therefore, it is expensive, and even
 
146
    <em>more</em> expensive than the <c>++</c> (which copies its left argument,
 
147
    but not its right argument).</p>
 
148
 
 
149
    <p>In the following situations, you can easily avoid calling <c>lists:flatten/1</c>:</p>
 
150
 
 
151
    <list type="bulleted">
 
152
      <item>When sending data to a port. Ports understand deep lists
 
153
       so there is no reason to flatten the list before sending it to
 
154
       the port.</item>
 
155
      <item>When calling BIFs that accept deep lists, such as
 
156
      <seealso marker="erts:erlang#list_to_binary/1">list_to_binary/1</seealso> or
 
157
      <seealso marker="erts:erlang#iolist_to_binary/1">iolist_to_binary/1</seealso>.</item>
 
158
      <item>When you know that your list is only one level deep, you can can use
 
159
      <seealso marker="stdlib:lists#append/1">lists:append/1</seealso>.</item>
 
160
    </list>
 
161
 
 
162
    <p><em>Port example</em></p>
 
163
    <p><em>DO</em></p>
 
164
    <pre>
 
165
      ...
 
166
      port_command(Port, DeepList)
 
167
      ...</pre>
 
168
    <p><em>DO NOT</em></p>
 
169
    <pre>
 
170
      ...
 
171
      port_command(Port, lists:flatten(DeepList))
 
172
      ...</pre>
 
173
 
 
174
    <p>A common way to send a zero-terminated string to a port is the following:</p>
 
175
 
 
176
    <p><em>DO NOT</em></p>
 
177
    <pre>
 
178
      ...
 
179
      TerminatedStr = String ++ [0], % String="foo" => [$f, $o, $o, 0]
 
180
      port_command(Port, TerminatedStr)
 
181
      ...</pre>
 
182
 
 
183
    <p>Instead do like this:</p>
 
184
 
 
185
    <p><em>DO</em></p>
 
186
    <pre>
 
187
      ...
 
188
      TerminatedStr = [String, 0], % String="foo" => [[$f, $o, $o], 0]
 
189
      port_command(Port, TerminatedStr) 
 
190
      ...</pre>
 
191
 
 
192
    <p><em>Append example</em></p>
 
193
    <p><em>DO</em></p>
 
194
    <pre>
 
195
      > lists:append([[1], [2], [3]]).
 
196
      [1,2,3]
 
197
      ></pre>
 
198
    <p><em>DO NOT</em></p>
 
199
    <pre>
 
200
      > lists:flatten([[1], [2], [3]]).
 
201
      [1,2,3]
 
202
      ></pre>
 
203
  </section>
 
204
 
 
205
  <section>
 
206
    <title>Why you should not worry about recursive lists functions</title>
 
207
 
 
208
    <p>In the performance myth chapter, the following myth was exposed:
 
209
    <seealso marker="myths#tail_recursive">Tail-recursive functions
 
210
    are MUCH faster than recursive functions</seealso>.</p>
 
211
 
 
212
    <p>To summarize, in R12B there is usually not much difference between
 
213
    a body-recursive list function and tail-recursive function that reverses
 
214
    the list at the end. Therefore, concentrate on writing beautiful code
 
215
    and forget about the performance of your list functions. In the time-critical
 
216
    parts of your code (and only there), <em>measure</em> before rewriting
 
217
    your code.</p>
 
218
 
 
219
    <p><em>Important note</em>: This section talks about lists functions that
 
220
    <em>construct</em> lists. A tail-recursive function that does not construct
 
221
    a list runs in constant space, while the corresponding body-recursive
 
222
    function uses stack space proportional to the length of the list.
 
223
    For instance, a function that sums a list of integers, should <em>not</em> be
 
224
    written like this</p>
 
225
    
 
226
    <p><em>DO NOT</em></p>
 
227
    <code type="erl">
 
228
recursive_sum([H|T]) -> H+recursive_sum(T);
 
229
recursive_sum([])    -> 0.</code>
 
230
 
 
231
    <p>but like this</p>
 
232
 
 
233
    <p><em>DO</em></p>
 
234
    <code type="erl">
 
235
sum(L) -> sum(L, 0).
 
236
 
 
237
sum([H|T], Sum) -> sum(T, Sum + H);
 
238
sum([], Sum)    -> Sum.</code>
 
239
  </section>
 
240
</chapter>
 
241