Setting/changing wildcards for ets in a nested record

"Gösta Ask (Mobile Arts)" <>
Wed Feb 23 15:22:16 CET 2005


I found a problem when I wrote a routine to set all fields in a nested
record to the special value '_'. Part of the demo code:

     P = #person{},
     R = set_deep_underscore(P),
     {R, R#person{names = #name{last="Virding"}}}.

which gives the following output:

Erlang (BEAM) emulator version [source] [hipe]
Eshell V5.3.6.2  (abort with ^G)

196> person:demo().

How come the first two fields in the #name record get set to
'undefined'? I had hoped that all fields that are not referred to
would get copies of their old values when a new record is

Instead fields that are not referred in the record where a change
takes place (setting last = "Virding" in this example) get new
values from the default setting. The default is 'undefined'. This
was a bit confusing. Is the behavior intentional? Or unavoidable?

I stumbled on this thing when I checked if I could use the cool

      P = #person{_ = '_'},

for testing purposes. Comparing an actual record output from a Test
Object with an expected record prepared in advance, that is.

For testing purposes it is nice to start with a record with wildcards.
The record can be used as a pattern in ets:match_object/2 after the
records output from the test object have been inserted into an ets
table. To be flexible it must be possible to set each individual
field in the test record to a specific value before the test is

With the present behavior I will have to resort to setting all fields
explicitly = '_' in the record definition. This means a lot of extra
keyboard work since this records are quite large.

Gösta Ask
(Mobile Arts)

Here is the routine to traverse a record and set all fields = '_',
assuming that the parameter Rec is a record represented as a tuple.

set_deep_underscore(Rec)  ->
     [RecName|Fields] = tuple_to_list(Rec),
     traverse(Fields, [RecName]).

traverse([], L) ->

traverse([H|T], [LH|LT]) when is_tuple(H) ->
     traverse(T, [set_deep_underscore(H),LH|LT]);

traverse([_|T], L) ->
     traverse(T, ['_'|L]).

And here are the record definitions

-record(name, {first,middle,last}).
-record(addr, {nr,street,city}).
-record(town, {code,size}).
-record(person, {names = #name{}, phone,
		 address = #addr{city = #town{}}, age, job}).

More information about the erlang-bugs mailing list