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

« back to all changes in this revision

Viewing changes to system/doc/programming_examples/records.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>2003</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>Records</title>
 
25
    <prepared></prepared>
 
26
    <docno></docno>
 
27
    <date></date>
 
28
    <rev></rev>
 
29
    <file>records.xml</file>
 
30
  </header>
 
31
 
 
32
  <section>
 
33
    <title>Records vs Tuples</title>
 
34
    <p>The main advantage of using records instead of tuples is that
 
35
      fields in a record are accessed by name, whereas fields in a
 
36
      tuple are accessed by position. To illustrate these differences,
 
37
      suppose that we want to represent a person with the tuple
 
38
      <c>{Name, Address, Phone}</c>.</p>
 
39
    <p>We must remember that the <c>Name</c> field is the first
 
40
      element of the tuple, the <c>Address</c> field is the second
 
41
      element, and so on, in order to write functions which manipulate
 
42
      this data. For example, to extract data from a variable <c>P</c>
 
43
      which contains such a tuple we might write the following code
 
44
      and then use pattern matching to extract the relevant fields.</p>
 
45
    <code type="none">
 
46
Name = element(1, P),
 
47
Address = element(2, P),
 
48
...</code>
 
49
    <p>Code like this is difficult to read and understand and errors
 
50
      occur if we get the numbering of the elements in the tuple wrong.
 
51
      If we change the data representation by re-ordering the fields,
 
52
      or by adding or removing a field, then all references to
 
53
      the person tuple, wherever they occur, must be checked and
 
54
      possibly modified.</p>
 
55
    <p>Records allow us to refer to the fields by name and not
 
56
      position. We use a record instead of a tuple to store the data.
 
57
      If we write a record definition of the type shown below, we can
 
58
      then refer to the fields of the record by name.</p>
 
59
    <code type="none">
 
60
-record(person, {name, phone, address}).</code>
 
61
    <p>For example, if <c>P</c> is now a variable whose value is a
 
62
      <c>person</c> record, we can code as follows in order to access
 
63
      the name and address fields of the records.</p>
 
64
    <code type="none">
 
65
Name = P#person.name,
 
66
Address = P#person.address,
 
67
...</code>
 
68
    <p>Internally, records are represented using tagged tuples:</p>
 
69
    <code type="none">
 
70
{person, Name, Phone, Address}</code>
 
71
  </section>
 
72
 
 
73
  <section>
 
74
    <title>Defining a Record</title>
 
75
    <p>This definition of a person will be used in many of
 
76
      the examples which follow. It contains three fields, <c>name</c>,
 
77
      <c>phone</c> and <c>address</c>. The default values for
 
78
      <c>name</c> and <c>phone</c> is "" and [], respectively.
 
79
      The default value for <c>address</c> is the atom
 
80
      <c>undefined</c>, since no default value is supplied for this
 
81
      field:</p>
 
82
    <pre>
 
83
-record(person, {name = "", phone = [], address}).</pre>
 
84
    <p>We have to define the record in the shell in order to be able
 
85
      use the record syntax in the examples:</p>
 
86
    <pre>
 
87
> <input>rd(person, {name = "", phone = [], address}).</input>
 
88
person</pre>
 
89
    <p>This is due to the fact that record definitions are available
 
90
      at compile time only, not at runtime. See <c>shell(3)</c> for
 
91
      details on records in the shell.
 
92
      </p>
 
93
  </section>
 
94
 
 
95
  <section>
 
96
    <title>Creating a Record</title>
 
97
    <p>A new <c>person</c> record is created as follows:</p>
 
98
    <pre>
 
99
> <input>#person{phone=[0,8,2,3,4,3,1,2], name="Robert"}.</input>
 
100
#person{name = "Robert",phone = [0,8,2,3,4,3,1,2],address = undefined}</pre>
 
101
    <p>Since the <c>address</c> field was omitted, its default value
 
102
      is used.</p>
 
103
    <p>There is a new feature introduced in Erlang 5.1/OTP R8B,
 
104
      with which you can set a value to all fields in a record,
 
105
      overriding the defaults in the record specification. The special
 
106
      field <c>_</c>, means "all fields not explicitly specified".</p>
 
107
    <pre>
 
108
> <input>#person{name = "Jakob", _ = '_'}.</input>
 
109
#person{name = "Jakob",phone = '_',address = '_'}</pre>
 
110
    <p>It is primarily intended to be used in <c>ets:match/2</c> and
 
111
      <c>mnesia:match_object/3</c>, to set record fields to the atom
 
112
      <c>'_'</c>. (This is a wildcard in <c>ets:match/2</c>.)</p>
 
113
  </section>
 
114
 
 
115
  <section>
 
116
    <title>Accessing a Record Field</title>
 
117
    <pre>
 
118
> <input>P = #person{name = "Joe", phone = [0,8,2,3,4,3,1,2]}.</input>
 
119
#person{name = "Joe",phone = [0,8,2,3,4,3,1,2],address = undefined}
 
120
> <input>P#person.name.</input>
 
121
"Joe"</pre>
 
122
  </section>
 
123
 
 
124
  <section>
 
125
    <title>Updating a Record</title>
 
126
    <pre>
 
127
> <input>P1 = #person{name="Joe", phone=[1,2,3], address="A street"}.</input>
 
128
#person{name = "Joe",phone = [1,2,3],address = "A street"}
 
129
> <input>P2 = P1#person{name="Robert"}.</input>
 
130
#person{name = "Robert",phone = [1,2,3],address = "A street"}</pre>
 
131
  </section>
 
132
 
 
133
  <section>
 
134
    <title>Type Testing</title>
 
135
    <p>The following example shows that the guard succeeds if
 
136
      <c>P</c> is record of type <c>person</c>.</p>
 
137
    <pre>
 
138
foo(P) when is_record(P, person) -> a_person;
 
139
foo(_) -> not_a_person.</pre>
 
140
  </section>
 
141
 
 
142
  <section>
 
143
    <title>Pattern Matching</title>
 
144
    <p>Matching can be used in combination with records as shown in
 
145
      the following example:</p>
 
146
    <pre>
 
147
> <input>P3 = #person{name="Joe", phone=[0,0,7], address="A street"}.</input>
 
148
#person{name = "Joe",phone = [0,0,7],address = "A street"}
 
149
> <input>#person{name = Name} = P3, Name.</input>
 
150
"Joe"</pre>
 
151
    <p>The following function takes a list of <c>person</c> records
 
152
      and searches for the phone number of a person with a particular
 
153
      name:</p>
 
154
    <code type="none">
 
155
find_phone([#person{name=Name, phone=Phone} | _], Name) ->
 
156
    {found,  Phone};
 
157
find_phone([_| T], Name) ->
 
158
    find_phone(T, Name);
 
159
find_phone([], Name) ->
 
160
    not_found.</code>
 
161
    <p>The fields referred to in the pattern can be given in any order.</p>
 
162
  </section>
 
163
 
 
164
  <section>
 
165
    <title>Nested Records</title>
 
166
    <p>The value of a field in a record might be an instance of a
 
167
      record. Retrieval of nested data can be done stepwise, or in a
 
168
      single step, as shown in the following example:</p>
 
169
    <pre>
 
170
-record(name, {first = "Robert", last = "Ericsson"}).
 
171
-record(person, {name = #name{}, phone}).
 
172
 
 
173
demo() ->
 
174
  P = #person{name= #name{first="Robert",last="Virding"}, phone=123},
 
175
  First = (P#person.name)#name.first.</pre>
 
176
    <p>In this example, <c>demo()</c> evaluates to <c>"Robert"</c>.</p>
 
177
  </section>
 
178
 
 
179
  <section>
 
180
    <title>Example</title>
 
181
    <pre>
 
182
%% File: person.hrl
 
183
 
 
184
%%-----------------------------------------------------------
 
185
%% Data Type: person
 
186
%% where:
 
187
%%    name:  A string (default is undefined).
 
188
%%    age:   An integer (default is undefined).
 
189
%%    phone: A list of integers (default is []).
 
190
%%    dict:  A dictionary containing various information 
 
191
%%           about the person. 
 
192
%%           A {Key, Value} list (default is the empty list).
 
193
%%------------------------------------------------------------
 
194
-record(person, {name, age, phone = [], dict = []}).</pre>
 
195
    <pre>
 
196
-module(person).
 
197
-include("person.hrl").
 
198
-compile(export_all). % For test purposes only.
 
199
 
 
200
%% This creates an instance of a person.
 
201
%%   Note: The phone number is not supplied so the
 
202
%%         default value [] will be used.
 
203
 
 
204
make_hacker_without_phone(Name, Age) ->
 
205
   #person{name = Name, age = Age, 
 
206
           dict = [{computer_knowledge, excellent}, 
 
207
                   {drinks, coke}]}.
 
208
 
 
209
%% This demonstrates matching in arguments
 
210
 
 
211
print(#person{name = Name, age = Age,
 
212
              phone = Phone, dict = Dict}) ->
 
213
  io:format("Name: ~s, Age: ~w, Phone: ~w ~n" 
 
214
            "Dictionary: ~w.~n", [Name, Age, Phone, Dict]).
 
215
 
 
216
%% Demonstrates type testing, selector, updating.
 
217
 
 
218
birthday(P) when record(P, person) -> 
 
219
   P#person{age = P#person.age + 1}.
 
220
 
 
221
register_two_hackers() ->
 
222
   Hacker1 = make_hacker_without_phone("Joe", 29),
 
223
   OldHacker = birthday(Hacker1),
 
224
   % The central_register_server should have 
 
225
   % an interface function for this.
 
226
   central_register_server ! {register_person, Hacker1},
 
227
   central_register_server ! {register_person, 
 
228
             OldHacker#person{name = "Robert", 
 
229
                              phone = [0,8,3,2,4,5,3,1]}}.</pre>
 
230
  </section>
 
231
</chapter>
 
232