Record selectors

Håkan Stenholm hakan.stenholm@REDACTED
Sat Jan 4 03:55:38 CET 2003


On fredag, jan 3, 2003, at 12:15 Europe/Stockholm, Chris Pressey wrote:

> On Thu, 2 Jan 2003 18:50:14 +0100
> "Daniel Dudley" <daniel.dudley@REDACTED> wrote:
>
>> I'm curious as to why it is necessary to specify the record
>> name when selecting a record instance bound to a variable,
>> i.e., Variable#RecordName.Field.
>
> Because Erlang is a dynamically-typed language.  In a dynamically-typed
> language, values have types, but variables do not.
>
>> Using an example from the
>> Erlang Extensions document, but following good programming
>> practice by using a meaningful variable name, we have:
>>
>>> Person = #person{name = "Joe", [0,8,2,3,4,3,1,2]}.
>>     {person, "Joe", [0,8,2,3,4,3,1,2], undefined}
>>> Person#person.name.
>>     "Joe"
>>
>> Since the Person variable is bound to an instance of person
>> records, it seems to me that it should be possible to use
>> syntax like one of the following examples to retrieve field
>> data (and avoid duplicity and unnecessary keyboard typing
>> in the code):
>>
>> 1)  > Person#.name
>> 2)  > Person#name
>> 3)  > Person.name
>
> But consider the case of there being another record definition with a
> field called 'name', e.g. Country#country.name.  If one were then to 
> write
> a function like
>
>   print_name(X) -> io:fwrite("~p~n", [X#name]).

Sure there is if the Virtual machine would keep track of the record 
definitions (the fieldname - index mapping) and records would be tagged 
as records rather than being implemented as tuples in the VM.

A: 						Person.name
would be the same as:
						RecordName = element(1,Person),
						FieldValue = element(#RecordName.name, Person),

Assuming that the VM knew about the record definition, which it 
currently doesn't as records only exist during the preprocessor stage.
Records are a late Erlang addition which is one of the reasons why 
there is number of problems that need to be solved to handle records 
properly:

* Records are implemented as tuples, this leads to problems with 
properly identifying records as records (they will always be identified 
as tuples as well), I don't think this should be a major problem as the 
worst case should be a failed element/2 access (or runtime errors later 
on trying to update a tuple as a record), one would assume that code 
that acts on records only receives records - making this a unlikely bug 
generator.

* The tuple implementation is sometimes used directly during code 
change (when record defs. have been updated), as there can be only one 
record definition at the same time.
So changing the implementation might yield some problems - but to me it 
appears that the Person.name syntax would work without this kind of 
change.
There is of course the question how the VM should handle the fieldname 
- index mapping in this kind of cases (a old and new version might be 
useful to keep around and to be able to use as well).

* There is also compatibility problem as it isn't possible to determine 
which record definition was actually used when a module was compiled. 
It might be useful to keep a fieldname - index mapping for each record 
as well as one for each unique version used by the modules.

Drawbacks:

* Doing a #RecordName.FieldName access dynamically during runtime will 
obviously be more costly - retrieving the record name and doing a 
lookup on the {RecordName, FieldName} key.

>
> There is no way for the compiler to infer what field #name refers to.
>
> The practical recourse at the moment, at least for me, is:
> a) if performance is critical, use records and accept the silly syntax
> b) if flexibility is more important, use dictionaries
>
> Quite often I find myself wrapping record accesses in functions, 
> although
> "person:name(X)" is just as verbose as "X#person.name" (in fact it's 
> one
> character longer :) but it looks nicer, plus it abstracts the access so
> that e.g. person:name(X) could be derived from X#person.first_name and
> X#person.last_name at some future point in development.  Again, if
> performance is critical, this sort of thing should still be avoided,
> because unlike "X#person.name", you can't tell what the complexity of
> "person:name(X)" is just by looking at it.
>
> -Chris
>




More information about the erlang-questions mailing list