[erlang-questions] The compiler "eats" structures which are not separated by commas

Richard O'Keefe <>
Tue Apr 24 00:24:00 CEST 2012

On 23/04/2012, at 9:23 PM, Jan Burse wrote:

>  schrieb:
>> We could have a rule that says "take all the
>> -record(name, { ..., field ... })
>> declarations that are visible in the current module,
>> and for each field name, construct a function
>>     field(#rec1{...,field=X,...}) ->  X;
>>     ...
>>     field(#recn(...,field=X,...}) ->  X.
>> "
>> so that instead of Foo#rec.bar we could use a plain
>> bar(Foo), which is much better syntax for a functional
>> language than 'get' prefixes.  And the type language
>> used by dialyzer could handle this.
> This would not be the intention of a getBar(Foo).

First off, I was talking about bar(Foo), not getBar(Foo).
(Exercise: who said that pure functions should not be given
imperative phrases as names and why?)

Second, *I* just defined bar(Foo); who are you to tell me
that what I intended bar to do is not its intention?  Or
to put it another way, you can intend your getBar(Foo) to
do whatever you feel like, but *I* intended an automatically
defined bar(Foo) to accept all and only the records *visible*
in the module where it was defined.  And it remains true that
dialyzer *could* handle such a bar/1 perfectly well.

> To be universal so that a resolution a runtime can happen.

That's your intention, not *my* intention.

If you want something that type inference can work on,
then it *HAS* to be something based on information that
is *AVAILABLE* to the type inferencer.  Wanting it "to
be universal so that a resolution a[t] runtime can
happen" is tantamount to saying that you REJECT type
inference, or else that you wish for magic to happen.

Given the actual state of Erlang's records, it is
*impossible* for run time resolution to happen.

-record(foo, {bar,ugh}).

a() -> v:v(#foo{bar=1, ugh=2}).

-record(foo, {ugh,bar}).

b() -> v:v(#foo{ugh=1, bar=2}).


v(Rec) -> getBar(Rec).


Here getBar/1 is your intention, a "universal" function
that magically selects the "bar" field from any record
that has one.

a:a() calls v:v({foo,1,2}).
b:b() calls v:v({foo,1,2}).

Just what run-time information is v:v/1 supposed to
call on so that it can know to return 1 for the
first call and 2 for the second?

With frames, no problem:

a() -> v:v(<foo{bar ~ 1, ugh ~ 2}>).

b() -> v:v(<foo{ugh ~ 1, bar ~ 2}>).

v(F) -> ~bar(F).  % abbreviates frame_value(F, 'bar').

> For a resolution at runtime we wouldn't even need
> a type inference. Only access to the meta data of
> the record type declaration.

But THERE IS NO SUCH ANIMAL.  Just like in C, one
record *name* may be used for any finite number of
record *types* and there is *no* indication in a
record *value* of which record *type* it came from.

You may say that this is a bad thing, that at the very
least record names ought to be tagged with something
other than a simple name, so that it _is_ possible to
discover which -record declaration applied.

If you said those things, I would agree with you.
I certainly sent a proposal to this list quite some
time ago for a different approach to record tagging
that was about as compatible with the current scheme
as possible while still allowing you to discover
which -record declaration was the right one.

But that proposal was never adopted, and the Erlang
we actually *have* is one in which your wish for a
universal getBar/1 CANNOT be granted.

> Only reason getXXX()/setXXX() is probably not done
> is performance loss I guess,

No.  They are not done because they CANNOT be done
because there can be multiple record types with the
same name and it is IMPOSSIBLE to discover from a
run-time value which of those record types was meant.

You really don't understand Erlang records until this
is obvious to you.

More information about the erlang-questions mailing list