We've had a claim recently that using
Person#person_name
instead of
Person.name
is so horrible that it's scaring off people who would otherwise
use Erlang.
What would be _Erlangish_ approach to this look like?
(Apart from implementing frames, of course.)
I think PL/I was the first language to use "." for
field selection. COBOL and Algol 68 used (selector OF record).
In the statement
x = thingy.selector;
what is ".selector"?
It is nothing other than a function, applied to the argument
"thingy" to yield a result.
What's the Erlang syntax for applying a function to an argument?
X = selector(Thingy)
In the statement
thingy.selector = y;
what is ".selector ="?
It is nothing other than a function, applied to two arguments.
What's the Erlang syntax for applying a function to two arguments?
Thingy1 = set_selector(Thingy0, Y)
Now we can define these things manually. We just have to include
a clause for each visible record type.
What's the Erlang way to generate functions automatically from
declarative information?
Use attributes to provide the information and a parse transform
to do the generation.
For example, you might write
-record(person, {id,name,department_id,manager_id,age,job}).
-record(department, {id,name, manager_id}).
-record(project, {id,name,department_id}).
-getters([id,name]).
-setters([name]).
From that, you might like to get automatically generated code like
id({person,F,_,_,_,_,_}) -> F;
id({department,F,_,_}) -> F;
id({project,F,_,_}) -> F.
name({person,_,F,_,_,_,_}) -> F;
name({department,_,F,_}) -> F;
name({project,_,F,_}) -> F.
set_name({person,X1,_,X3,X4,X5,X6}, F) ->
{person,X1,F,X3,X4,X5,X6};
set_name({department,X1,_,X3}, F) ->
{department,X1,F,X3};
set_name({project,X1,_,X3}, F) ->
{project,X1,F,X3}.
Well, as it happens, that code _was_ automatically generated, and
it was automatically generated from those lines. This was just a
quick prototype, so I whipped it up in AWK. Two pages with comments,
one page without. The _right_ way is a parse transform, of course.
I don't regard this design as settled, so there's no EEP.
For example, it's reasonable to want automatically generated -spec
declarations as well, which would generally look like
-spec <field>(#<record 1>{}) -> <field type 1>
; (#<record 2>{}) -> <field type 2>
... .
-spec set_<field>(R, <field type 1>) -> R when R :: #<record 1>{}
; (R, <field type 2>) -> R when R :: #<record 2>{}
... .
but this is tedious rather than difficult.
For another thing, you might want to give the selector function a different
name from the field and you might not want all possible records for some
selector function.
The nice thing is that code generators like this can be written entirely
in Erlang using existing features.