auto-generated record access functions

ke han <>
Mon May 29 19:35:49 CEST 2006


Ulf,
thanks.  I'll look into this when I start again tomorrow.
What I'm trying to do is use your record access in a framework so the  
module person will use a record #person to store its data.  In the  
simplest case, an "instance of person" would be just the record which  
would be used in conjunction with the person module to get and set  
values via a controller which is a process.  More complex models  
could be processes and would work in a similar fashion (the  
controller would just have to know to send the message differently).   
I'm trying to figure out a way to make this somewhat transparent to  
the framework user.

One thing I want to do with your record access is to start off a  
model as an empty module definition (as in my example).  As the  
programmer adds behavior (e.g. validations on the various attributes  
of the record), they would add functions to the module.
So, I'm going to pretty quickly have to figure out how to take your  
record access to the next level.

For example, start with the empty module person as:
-module(person).
-compile({parse_transform, exprecs}).
-record(person, {firstName, lastName, birthDate}).
-export_records([person]).

Then when the programmer is ready to add validation for the  
birthDate, they add the function:

birthDate(Date) ->
	validateDate(Date).

This function would be not exported and called (when it exists) by  
your record set function (set-person/2 in this case).  This would  
also imply I want your record access functions to handle exceptions  
in a certain way as well.  That is, if birthDate/1 throws an  
exception, the set does not happen.
This provides the beginnings of an "attribute framework", which is an  
essential part for easily creating models and controllers.

good night, ke han


On May 30, 2006, at 12:28 AM, Ulf Wiger ((AL/EAB)) wrote:

>
> I believe it's because your module has no hand-written functions.
>
> The parse-transform module I wrote looks for the first function in  
> order
> to create the record access functions before it. If there are no
> functions in the module, it will simply not generate the access
> functions, but it will go on and try to export them.
>
> That's not a feature. It didn't occur to me at the time that people
> would want to create modules with no functions in them. (:
>
> BR,
> Ulf W
>
>> -----Original Message-----
>> From: ke han [mailto:]
>> Sent: den 29 maj 2006 16:09
>> To: Ulf Wiger (AL/EAB)
>> Cc: 
>> Subject: Re: auto-generated record access functions
>>
>> Ulf,
>> I've just tested your record access generator.  I'm getting
>> some errors.
>>
>> I compile test.erl which is:
>>
>> -module(test).
>> -compile({parse_transform, exprecs}).
>> -record(person, {firstName, lastName, birthDate}).
>> -export_records([person]).
>>
>> compile results:  (note, my erlc is a bash script which adds
>> path, includes and outputs in the correct places)  > erlc
>> test.erl using /Users/jhancock/bin/erlc
>> ./test.erl:4: function '#new-person'/0 undefined
>> ./test.erl:4: function '#set-person'/2 undefined
>> ./test.erl:4: function '#get-person'/2 undefined
>> ./test.erl:4: function '#info-person'/1 undefined
>> ./test.erl:4: function '#new-person'/1 undefined
>>
>> I just tried your exact example from the April 19 posting.
>> -module(test).
>> -compile({parse_transform, exprecs}).
>> -record(a, {a, b, c}).
>> -export_records([a]).
>>
>> same type of errors.
>>
>> any ideas?
>> thanks, ke han
>>
>>
>>
>>
>> On Apr 19, 2006, at 12:35 AM, Ulf Wiger ((AL/EAB)) wrote:
>>
>>>
>>> I've written a small(-ish) parse transform that generates code for
>>> accessing exported records.
>>>
>>> I did read through ROK's abstract patterns proposal once more, but
>>> decided that it would be too much to try to implement _that_. The
>>> current hack does use function names that are somewhat similar to
>>> ROK's abstract patterns, but I don't think that will be a problem
>>> (mainly because I don't envision that anyone would use this
>> stuff if
>>> the abstract patterns were
>>> available.)
>>>
>>> The idea is to use records as before, but for module- local
>> use. For
>>> outside callers, records are 'exported'
>>> by including a -export_records([RecName]) directive.
>>> The following code extract illustrates the kind of code laid out by
>>> the parse_transform:
>>>
>>> -module(test).
>>> -compile({parse_transform, exprecs}).
>>> -record(a, {a, b, c}).
>>> -export_records([a]).
>>>
>>> %%% generated code
>>> -export(['#new-a'/0, '#new-a'/1,
>>>          '#get-a'/2, '#set-a'/2,
>>>          '#info-a'/1]).
>>>
>>> '#new-a'() -> #a{}.
>>> '#new-a'(Vals) -> '#set-a'(Vals, #a{}).
>>>
>>> '#get-a'(Attrs, R) when is_list(Attrs) ->
>>>     ['#get-a'(A, R) || A <- Attrs];
>>> '#get-a'(a, R) -> R#a.a;
>>> '#get-a'(b, R) -> R#a.b;
>>> '#get-a'(c, R) -> R#a.c.
>>>
>>> '#set-a'(Vals, Rec) ->
>>>     F = fun ([], R, _F1) -> R;
>>>             ([{a, V} | T], R, F1) -> F1(T, R#a{a = V}, F1);
>>>             ([{b, V} | T], R, F1) -> F1(T, R#a{b = V}, F1);
>>>             ([{c, V} | T], R, F1) -> F1(T, R#a{c = V}, F1)
>>>         end,
>>>     F(Vals, Rec, F).
>>>
>>> '#info-a'(fields) -> record_info(fields, a).
>>>
>>> %%% end generated code
>>>
>>>
>>> A short shell dialogue to illustrate the use:
>>>
>>> Eshell V5.4.12  (abort with ^G)
>>> 1> test:'#new-a'().
>>> {a,undefined,undefined,undefined}
>>> 2> test:'#set-a'([{a,1},{c,3}], v(1)).
>>> {a,1,undefined,3}
>>> 3> test:'#set-a'([{b,2}], v(2)).
>>> {a,1,2,3}
>>> 4> test:'#get-a'(b, v(3)).
>>> 2
>>> 5> test:'#get-a'([a,c], v(3)).
>>> [1,3]
>>> 6> test:'#info-a'(fields).
>>> [a,b,c]
>>>
>>>
>>> Parse transformery attached. It's based on the
>> stools_id_trans module
>>> that I posted a while back, but with improved error handling
>>> (controlled errors in the parse_transform module are reported as
>>> regular compilation
>>> errors.)
>>>
>>> BR,
>>> Ulf W
>>> <exprecs.erl>
>>
>>




More information about the erlang-questions mailing list