auto-generated record access functions
Ulf Wiger (AL/EAB)
ulf.wiger@REDACTED
Tue May 30 13:18:26 CEST 2006
Hi,
I modified the parse_transform somewhat so that it correctly handles
modules with no hand-written functions. My exhaustive testing was to
compile this module:
-module(test2).
-compile({parse_transform, exprecs}).
-record(r, {a1, a2}).
-export_records([r]).
and verify that the functions were generated appropriately.
Regarding the special requirements on exception semantics, my first
instinct is to stick to the default erlang semantics. This is only a
quick hack to solve a specific problem. You are of course free to extend
the parse_transform to suit your needs. To back up this claim, I've
inserted an EPL statement in the file.
BR,
Ulf W
> -----Original Message-----
> From: ke han [mailto:ke.han@REDACTED]
> Sent: den 29 maj 2006 19:36
> To: Ulf Wiger (AL/EAB)
> Cc: erlang-questions@REDACTED
> Subject: Re: auto-generated record access functions
>
> 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:ke.han@REDACTED]
> >> Sent: den 29 maj 2006 16:09
> >> To: Ulf Wiger (AL/EAB)
> >> Cc: erlang-questions@REDACTED
> >> 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>
> >>
> >>
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: exprecs.erl
Type: application/octet-stream
Size: 10731 bytes
Desc: exprecs.erl
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20060530/da513a7f/attachment.obj>
More information about the erlang-questions
mailing list