[erlang-questions] If you are homesick for object.selector

Sun Jan 27 11:33:40 CET 2013

Tom Janssens wrote:

> This is not how it would work; this would be a better example:
> -record(foo, {a,b,c}).
> -record(bar, {a,x,y}).
> sum(X#foo) -> X.a+X.b+X.c;
> sum(X#bar) -> X.a+X.x+X.y.

Weird.  Are you suggesting a new syntax <variable>#<record name>
which is like <variable>=#<record name>{}?

I can't help feeling that

sum(#foo{a=A, b=B, c=C}) -> A+B+C;
sum(#bar{a=A, x=X, y=Y}) -> A+X+Y.

is superior.  In ML, I would write

    datatype thingy
           = Foo of {a : int, b : int, c : int}
           | Bar of {a : int, x : int, c : int}

    fun sum (Foo {a=a, b=b, c=c}) = a+b+c
      | sum (Bar {a=a, x=x, y=y}} = a+x+y

and pretty much the same thing in Haskell.
In functional languages, I expect to use field names
in patterns and not elsewhere.

If you pick up all the fields you want in one pattern
match, you write the record name once and only once.

> anotherSum(X) ->
>   First = X#foo.a,
>   Middle = X.b,
>   Last = X.c,
>   First+Middle+Last.

Yes, but again, why go out of your way to avoid
a pattern match?  The idiomatic way to do this is

another_sum(#foo{a = First, b = Middle, c = Last}) ->
    First + Middle + Last.

When I devised frames I tried rewriting some fairly
large chunks of existing code using frame notation,
and a _very_ helpful first step was pushing field
accesses back into pattern matching.  As a _reader_
of other people's code, I found it _extremely_ helpful
to see _all_ the fields being picked up mentioned in
one place.

> So the preprocessor would only infer record info when it is available.

Yes, but "available" is the magic word, isn't it?
The case where a variable is annotated with a record name (and
X#foo is not currently legal Erlang syntax) is straightforward,
but what about

> anotherSum(X) ->
>   First  = f(X)#foo.a,
>   Middle = f(X).b,
>   Last   = f(X).c,
>   First+Middle+Last.

where to a human reader who has seen f/1 it is obvious that
f/1 always returns the same kind of thing.  A *local* check
by a preprocessor is not going to catch this.  You need some
sort of type check for at least a whole module.

I am NOT saying that it cannot be done.
I am NOT saying that it should not be done.

I *AM* saying that the hard work of devising an effective
(abstract) algorithm that CAN do whatever the task is should
be done by the people who want the feature.  And simplistic
hacks are never going to be satisfactory long term because
people will expect whatever the algorithm accomplishes to
_make sense to them_.  And that means that if X#foo works,
then element(N,X)#foo should work, and X#zoo.ick#foo should
work, and if f/1 is "obviously" safe, f(X)#foo should work.
When the algorithm break down, it should be clear to a
programmer _why_ it broke down and what to do about it.

>> Should be able to derive it?  Please describe the algorithm.
> See above

I did _look_ above, but did not _see_ it because you have not
described an algorithm.  A sample input output pair or two is
not a description of an algorithm.

Describe an algorithm.  Write an EEP.  Some EEPs get adopted.
Some get implemented by third parties who like the idea.

More information about the erlang-questions mailing list