Archive

Posts Tagged ‘Record’

Record introspection at compile time

October 8th, 2009

For AMF implementation, I have to define the mapping between Actionscript classes with something equivalent in Erlang. First thing came into my mind is record. However, I immediately encountered some of the difficulties when using records in Erlang

  1. Read: can’t use reflection easily after parsing AMF, I received the object with properties/values and I need to map to the corresponding record
  2. Write: Need to introspect the record and write its properties into binaries

I found this post from trapexit. However, I need specifically more than that.

Normally records are defined in a header file “.hrl”. And the idea is to generate utility codes (getter, setter, record meta data ….) at compile time. The heart of it is epp:parse_file/3 function. The generator (or the helper) reads header files, parses all records and create a compilable .erl file which contains all functions you need to do all magic with records:

  1. set(Obj, PropertyName, Value) -> {ok, NewObj, {PropertyName, Value}}
  2. get(Obj, PropertyName) -> {ok, Value}
  3. fields(record_name) -> Fields = [string()]
  4. fields_atom(record_name) -> Fields = [term()]
  5. type(Obj) -> record_name

messages.hrl – the source

record_helper.erl – the generator

record_utils.erl – the generated source

Below is the demonstration of how to generate and use the record utils

1> c(record_helper.erl).
{ok,record_helper}
2> record_helper:make(["messages.hrl"], ".").
ok
3> ls().
messages.hrl            record_helper.beam
record_helper.erl      record_utils.erl
ok
6> c(record_utils).
{ok,record_utils}
7> rr("messages.hrl").
[abstract_message,async_message]
8> Obj = #async_message{}.
#async_message{
    parent =
        #abstract_message{
            clientId = undefined,destination = undefined,
            messageId = undefined,timestamp = undefined,
            timeToLive = undefined,headers = undefined,body = undefined},
    correlationId = undefined,correlationIdBytes = undefined}
9> record_utils:set(Obj, correlationId, "ADF-123-DDF-543").
{ok,#async_message{
        parent =
            #abstract_message{
                clientId = undefined,destination = undefined,
                messageId = undefined,timestamp = undefined,
                timeToLive = undefined,headers = undefined,body = undefined},
        correlationId = "ADF-123-DDF-543",
        correlationIdBytes = undefined},
    {correlationId,"ADF-123-DDF-543"}}
10> {ok,NewObj, _} = record_utils:set(Obj, correlationId, "ADF-123-DDF-543").
{ok,#async_message{
        parent =
            #abstract_message{
                clientId = undefined,destination = undefined,
                messageId = undefined,timestamp = undefined,
                timeToLive = undefined,headers = undefined,body = undefined},
        correlationId = "ADF-123-DDF-543",
        correlationIdBytes = undefined},
    {correlationId,"ADF-123-DDF-543"}}
11> record_utils:get(NewObj, correlationId).
{ok,"ADF-123-DDF-543"}
12> record_utils:type(NewObj).
async_message

record_helper.erl is not so clean as there’re all string concatenations … further improvements can be:

  1. Using template language like ErlyDTL or ErlTL
  2. Clean up code to have more friendly arguments
  3. You add ….

AMF, Basic, Record , ,