You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `«module»` module also provides [«sibling/arity»](https://www.erlang.org/doc/apps/«app»/«module».html#«sibling»/«arity»), which «one-line contrast».
75
75
76
76
```lfe
77
-
> («module»:«sibling» «args»)
77
+
lfe> («module»:«sibling» «args»)
78
78
«actual output»
79
79
```
80
80
81
81
<!-- 7. CLOSE — arc posts: trail next week ("Next week, we will …").
82
82
Standalone posts: a one-sentence practicality verdict ("While the
83
-
odds are low you'll reach for this daily, …"). Then sign. -->
83
+
odds are low you'll reach for this daily, …"). No signature line —
84
+
the author byline is rendered at the top of the post. -->
84
85
«Closing line.»
85
-
86
-
- «Surname»
87
86
````
88
87
89
88
## Pre-publish checklist (from the style guide, §9)
@@ -96,7 +95,8 @@ The `«module»` module also provides [«sibling/arity»](https://www.erlang.org
96
95
5. Exactly one deeper cut, ≤2 paragraphs.
97
96
6. No headings/bullets in the body unless the post genuinely turns a
98
97
corner; ~250–450 words incl. code (~650–1,100 for arc installments).
99
-
7. Signature line; arc recap + trail lines if in an arc.
98
+
7. No signature line (author byline is rendered at the top); arc recap +
description: "Reopening LFE Friday with the safe map read: maps:get/3 hands back a default instead of crashing on a missing key — plus the one eager-evaluation gotcha to know."
cover_alt: "Vigdís — LFE Friday, LiffyBot reaching into a glowing key-value lattice in a Mead-style command room"
18
+
math: false
19
+
---
20
+
21
+
Today's LFE Friday digs into [`maps:get/3`](https://www.erlang.org/doc/apps/stdlib/maps.html#get/3) — and with it, quietly reopens the series after a rather long pause.
22
+
23
+
It has been a while. The last time LFE Friday reached for a key-value store, the answer was [`dict:merge/3`](/blog/tutorials/2015/03/01/1823-lfe-friday---dictmerge3), back in March 2015. `dict` still works. But it is no longer where modern LFE reaches first: the `maps` module landed in Erlang/OTP 17, a few months after this series first started, and somehow never got its turn here. So the revival starts where you actually start most days — pulling a value back out of a map without getting burned when the key isn't there. Over the next few Fridays we will walk the rest of the module; today, the safe read.
24
+
25
+
`maps:get/3` takes a key, a map, and a default value. It returns the value stored under that key — or, if the key is not in the map, the default you handed it. That third argument is the whole point: it is the difference between a lookup that answers and a lookup that crashes.
Notice the shell hands the keys back in its own order, not the order we typed them in — `maps` are unordered, and the printed layout reflects the map's internal arrangement rather than our insertion order. Reading a key that exists, though, is unremarkable, which is exactly what you want from a read.
35
+
36
+
```lfe
37
+
lfe> (maps:get 'host config)
38
+
"localhost"
39
+
lfe> (maps:get 'port config)
40
+
8080
41
+
```
42
+
43
+
Those are `maps:get/2`, the two-argument cousin. Now let's try to break it — what happens when we ask for a key that isn't there?
44
+
45
+
```lfe
46
+
lfe> (maps:get 'timeout config)
47
+
** exception error: #(badkey timeout)
48
+
in (maps : get timeout #M(port 8080 scheme http host "localhost"))
49
+
```
50
+
51
+
`maps:get/2` does not shrug and hand back `undefined` the way some languages' map lookups do. A missing key is an *error* — `#(badkey timeout)` — and it will take down a process that wasn't expecting it. Often that strictness is precisely what you want. But just as often you have a sensible fallback in mind, and crashing is overkill. That is what the third argument buys you.
52
+
53
+
```lfe
54
+
lfe> (maps:get 'timeout config 5000)
55
+
5000
56
+
lfe> (maps:get 'host config "0.0.0.0")
57
+
"localhost"
58
+
```
59
+
60
+
When the key is missing you get the default; when it is present the default is ignored and you get the real value. One function — no `try`, no `case`.
61
+
62
+
There is one wrinkle worth knowing before you sprinkle `maps:get/3` everywhere. LFE, like Erlang, **evaluates arguments eagerly**: every argument is computed *before* the call happens. So the default is built whether or not it ends up being used.
The key `host` is present, so `"fallback"` is thrown away — but `computing default` still printed, because the argument was evaluated first. For a constant like `5000` that costs nothing. For a default that hits a database or spawns a process, it is a real bill, paid on every lookup, including the hits. When the default is expensive, don't reach for `get/3` — reach for `maps:find/2` and decide what to do only on a miss.
71
+
72
+
```lfe
73
+
lfe> (maps:find 'host config)
74
+
#(ok "localhost")
75
+
lfe> (maps:find 'timeout config)
76
+
error
77
+
```
78
+
79
+
`maps:find/2` is `get/3`'s quieter sibling: instead of a default, it tells you whether the key was there at all, as a tagged result — `#(ok Value)` or the bare atom `error` — that you can match on, rather than a value you can't tell apart from a real stored default.
80
+
81
+
This is also where the decade shows. `dict` has `fetch/2` (crashes, like `get/2`) and `find/2` (tagged, like `maps:find/2`) — but no ergonomic fetch-with-a-default. `maps:get/3` — which arrived in OTP 17.1, a point release behind the `maps` module itself — folds that whole pattern into a single call, and underneath, a map lookup is effectively constant-time for the sizes you'll meet in practice. That economy is a good part of why `maps` won.
82
+
83
+
Next week we will start putting things *into* maps.
0 commit comments