Skip to content

Commit 341de45

Browse files
nojafzth
andauthored
Initial dictionary page (#1006)
* Initial dictionary page * expand and rework docs on dicts a bit * add dict to the syntax widget --------- Co-authored-by: Gabriel Nordeborn <[email protected]>
1 parent 3cd0ba0 commit 341de45

File tree

4 files changed

+270
-0
lines changed

4 files changed

+270
-0
lines changed

data/sidebar_manual_v1200.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"tuple",
3838
"record",
3939
"object",
40+
"dict",
4041
"variant",
4142
"polymorphic-variant",
4243
"null-undefined-option",

misc_docs/syntax/language_dict.mdx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
id: "dict"
3+
keywords: ["dict"]
4+
name: "dict"
5+
summary: "This is the `dict{}` syntax"
6+
category: "languageconstructs"
7+
---
8+
9+
> Available in v12+
10+
11+
The `dict{}` syntax is used to represent [dictionaries](dict.md). It's used both when creating dicts, and when pattern matching on dicts.
12+
13+
### Example
14+
15+
<CodeTab labels={["ReScript", "JS Output"]}>
16+
17+
```res
18+
// Create a dict
19+
let d = dict{"A": 5, "B": 6, "C": 7}
20+
21+
// Pattern match on the full dict
22+
let b = switch d {
23+
| dict{"B": b} => Some(b)
24+
| _ => None
25+
}
26+
27+
// Destructure the dict
28+
let dict{"C": ?c} = d
29+
```
30+
31+
```js
32+
let d = {
33+
A: 5,
34+
B: 6,
35+
C: 7
36+
};
37+
38+
let b = d.B;
39+
40+
let b$1 = b !== undefined ? b : undefined;
41+
42+
let c = d.C;
43+
```
44+
45+
</CodeTab>
46+
47+
### References
48+
49+
* [Dictionaries](/docs/manual/latest/dict)
50+
51+

pages/docs/manual/v12.0.0/dict.mdx

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
title: "Dictionary"
3+
description: "Dictionary data structure in ReScript"
4+
canonical: "/docs/manual/v12.0.0/dict"
5+
---
6+
7+
# Dictionary
8+
9+
ReScript has first class support for dictionaries. Dictionaries are mutable objects with string keys, where all values must have the same type. Dicts compile to regular JavaScript objects at runtime.
10+
11+
## Create
12+
13+
You can create a new dictionary in a few different ways, depending on your use case.
14+
15+
<CodeTab labels={["ReScript", "JS Output"]}>
16+
17+
```res prelude
18+
// Using the first class dict syntax
19+
let d = dict{"A": 5, "B": 6}
20+
21+
// Programatically via the standard library
22+
let d2 = Dict.fromArray([("A", 5), ("B", 6)])
23+
```
24+
25+
```js
26+
let d = {
27+
A: 5,
28+
B: 6
29+
};
30+
31+
let d2 = Object.fromEntries([
32+
[
33+
"A",
34+
5
35+
],
36+
[
37+
"B",
38+
6
39+
]
40+
]);
41+
42+
```
43+
44+
</CodeTab>
45+
46+
A few things to note here:
47+
48+
* Using the first class `dict{}` syntax compiles cleanly to a JavaScript object directly
49+
* Using `Dict.fromArray` is useful when you need to create a dictionary programatically
50+
51+
## Access
52+
53+
You can access values from a Dictionary either via the the standard library `Dict` module functions, or using pattern matching.
54+
55+
<CodeTab labels={["ReScript", "JS Output"]}>
56+
57+
```res prelude
58+
let d = dict{"A": 5, "B": 6, "C": 7}
59+
60+
// Using `Dict.get`
61+
let a = d->Dict.get("A")
62+
63+
// Switching on the full dict
64+
let b = switch d {
65+
| dict{"B": b} => Some(b)
66+
| _ => None
67+
}
68+
69+
// Destructuring
70+
let dict{"C": ?c} = d
71+
```
72+
73+
```js
74+
let d = {
75+
A: 5,
76+
B: 6,
77+
C: 7
78+
};
79+
80+
let a = d["A"];
81+
82+
let b = d.B;
83+
84+
let b$1 = b !== undefined ? b : undefined;
85+
86+
let c = d.C;
87+
```
88+
</CodeTab>
89+
90+
> In the Destructuring example, we're using the `?` optional pattern match syntax to pull out the `C` key value as an optional, regardless of if the dict has it or not.
91+
92+
## Pattern matching
93+
Dictionaries have first class support for pattern matching. Read more in the [dedicated guide on pattern matching and destructring in ReScript](pattern-matching-destructuring.md#match-on-dictionaries).
94+
95+
## Updating and setting values
96+
97+
You can set and update new values on your dictionary using the `Dict.set` function. All updates are mutable.
98+
99+
<CodeTab labels={["ReScript", "JS Output"]}>
100+
101+
```res prelude
102+
let d = dict{"A": 5, "B": 6}
103+
104+
d->Dict.set("C", 7)
105+
```
106+
107+
```js
108+
let d = {
109+
A: 5,
110+
B: 6
111+
};
112+
113+
d["C"] = 7;
114+
```
115+
116+
</CodeTab>
117+
118+
## Advanced example: Pattern matching on JSON
119+
120+
JSON objects are represented as dictionaries (`dict<JSON.t>`). You can leverage that fact to decode JSON in a nice way, using only language features:
121+
122+
<CodeTab labels={["ReScript", "JS Output"]}>
123+
124+
```res prelude
125+
type user = {
126+
name: string,
127+
email: string,
128+
}
129+
130+
/** Decode JSON to a `user`.
131+
let decodeUser = (json: JSON.t) => {
132+
switch json {
133+
| Object(dict{"name": JSON.String(name), "email": JSON.String(email)}) =>
134+
Some({name, email})
135+
| _ => None
136+
}
137+
}
138+
139+
```
140+
141+
```js
142+
function decodeUser(json) {
143+
if (typeof json !== "object" || json === null || Array.isArray(json)) {
144+
return;
145+
}
146+
let name = json.name;
147+
if (typeof name !== "string") {
148+
return;
149+
}
150+
let email = json.email;
151+
if (typeof email === "string") {
152+
return {
153+
name: name,
154+
email: email
155+
};
156+
}
157+
158+
}
159+
```
160+
161+
</CodeTab>

pages/docs/manual/v12.0.0/pattern-matching-destructuring.mdx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,63 @@ printStudents({
762762

763763
</CodeTab>
764764

765+
### Match on Dictionaries
766+
767+
You can pattern match on dictionaries just like you can on other ReScript data structures.
768+
769+
When pattern matching on a dictionary it's assumed by default that you're expecting the keys you match on to exist in the dictionary. Example:
770+
<CodeTab labels={["ReScript", "JS Output"]}>
771+
772+
```res prelude
773+
let d = dict{"A": 5, "B": 6}
774+
775+
// We're expecting the `B` key to exist below, and `b` will be `int` in the match branch
776+
let b = switch d {
777+
| dict{"B": b} => Some(b)
778+
| _ => None
779+
}
780+
```
781+
782+
```js
783+
let d = {
784+
A: 5,
785+
B: 6
786+
};
787+
788+
let b = d.B;
789+
790+
let b$1 = b !== undefined ? b : undefined;
791+
```
792+
793+
</CodeTab>
794+
795+
However, there are situations where you want to pull out the value of a key as an option. You can do that using the `?` optional syntax in the pattern match:
796+
797+
<CodeTab labels={["ReScript", "JS Output"]}>
798+
799+
```res prelude
800+
let d = dict{"A": 5, "B": 6}
801+
802+
// We're pulling out `B` regardless of if it has a value or not, and therefore get `b` as `option<int>`
803+
let b = switch d {
804+
| dict{"B": ?b} => b
805+
}
806+
```
807+
808+
```js
809+
let d = {
810+
A: 5,
811+
B: 6
812+
};
813+
814+
let b = d.B;
815+
```
816+
817+
</CodeTab>
818+
819+
Notice how in the first case, when not using `?`, we had to supply a catch-all case `_`. That's because the pattern match _expects_ `B` to exist in the first case, for the pattern to match. If `B` doesn't exist, the match falls through to the next branch, and therefore we need to catch it to be exhaustive in our matching.
820+
821+
However, in the second case, we don't need a catch-all case. That's because the first branch will _always_ match the dictionary - either `B` exists or it doesn't, but it doesn't matter because we're pulling it out as an optional value.
765822

766823
### Small Pitfall
767824

0 commit comments

Comments
 (0)