I still say that Erlang needs dynamic record fields
the way oysters need shooting sticks, but here's
how it could be done.
Step 1.
"To each module using records, a pseudo function
is added during compilation to obtain information
about records:
record_info(fields, Record) -> [Field]
record_info(size, Record) -> Size
"
Extend this with
record_info({index,Field}, Record) -> Index
The term "pseudo function" (which ought to be
"pseudo-function" or "pseudofunction") refers
to the way the compiler reports an error if you
call record_info/2 with non-literal arguments.
Step 2.
Instead of reporting an error, have the compiler
report a warning, and actually generate an
executable module-local definition of the
record_info/2 function; the existing behaviour
then just becomes the compiler special-casing a
known function, which is no more surprising than
compiling 1+1 as 2.
Step 3.
There is no step 3. If you want there to be a
step 3, you can write
-compile({inline, [field/3,field/3]}).
field(Tuple, Record, Field)
when is_tuple(Tuple),
tuple_size(Tuple) == record_info(size, Record),
element(1,Tuple) == Record
-> I = record_info({index,Field}, Record),
element(I, Tuple).
field(Tuple, Record, Field, New_Value)
when is_tuple(Tuple),
tuple_size(Tuple) == record_info(size, Record),
element(1,Tuple) == Record
-> I = record_info({index,Field}, Record),
setelement(I, Tuple, New_Value).
and stuff them in a file which you -include whenever
you have a real need for this feature. (Which is
when oysters have a real need for shooting-sticks.)
The thing that makes this approach almost attractive is
that it very slightly extends an existing interface and
then just removes a highly unusual restriction from it.
(Which other Erlang functions must have literal arguments?)