[erlang-questions] maps or records?

Siraaj Khandkar <>
Tue Mar 1 04:15:26 CET 2016

On 2/29/16 3:02 PM, Torben Hoffmann wrote:
> Jesper Louis Andersen <> writes:
>> [ text/plain ]
>> On Mon, Feb 29, 2016 at 4:28 PM, Siraaj Khandkar <>
>> wrote:
>>> In other words, I'm saying it is very possible to have this cake (of
>>> public structure) and eat it too (in private, without anyone accessing the
>>> rapidly-changing, secret cream) :)
>> You are so close to the idea of view types, and Torben hinted me I should
>> say something about them :)
>> One advantage of a function is that it doesn't have to give you the field
>> outright, but can provide ways to dynamically cast that structure into
>> another structure you export. Two really good examples is that you can
>> return some kind of tuple depending on the contents of the data and thus
>> you can build a case match on the data. This ad-hoc
>> for-the-purpose-construction of a datatype can often yield far more precise
>> code since it splits analysis of what is *in* the datastructure from
>> computation which says what to *do* about that data. Say we have a #uri{}
>> record. The path component has many possible representations: a binary(), a
>> list of binaries, an iterator, and so on. Different view-functions would
>> give you different ways to handle that binary.
>> Another nice thing is that functions can give you are
>> zipper/derivative/delimiting-continuation over the data in the structure.
>> The path-component can then be unfolded one path-entry at a time:
>> pth(X) ->
>>      case http_uri:unfold_path(X) of
>>          none -> ...;
>>          {some, C, X2} ->
>>             ... C ... pth(X2)
>>      end.
>> or you can imagine a gb_trees/gb_sets like iterator over the data structure.
>> A plain map() cannot give any of these ideas, and its transparency also
>> tightly couples your code to the map() structure. So one has to carefully
>> weigh what kind of interface you want in the long run. I much prefer views
>> of the data structures if possible since it allows for more freedom in the
>> long run, but it requires you to be able to figure out what kind of
>> functions you would need a priori on the data. On the other hand, it
>> provides for much better hiding of what is going on inside the module,
>> which allows you more flexibility regarding backwards compatibility.
>> In other words: exporting records across application boundaries tend to
>> lock them down, so be pretty sure they are set in stone. Also think hard if
>> you want every user to implement the analysis code. The view is much like
>> in a database: do you export the raw records, or do you expose a
>> transactional API through stored procedures which tell you what you can do
>> with the data?
> Why attempt to write a half-baked answer when you can ask Jesper to
> explain it well?!?! [1]
> Look at Cowboy and Webmachine for examples of how to provide functions
> to work with a request.
> Both have a very rich API for extracting relevant things out of the
> request record.
> No need to start poking into that record on your own.

I think you missed the point, see my reply to Jesper :)

That said, since you bring-up Cowboy, it is a good example of what I 
mean by other constraints and plans - an author might want to fill-in 
some of the fields lazily (such body in cowboy_req), in which case 
per-field accessor functions are their only good choice, unless, of 
course, they want to consider compound subsets (of, say, only the 
eagerly calculated parts, but I digress - it isn't the important 
point)... :) Anyhow, without a specific application and vision for it's 
future, which API design direction to take is not something you or I can 
finalize here - it depends on a bunch of things.

The important point is that, by using an abstract type, you're not at 
all limiting yourself to exposing per-field accessor functions - you can 
do other things (if you wish), as long as you make a clear distinction 
between internals and API.

More information about the erlang-questions mailing list