<?xml version="1.0" encoding="latin1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">

<chapter>
  <header>
    <copyright>
      <year>2003</year><year>2010</year>
      <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.

    </legalnotice>

    <title>Records</title>
    <prepared></prepared>
    <docno></docno>
    <date></date>
    <rev></rev>
    <file>records.xml</file>
  </header>
  <p>A record is a data structure for storing a fixed number of
    elements. It has named fields and is similar to a struct in C.
    Record expressions are translated to tuple expressions during
    compilation. Therefore, record expressions are not understood by
    the shell unless special actions are taken. See <c>shell(3)</c>
    for details.</p>
  <p>More record examples can be found in <em>Programming Examples</em>.</p>

  <section>
    <title>Defining Records</title>
    <p>A record definition consists of the name of the record,
      followed by the field names of the record. Record and field names
      must be atoms. Each field can be given an optional default value.
      If no default value is supplied, <c>undefined</c> will be used.</p>
    <pre>
-record(Name, {Field1 [= Value1],
               ...
               FieldN [= ValueN]}).</pre>
    <p>A record definition can be placed anywhere among the attributes
      and function declarations of a module, but the definition must
      come before any usage of the record.</p>
    <p>If a record is used in several modules, it is recommended that
      the record definition is placed in an include file.</p>
  </section>

  <section>
    <title>Creating Records</title>
    <p>The following expression creates a new <c>Name</c> record where
      the value of each field <c>FieldI</c> is the value of evaluating
      the corresponding expression <c>ExprI</c>:</p>
    <pre>
#Name{Field1=Expr1,...,FieldK=ExprK}</pre>
    <p>The fields may be in any order, not necessarily the same order as
      in the record definition, and fields can be omitted. Omitted
      fields will get their respective default value instead.</p>
    <p>If several fields should be assigned the same value,
      the following construction can be used:</p>
    <pre>
#Name{Field1=Expr1,...,FieldK=ExprK, _=ExprL}</pre>
    <p>Omitted fields will then get the value of evaluating <c>ExprL</c>
      instead of their default values. This feature was added in
      Erlang 5.1/OTP R8 and is primarily intended to be used to create
      patterns for ETS and Mnesia match functions. Example:</p>
    <pre>
-record(person, {name, phone, address}).

...

lookup(Name, Tab) ->
    ets:match_object(Tab, #person{name=Name, _='_'}).</pre>
  </section>

  <section>
    <title>Accessing Record Fields</title>
    <pre>
Expr#Name.Field</pre>
    <p>Returns the value of the specified field. <c>Expr</c> should
      evaluate to a <c>Name</c> record.</p>
    <p>The following expression returns the position of the specified
      field in the tuple representation of the record:</p>
    <pre>
#Name.Field</pre>
    <p>Example:</p>
    <pre>
-record(person, {name, phone, address}).

...

lookup(Name, List) ->
    lists:keysearch(Name, #person.name, List).</pre>
  </section>

  <section>
    <title>Updating Records</title>
    <pre>
Expr#Name{Field1=Expr1,...,FieldK=ExprK}</pre>
    <p><c>Expr</c> should evaluate to a <c>Name</c> record. Returns a
      copy of this record, with the value of each specified field
      <c>FieldI</c> changed to the value of evaluating the corresponding
      expression <c>ExprI</c>. All other fields retain their old
      values.</p>
    <p></p>
  </section>

  <section>
    <title>Records in Guards</title>
    <p>Since record expressions are expanded to tuple expressions,
      creating records and accessing record fields are allowed in
      guards. However all subexpressions, for example for field
      initiations, must of course be valid guard expressions as well.
      Examples:</p>
    <code type="none">
handle(Msg, State) when Msg==#msg{to=void, no=3} ->
    ...

handle(Msg, State) when State#state.running==true ->
    ...</code>
    <p>There is also a type test BIF <c>is_record(Term, RecordTag)</c>.
      Example:</p>
    <pre>
is_person(P) when is_record(P, person) ->
    true;
is_person(_P) ->
    false.</pre>
  </section>

  <section>
    <title>Records in Patterns</title>
    <p>A pattern that will match a certain record is created the same
      way as a record is created:</p>
    <pre>
#Name{Field1=Expr1,...,FieldK=ExprK}</pre>
    <p>In this case, one or more of <c>Expr1</c>...<c>ExprK</c> may be
      unbound variables.</p>
  </section>

  <section>
    <title>Nested records</title>
    <p>Beginning with R14 parentheses when accessing or updating nested
      records can be omitted. Assuming we have the following record
      definitions:</p>
    <pre>
-record(nrec0, {name = "nested0"}).
-record(nrec1, {name = "nested1", nrec0=#nrec0{}}).
-record(nrec2, {name = "nested2", nrec1=#nrec1{}}).

N2 = #nrec2{},
    </pre>
    <p>Before R14 you would have needed to use parentheses as following:</p>
    <pre>
"nested0" = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0.name,
N0n = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0{name = "nested0a"},
    </pre>
    <p>Since R14 you can also write:</p>
    <pre>
"nested0" = N2#nrec2.nrec1#nrec1.nrec0#nrec0.name,
N0n = N2#nrec2.nrec1#nrec1.nrec0#nrec0{name = "nested0a"},</pre>
  </section>

  <section>
    <title>Internal Representation of Records</title>
    <p>Record expressions are translated to tuple expressions during
      compilation. A record defined as</p>
    <pre>
-record(Name, {Field1,...,FieldN}).</pre>
    <p>is internally represented by the tuple</p>
    <pre>
{Name,Value1,...,ValueN}</pre>
    <p>where each <c>ValueI</c> is the default value for <c>FieldI</c>.</p>
    <p>To each module using records, a pseudo function is added
      during compilation to obtain information about records:</p>
    <pre>
record_info(fields, Record) -> [Field]
record_info(size, Record) -> Size</pre>
    <p><c>Size</c> is the size of the tuple representation, that is
      one more than the number of fields.</p>
    <p>In addition, <c>#Record.Name</c> returns the index in the tuple
    representation of <c>Name</c> of the record <c>Record</c>.
    <c>Name</c> must be an atom.</p>
  </section>
</chapter>

