Skip to content

Commit 4fec259

Browse files
authored
Add clarifying Gotchas regarding JSON encoding (#213)
1 parent 13da34e commit 4fec259

1 file changed

Lines changed: 32 additions & 1 deletion

File tree

markdown/api/library/json/encode.markdown

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,42 @@ _[Table][api.type.Table]._ Lua table containing optional directives to the JSON
3535
3. All control chars are encoded to `\uXXXX` format, for example `"\021"` encodes to `"\u0015"`.
3636
4. All JSON `\uXXXX` chars are decoded to chars (`0`-`255` byte range only).
3737
5. JSON single line `//` and `/* */` block comments are discarded during decoding.
38-
6. Numerically indexed Lua arrays are encoded to JSON lists, for example `[1,2,3]`.
38+
6. A Lua table is encoded to a JSON array when all of its keys are positive integers (gaps are permitted), for example `[1,2,3]`. The presence of any key that isn't a positive integer forces the entire table to be encoded as a JSON object instead.
3939
7. Lua dictionary tables are converted to JSON objects, for example `{"one":1,"two":2}`.
4040
8. By default, JSON nulls are decoded to Lua `nil` and treated by Lua in the normal way (for example, they appear not to exist — see [json.decode()][api.library.json.decode]).
4141

4242

43+
## Gotchas
44+
45+
JSON has two collection types, arrays (`[]`) and objects (`{}`), but Lua has only the table, so `json.encode()` has to pick one. A table is encoded as an array when all of its keys are positive integers (gaps are permitted), and as an object the moment any non-integer key is present.
46+
47+
Because JSON object keys are always strings, every key in an object-encoded table is stringified, integer keys included. Adding a single key that isn't a positive integer therefore changes how the entire table is encoded, including its positive-integer keys:
48+
49+
``````lua
50+
local json = require( "json" )
51+
52+
local t1 = {
53+
[1] = 1,
54+
[2] = 2,
55+
[3] = 3,
56+
}
57+
print( json.encode( t1 ) ) --> [1,2,3]
58+
59+
local t2 = {
60+
[1] = 1,
61+
[2] = 2,
62+
[3] = 3,
63+
["a"] = "a",
64+
}
65+
print( json.encode( t2 ) ) --> {"1":1,"2":2,"a":"a","3":3}
66+
``````
67+
68+
Two consequences follow:
69+
70+
1. __Round-tripping does not preserve integer keys.__ `json.decode( json.encode( t2 ) )` returns a table keyed by the strings `"1"`, `"2"`, `"3"`, not the integers `1`, `2`, `3`. Code that later indexes with `t[1]` will get `nil`.
71+
2. __Key order in an object is not guaranteed.__ Do not rely on the position of keys in the encoded string.
72+
73+
4374
## Examples
4475

4576
##### General

0 commit comments

Comments
 (0)