[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