so that employee() would inherit the field name from person().
But it seems that this is not correct Erlang.
I know how to do that in OO languages (subclasses), and in C (union of structs). What would be the idiomatic/correct way to implement something like that in Erlang? Or, if subtyping is not the way to do that, how would I avoid repeatedly including “name” in all types of person, as in the following?
-type employee() :: #{name => string(), salary => non_neg_integer()}.
-type freelancer() :: #{name => string(), hourly_rate => non_neg_integer()}.
% ... (several other types of person here)
Thank you for your answer – I understand what you mean. I’ll wait for someone to confirm if this is the way to go (not using maps and using records).
One possibility is to define a map with some mandatory and some optional key-val entries, so in your example name would be mandatory while salary becomes optional.
In this case you can then match for the specific key (or keys) to see if a specific entity has the properties of an employee or not, and treat them accordingly.
One benefit of maps is that entities may or may not have certain properties, without having to be forced to conform to some rigid class hierarchy.
The same can also be done with records, by leaving certain “optional” fields as undefined.
Note: the above probably works best if the properties are unrelated to each other. If they do interact or depend on each other, then you may have to document this as comments, as type specs may not be able to express the relationships between the different optional properties.
Maps should be similar to records in performance when you’re dealing with “small maps” (32 elements or less), see Maps — Erlang System Documentation v28.3 for details.
You could also e.g. use a record for the mandatory fields and have one of the record fields store a map of “optional” data, to minimise the size of the map.
What data structure to pick will be somewhat dependent on what kind of data you want to represent, how the access/update pattern looks and to what extent it needs to be able to add new field.
Ok, I understand. The documentation on maps doesn’t make this clear to me:
“When creating a new map, always create it with all keys that will ever be used. To maximize sharing of keys (thus minimizing memory use), create a single function that constructs the map using the map syntax and always use it.”
It isn’t clear wether this means “do not use optional keys” or not… So from what you’re saying, optional keys are ok.
But anyway, I already have the answers I needed. Thanks a lot!