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