"Key := Val Updates an existing Key
The key must be present in the old map. If Key is not in the old map Erlang will complain loudly.
Using two operations instead of one has several advantages:
A spelling mistake cannot accidentally introduce a new key"
Lord knows how many times I accidentally created a new key with a spelling typo, and then later when I wanted to retrieve the data, I was like "What the hell is wrong? I know I put data in that key, so why is nothing coming back? I guess I have discovered a rare bug in the compiler that no one has ever discovered before."
To counteract such bugs I usually try to use as short names as possible. I mean, there is no point in writing productionDatabase when prodDb works just as well. It has several advantages but one of them is that the latter is much less likely to be misspelled.
"This trick is well known to old-style functional programmers, they waffle on about Y combinators and eat this stuff for breakfast, but it’s the kind of stuff that gives functional programming a bad name. Try explaining this to first year students who had a heavy night out at the pub the evening before."
Priceless (and completely true). I really think this attitude is why Erlang is such a success.
Meh, the Y combinator is a funny hack. A lot of people waffle on about it because they're blown away by how crazy untyped lambda calculus is. There are all kinds of ways to introduce recursion into a language, though. It's simply interesting that you might get it on accident in a language will as little restriction as UTLC.
There are two side notes. 1. Should we really be constrained by frequent pub visitors when teaching CS? Adapting to stupidity (OK, mediocrity) caused Java and switch from Scheme to Python for intro courses at MIT (with great help of mr. Guttag, I suppose).
2. Should we ever hire a person who couldn't get what Y Combinator is or not being able to write one in Scheme?
Update: Python is heavily used in Biology and related research (so they said) and transition at MIT seemed like reasonable, but I still believe that Scheme shall be the language for serious introductory courses, like classic Berkeley CS61a was. Now PLT/Racket folks are doing great job of introducing proper concepts and developing "good habits" to students.
I am in the process of writing an OTP-ish dialect of Erlang that compiles to Javascript and has its own runtime environment (http://luvv.ie/mission.html) so maps is a more work for me, so I am a bit yay!/sigh!...
The thing that I am less clear about with maps is their relationship with Mnesia tables going forward. Mnesia tables take their schema from records. I suspect we will go down the route of having records that contain 'privileged' fields (effectively ones you can have indexes on) and field that contain maps which allow to 'extend' the schema without performing difficult state transforms.
It will certainly help when you need to add a field to a record and thread that change through a running system without stopping it.
Hey, luvvie looks awesome. Thanks for all your great work. I am following it. Sorry don't have much insight as to what happens with Mnesia. Just wanted to thank you for your work.
Whoa. This makes the language feel much more approachable. I love that they've provided both an "upsert" and a semantically distinct "update" for their maps. Working without upsert is painful, but the problem of accidentally inserting when you meant to update is an irritating pitfall. They've really picked a good middle way here.
Does anyone know how often Learn You Some Erlang is updated? I'd definitely take another pass at the language with these features in place. Kudos, team!
Author here. I haven't yet updated it, but plan to eventually update the website with these features. The thing is a lot of it won't need to change majorly.
Maps should be a replacement of data structures like dicts and gb_trees, but I personally do not see them as a replacement of records within a module, where I feel their restrictiveness is welcome, for two main reasons:
1. especially to crash early in live code upgrades, despite, I'm sure, a lot of people disagreeing with me.
2. The module isolation inherent to records makes people think at a protocol level and with their API much, much better than the common pattern of saying "screw it", sharing the state around, and breaking abstraction all over. I like how it constrains the programmer to think of what should be passed around in messages, and that maps may remove that "think hard" part of the problem.
Maps should be especially nice and enable more complex dictionary manipulations, nested key/val mapping, and so on, and in terseness of operations. More elegantly, they could be a decent fix to 'use ETS to optimize K/V operations', although they won't benefit from the same parallel access.
I plan to explain this and possibly revisit some code snippets from the book in an add-on chapter, and also show what I wouldn't change.
Regarding Funs, I probably will just add a section to the anonymous function part, and see if I ever used recursive anoynmous functions before. It's likely that I avoided them on purpose in the book and as such, won't need to add too much there.
>If we now build a large list of objects, all with the same set of keys, then they can share a single key descriptor. This means that asymptotically maps will be as efficient in terms of storage as records.
Credit for this idea comes from Richard O'Keefe who pointed this out years ago. I don’t think any other programming language does this, but I might be wrong.
That is a nice language feature to enforce, I love it :) This is however basically the same thing that V8 / most Javascript runtimes do under the hood[1]. Essentially, as you construct objects and add/remove keys, you back them in the engine with more-efficient shared objects that have the same structure. Add a key D and it moves from <shared structure with A,B,C> to <shared structure with A,B,C,D>. Since most code ends up doing the same kind of operations on a bunch of similar bits of data, you can save a lot of compute-time by assuming that and having a slower fallback when it fails (like using an actual dictionary instead of a Struct-like thing).
That said, Javascript has zero enforcement for this, and the runtimes may have already shifted to something different. They are quite different beasts. Just pointing out that the idea has been around.
[1] it has been a while since I've looked closely, and I may be mistaken. Call it 95% certainty.
I don't think I've ever seen anyone actually use this in production code, of course. And you're free to have your own issues with function declarations and named function expressions having the exact same syntax, which causes a big problem in IE<=8 that is probably responsible for this feature not being in common use (and omitted from CoffeeScript, alas).
Well, most of those really conflate two things: static heterogeneous "maps", and dynamic homogeneous maps. The former being a structure whose keys are known at compile time (static) and whose values may be of different types (heterogeneous); the latter being a structure whose keys are not known until run time (dynamic) and whose values must all be of the same type (homogeneous).
Most languages conflate these, because they kind of look the same, but they are entirely different use cases, with different use patterns, permit different optimizations, and their generalization (a dynamic heterogenous structure) is pretty useless.
The relational model [1], which has been around since 1969, does distinguish these. The static heterogeneous structure is called a "tuple", and the dynamic homogeneous structure is called a "relation".
If only language designers would stop conflating the implementation of these structures with how they are used, we could drop the cringeworthy names "associative array" and "hash", stop calling tuples "maps" (which is a specific kind of relation), and stop calling relations "tables" (which are two-dimensional arrays, which are another kind of relation).
Erlang at least as of R17 has mostly kept this distinction (Erlang maps mostly support the static heterogeneous use case). However the majority of users are keen to jump on the "maps" bandwagon as a way to get syntax support for dynamic homogeneous use (which makes utterly no sense to me, as most of the syntax is for pattern matching and construction, which makes little sense in the dynamic case!). I am glad R17 does not include many of the proposals for such syntax that I've seen on the mailing list; and instead sticks closely to the original static heterogeneous design proposed by Richard O'Keefe.
Well, hashes in particular implies a very specific kind of map/table (one that uses hashing). I think the most common non-implementation-dependent names are maps, dict(ionarie)s, tables, and associative arrays.
Figuring out how to store arbitrary key-value pairs should be one of the first steps in learning a new language, given that every language has a different name for it.
Associative Array is probably my least favorite name for it, since it implies arrays aren't associative. It was a clojure book that first made me realize an array is a map that only allows ints for keys.
As someone who's completely foreign to Erlang, can anyone explain the rationale behind replacing records with maps? At a first glance it seems as though records are nominal types and maps are structural types, and if true that would suggest to me that these are complementary features rather than supplementary ones.
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.
The templating of the key descriptors is neat, but not original. NewtonScript did this in the early 90s (mostly in response to the severe memory pressure on the Apple Newton). I believe that Self did it, too (but those guys were on Sun workstations, and just showing off as far as I'm concerned :-) )
I've got a passing interest in Erlang, and also saw the existence of Elixir http://elixir-lang.org/ , which uses the Erlang VM. Could someone from either language's community comment on if they see a strong future for Elixir?
It runs on Erlang's VM. So there are chances if you pick one up or another you'll be able to at some level inter-operate.
It is up to you, try one and another one. Some people have big issue with Erlang's syntax. I actually kind of like it, so I prefer Erlang.
Others find Elixir more approachable, it reminds them of Ruby for example. Elixir has macros so you can do some nifty things with them. Those kind of blow my mind when I read them so I am afraid I would get too "clever" with them.
You can call Erlang from Elixir fairly easily so you can take advantage of libraries you find for Erlang.
So kind of up to you. Whatever you like or whatever gets you more productive and interested.
I have to say, this is one of my favourite programming books, even though I've never been paid to write any Erlang at all. Just the insights into how to go about building reliable systems are inspiring and profoundly affected my work in other languages.
That and it's written in a brilliantly approachable style.
Thank you for mentioning this book. I intend to learn Erlang after I finish studying Haskell, and I'll probably use this book because of your recommendation.
EEP-43 [0] standards draft, with an extensive overview of new Maps features, plenty of examples, and discussion on a few different syntax proposals they had.
(Is there any newer official documentation for maps? I couldn't find anything.)
An F#-like operator |> would be useless without a convenient partial application syntax. Macro-like operators aren't well received in Erlang, certainly not when they obfuscate what really is going on.
Egad, the color scheme he uses in the code blocks is horrible. The snook.ca contrast calculator says that's only a 2.66:1 contrast ratio, which is terribly unreadable. It needs to be at least 7:1.
There's been lots of chatter about maps on the mailing list; but the named inline functions thing is totally out of the blue to me, and totally welcome. Erlang does such a great job of fixing everything that OCaml almost but didn't quite get right.
Implementor here. Richard O'Keefe deserves all the credit as he had the idea and suggested the syntax (EEP 37). I just noticed that it was easy to implement it through let rec expressions in Core Erlang. No VM changes were required.
[+] [-] lkrubner|12 years ago|reply
"Key := Val Updates an existing Key The key must be present in the old map. If Key is not in the old map Erlang will complain loudly. Using two operations instead of one has several advantages: A spelling mistake cannot accidentally introduce a new key"
Lord knows how many times I accidentally created a new key with a spelling typo, and then later when I wanted to retrieve the data, I was like "What the hell is wrong? I know I put data in that key, so why is nothing coming back? I guess I have discovered a rare bug in the compiler that no one has ever discovered before."
[+] [-] rdtsc|12 years ago|reply
[+] [-] bjourne|12 years ago|reply
[+] [-] ams6110|12 years ago|reply
Maybe less likely, but if you've been writing a lot of code using -> and then in one case need := I can see it happening quite easily.
[+] [-] judk|12 years ago|reply
[+] [-] urbit|12 years ago|reply
Priceless (and completely true). I really think this attitude is why Erlang is such a success.
[+] [-] tel|12 years ago|reply
[+] [-] thirsteh|12 years ago|reply
[+] [-] dschiptsov|12 years ago|reply
Update: Python is heavily used in Biology and related research (so they said) and transition at MIT seemed like reasonable, but I still believe that Scheme shall be the language for serious introductory courses, like classic Berkeley CS61a was. Now PLT/Racket folks are doing great job of introducing proper concepts and developing "good habits" to students.
[+] [-] gordonguthrie|12 years ago|reply
The thing that I am less clear about with maps is their relationship with Mnesia tables going forward. Mnesia tables take their schema from records. I suspect we will go down the route of having records that contain 'privileged' fields (effectively ones you can have indexes on) and field that contain maps which allow to 'extend' the schema without performing difficult state transforms.
It will certainly help when you need to add a field to a record and thread that change through a running system without stopping it.
[+] [-] rdtsc|12 years ago|reply
[+] [-] portmanteaufu|12 years ago|reply
Does anyone know how often Learn You Some Erlang is updated? I'd definitely take another pass at the language with these features in place. Kudos, team!
[+] [-] mononcqc|12 years ago|reply
Maps should be a replacement of data structures like dicts and gb_trees, but I personally do not see them as a replacement of records within a module, where I feel their restrictiveness is welcome, for two main reasons:
1. especially to crash early in live code upgrades, despite, I'm sure, a lot of people disagreeing with me.
2. The module isolation inherent to records makes people think at a protocol level and with their API much, much better than the common pattern of saying "screw it", sharing the state around, and breaking abstraction all over. I like how it constrains the programmer to think of what should be passed around in messages, and that maps may remove that "think hard" part of the problem.
Maps should be especially nice and enable more complex dictionary manipulations, nested key/val mapping, and so on, and in terseness of operations. More elegantly, they could be a decent fix to 'use ETS to optimize K/V operations', although they won't benefit from the same parallel access.
I plan to explain this and possibly revisit some code snippets from the book in an add-on chapter, and also show what I wouldn't change.
Regarding Funs, I probably will just add a section to the anonymous function part, and see if I ever used recursive anoynmous functions before. It's likely that I avoided them on purpose in the book and as such, won't need to add too much there.
Let me know if that sounds good to you.
[+] [-] sandal|12 years ago|reply
[+] [-] Groxx|12 years ago|reply
Credit for this idea comes from Richard O'Keefe who pointed this out years ago. I don’t think any other programming language does this, but I might be wrong.
That is a nice language feature to enforce, I love it :) This is however basically the same thing that V8 / most Javascript runtimes do under the hood[1]. Essentially, as you construct objects and add/remove keys, you back them in the engine with more-efficient shared objects that have the same structure. Add a key D and it moves from <shared structure with A,B,C> to <shared structure with A,B,C,D>. Since most code ends up doing the same kind of operations on a bunch of similar bits of data, you can save a lot of compute-time by assuming that and having a slower fallback when it fails (like using an actual dictionary instead of a Struct-like thing).
That said, Javascript has zero enforcement for this, and the runtimes may have already shifted to something different. They are quite different beasts. Just pointing out that the idea has been around.
[1] it has been a while since I've looked closely, and I may be mistaken. Call it 95% certainty.
[+] [-] Cushman|12 years ago|reply
For the record, one of these is another thing JavaScript got right, sort of, with named function expressions:
I don't think I've ever seen anyone actually use this in production code, of course. And you're free to have your own issues with function declarations and named function expressions having the exact same syntax, which causes a big problem in IE<=8 that is probably responsible for this feature not being in common use (and omitted from CoffeeScript, alas).[+] [-] masklinn|12 years ago|reply
[+] [-] sdegutis|12 years ago|reply
[+] [-] colanderman|12 years ago|reply
Most languages conflate these, because they kind of look the same, but they are entirely different use cases, with different use patterns, permit different optimizations, and their generalization (a dynamic heterogenous structure) is pretty useless.
The relational model [1], which has been around since 1969, does distinguish these. The static heterogeneous structure is called a "tuple", and the dynamic homogeneous structure is called a "relation".
If only language designers would stop conflating the implementation of these structures with how they are used, we could drop the cringeworthy names "associative array" and "hash", stop calling tuples "maps" (which is a specific kind of relation), and stop calling relations "tables" (which are two-dimensional arrays, which are another kind of relation).
Erlang at least as of R17 has mostly kept this distinction (Erlang maps mostly support the static heterogeneous use case). However the majority of users are keen to jump on the "maps" bandwagon as a way to get syntax support for dynamic homogeneous use (which makes utterly no sense to me, as most of the syntax is for pattern matching and construction, which makes little sense in the dynamic case!). I am glad R17 does not include many of the proposals for such syntax that I've seen on the mailing list; and instead sticks closely to the original static heterogeneous design proposed by Richard O'Keefe.
[1] http://en.wikipedia.org/wiki/Relational_model
[+] [-] shadowfiend|12 years ago|reply
[+] [-] kevinmchugh|12 years ago|reply
Figuring out how to store arbitrary key-value pairs should be one of the first steps in learning a new language, given that every language has a different name for it.
Associative Array is probably my least favorite name for it, since it implies arrays aren't associative. It was a clojure book that first made me realize an array is a map that only allows ints for keys.
[+] [-] kibwen|12 years ago|reply
[+] [-] masklinn|12 years ago|reply
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:
will print: 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: will generate no warning from either erlang itself or dialyzer, and will print 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. [0] http://www.erlang.org/eeps/eep-0043.html section "Dialyzer and Type specification", sadly not directly linkable.[+] [-] kabdib|12 years ago|reply
[+] [-] leakybucket|12 years ago|reply
[+] [-] lostcolony|12 years ago|reply
[+] [-] rdtsc|12 years ago|reply
It is up to you, try one and another one. Some people have big issue with Erlang's syntax. I actually kind of like it, so I prefer Erlang.
Others find Elixir more approachable, it reminds them of Ruby for example. Elixir has macros so you can do some nifty things with them. Those kind of blow my mind when I read them so I am afraid I would get too "clever" with them.
You can call Erlang from Elixir fairly easily so you can take advantage of libraries you find for Erlang.
So kind of up to you. Whatever you like or whatever gets you more productive and interested.
[+] [-] NDizzle|12 years ago|reply
[1]: http://pragprog.com/book/jaerlang2/programming-erlang
[+] [-] fidotron|12 years ago|reply
That and it's written in a brilliantly approachable style.
[+] [-] Buttons840|12 years ago|reply
[+] [-] riquito|12 years ago|reply
http://www.erlang.org/eeps/eep-0043.html
[+] [-] minikomi|12 years ago|reply
[+] [-] talklittle|12 years ago|reply
(Is there any newer official documentation for maps? I couldn't find anything.)
[0]: http://www.erlang.org/eeps/eep-0043.html
[+] [-] pointernil|12 years ago|reply
Compared with maps adding a fun-call chaining operator like |> should be child's play, right? ;)
Seriously, what are the functional programmer's tricks to handle long function call chains in languages without the |> or similar operators?
Anyway, maps are a more important addition to the environment for sure. So thanks again.
[+] [-] nox_|12 years ago|reply
[+] [-] momerath|12 years ago|reply
[+] [-] oinksoft|12 years ago|reply
[+] [-] sbierwagen|12 years ago|reply
(CSS edited for clarity)
[+] [-] colanderman|12 years ago|reply
[+] [-] nox_|12 years ago|reply
[+] [-] siraaj|12 years ago|reply
[+] [-] brickcap|12 years ago|reply
[+] [-] nodivbyzero|12 years ago|reply
[+] [-] varg|12 years ago|reply