[erlang-questions] The compiler "eats" structures which are not separated by commas
Richard O'Keefe
ok@REDACTED
Tue Apr 24 00:24:00 CEST 2012
On 23/04/2012, at 9:23 PM, Jan Burse wrote:
> ok@REDACTED 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.
-module(a).
-export([a/0]).
-record(foo, {bar,ugh}).
a() -> v:v(#foo{bar=1, ugh=2}).
-module(b).
-export([b/0]).
-record(foo, {ugh,bar}).
b() -> v:v(#foo{ugh=1, bar=2}).
-module(v).
-export([v/1]).
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