Records, encapsulation and optional elements
Willem Broekema
willem@REDACTED
Tue May 21 14:44:06 CEST 2002
Alex Peake wrote:
> I am new to Erlang. Could someone please advise if the following is a
> reasonable attempt at encapsulating the creation of records (with optional
> elements)? Is there a more elegant way? It seems a shame that I can define
> defaults (in the .hrl) and yet not use them (in an encapsulated way) in the
> .erl.
Until it's possible to use a variable in record_info/2 (so it's evaluated
at run-time instead of compile-time), I use the following to avoid
repeating code when assigning multiple attributes:
-record(r, {k1,k2,k3}).
test() ->
F = record_info(fields, r),
% Create an 'r' record:
R = iter_fields(r, [{k1,v1},{k2,v2}], F),
io:format("R: ~p~n", [R]),
% Update the record, by supplying a {key,val} list:
R2 = iter_fields(R, [{k2,newv2}, {k3,newv3}], F),
io:format("R2: ~p~n", [R2]).
where 'iter_fields' is defined as follows:
% We make use of knowledge about implementation of records.
% It's bad style, but so very useful! ;-)
%
% Translate a {k,v} list 'L' to a record 'somerecord':
% L = [ {k1,v1}, ... ]
% Fields = record_info(fields, somerecord),
% R = iter_fields(somerecord, L, Fields).
iter_fields(L, [] ) when list(L) ->
[];
iter_fields( L, [F|Fields] ) when list(L) ->
case lists:keysearch(F, 1, L) of
{value, {F, Val}} ->
[Val | iter_fields(L, Fields) ];
false ->
[undefined | iter_fields(L, Fields) ]
end.
% Updating an existing record:
% R = #somerecord{ k1=v1, k2=v2 },
% Fields = record_info(fields, somerecord),
% R2 = iter_fields(R, [{k2,v2new}], Fields)
iter_fields(RName, KVL, L) when atom(RName), list(KVL), list(L) ->
% Assume 'RName' is record name, L its fieldlist
list_to_tuple( [RName | iter_fields(KVL, L)] );
iter_fields(Old, KVL, L) when tuple(Old) ->
% Assume 'Old' is a existing record, L its fieldlist.
OldL = tuple_to_list(Old),
list_to_tuple( [ hd(OldL) | iter_fields( tl(OldL), KVL, L) ] );
iter_fields(OldL, KVL, []) when list(OldL) ->
[];
iter_fields( [O|OldL], KVL, [F|Fields] ) ->
case lists:keysearch(F, 1, KVL) of
{value, {F, Val}} ->
% Field is overridden by KVL.
[Val | iter_fields(OldL, KVL, Fields) ];
false ->
% Field value is not overridden, so use old val.
[O | iter_fields(OldL, KVL, Fields) ]
end.
- Willem
More information about the erlang-questions
mailing list