tags:

views:

58

answers:

2

I'm having a problem that should be stupidly easy to fix. Following this, I'm trying to access a field in a record. Here's a simplified example that exhibits my problem:

-module(test).
-export([test/0]).

-record(rec, {f1=[], f2=[], f3=[]}).

test() ->
    Rec = #rec{f1=[1,2,3], f3=[4,5,6]},
    Fields = record_info(fields, rec),
    loop(Fields, Rec).

loop([Field|Fields], Rec) ->
    [Rec#rec.Field|loop(Fields, Rec)]; %% <-- This is line 12.
loop([], _Rec) ->
    [].

When I try to compile test, I get a syntax error:

./test.erl:12: syntax error before: Field

What am I doing wrong?

+1  A: 

Records are converted into arrays in compile-time, meaning that all field accesses are converted to erlang:element calls as well. Thus variables cannot be used as field names must be known at compile-time - as Damg already answered.

The "workarounds" I am aware of are either using proplists, dicts, etc. instead of records, or use Ulf Wiger's exprecs to generate record access functions.

Zed
+1  A: 

If you only want to enumerate record values you can use element/2 and enumerate elements from 2 (the first element is a record name) to tuple_size(Record).

If you want to access record fields by name at run time you can create auxiliary proplist at compile time like this:

Fields = lists:zip(record_info(fields, rec),
                   lists:seq(2, record_info(size, rec)))

Note that record_info() always evaluated at compile time.

And then query field value with function similar to this:

get_record_value(Name, Record, Fields) ->
    case proplists:get_value(Name, Fields) of
        undefined ->
            undefined;
        N when is_integer(N) ->
            element(N, Record)
    end.
hdima
I'm accepting this one, since it solves the problem stated in the question, but it turned out that my code could be restructured to not need to do this at all (I ended up cutting out about half my code). Hooray!
Nathon