Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> As someone who's completely foreign to Erlang, can anyone explain the rationale behind replacing records with maps?

Simplicity and flexibility. Erlang records have to be declared and they're nothing more than syntactic sugar for tuples.

> At a first glance it seems as though records are nominal types

They're not, not in the way you'd usually expect anyway. They're little more than macros for accessing tuple fields by name:

    -module(test).

    -record(foo, {bar, baz}).

    main(_) ->
        R = #foo{bar=1, baz=2},
        io:format("~w~n", [R]).
will print:

    {foo,1,2}
the record information does not exist at runtime. In fact, you can just create the corresponding tuple and tell Erlang to interpret it as a record:

    S = {foo, 2, 3},
    T = S#foo{bar=3},
    io:format("~w ~w~n", [S, T]).
will generate no warning from either erlang itself or dialyzer, and will print

    {foo,2,3} {foo,3,3}
And although dialyzer (erlang's "type checker") can use records as type specs, it will be updated to handle map specs[0], allowing for the exact same static expressivity since you can define a map with explicitly specified keys e.g.

    -type foo() :: #{ 'status' => 'update' | 'keep', 'c' => integer() }
[0] http://www.erlang.org/eeps/eep-0043.html section "Dialyzer and Type specification", sadly not directly linkable.


Having the record not exist at runtime can lead to issues if you serialise you records using term_to_binary. If the format of the record changes, old records can no longer be accessed.

    1> rd(person, {name, email}).
    person
    2> P = #person{name = 'John', email = 'john@example.com'}.
    #person{name = 'John',email = 'john@example.com'}
    3> P#person.email.
    'john@example.com'
    4> rd(person, {name, email, age}).
    person
    5> P#person.email.
    ** exception error: {badrecord,person}


That is actually good in my opinion, because of how static records are expected to be in structure. You shouldn't be able to reload or proceed with data dating from an earlier version as if nothing happened.

You have to think about what changed and prepare for an upgrade from any version you may encounter, rather than move along with incorrect data, similar to if it were corrupted.

I fear Erlang programmers will use maps in a way that allows them to be sloppy, rather than just exploiting the flexibility they allow. Double-edged sword, in a way.


I suspect what you will find is that API's are defined with records, one or more of whose fields is a map. You do kind of do that with Mnesia tables where you want to specify the indexable-keys up front, but need to have the flexibility to extend the schema - a nice kv list does the trick.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: