[erlang-questions] Exporting a record type

Ulf Wiger ulf@REDACTED
Fri Jul 10 10:36:49 CEST 2015


The -export_type/1 construct makes the type visible to other modules, so you can refer to it. It doesn’t correspond to a function call.

In Bob’s example, you could have a module shoe_store, where:

-spec buy(store(), shoes:shoe(), price()) -> receipt().

(Soon, Bob and I will launch our new chain…)


The reason why records should not be ‘exported’ is the compile-time dependency: other modules may break if you change the record structure and they are not recompiled at the same time.

There are a few ways to manage this:
- Only use records inside one module
- Only use records inside one application, since an application is normally built and upgraded as a unit anyway
- Export accessor functions to manipulate the record structure

The last point, accessor functions, may either be high-level or map one-to-one to the record arguments.

There is parse_trans [1] for those who want to rely heavily on exported records and accessor functions. For a practical example, see e.g. [2] and [3]. One can also use exprecs as a low-level support for creating higher-level accessor functions.

Exprecs does have some support for transforming old records to new. This is almost entirely undocumented, and I’ve always considered it incomplete. But as I’m writing this, I did think of one thing that might make it worth documenting - will see if I get a chance to experiment … Meanwhile, [4] offers some hints.

[1] https://github.com/uwiger/parse_trans/blob/master/doc/exprecs.md
[2] http://blogs.openaether.org/?p=253
[3] https://github.com/uwiger/jobs/blob/master/src/jobs_info.erl (jobs_info:pp/1 converts a record to {Tag, Proplist})
[4] https://github.com/uwiger/parse_trans/blob/master/examples/test_exprecs_vsns.erl
Eshell V5.10.4  (abort with ^G)
1> test_exprecs_vsns:f().
'#info-r'(fields) -> [a,b,c]
'#info-r__1_1'(fields)' -> [a,b,c,d] (not exported)
'#info-r__1_2'(fields)' -> [a,b] (not exported)
'#convert-'("1_1", {r,1,2,3,4}) -> {{r,1,2,3},[{d,4}]}
'#convert-'("1_2", {r,1,2}) -> {{r,1,2,undefined},[]}
ok


> On 10 Jul 2015, at 02:05, lloyd@REDACTED wrote:
> 
> Hi folks,
> 
> I've asked Loïc Hoguin directly about this, but I thought an elaboration and discussion might be of interest to many on this list.
> 
> In  Loïc's new book, The Erlanger Playbook, he advocates against using including records through *.hrl. (pp 40-41)
> 
> Instead, he recommends using types:
> 
> -record(state, {}).
> -opaque state() :: #state{}.
> 
> He leaves hanging the question of how to access this record from another module. 
> 
> The Erlang Types and Function Specifications doc suggests that the type can be exported using -export_type(...). But, to my feeble mind, the exposition is less than clear.
> 
> My case and problem is as follows: 
> 
> -record(book, {
>   ... yada yada (some seven fields)
>   }
> 
> I define the record, then:
> 
> -opaque book() :: #book{}.
> 
> -export_type([book/0]).
> 
> Now, I access a remote db in a different module and want to instantiate a book record, but it's not at all clear to me how to do so.
> 
> If I do the following in the console...
> 
> wg_books:book(). I get:
> 
> ** exception error: undefined function wg_dets_books:book/0
> 
> This seems to be an all-to-little documented corner of Erlang. Is there a kind soul who can help show the way?
> 
> Many thanks,
> 
> LRP
> 
> 
> 
> 
> 
> 
> 
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions

Ulf Wiger, Co-founder & Developer Advocate, Feuerlabs Inc.
http://feuerlabs.com






More information about the erlang-questions mailing list