JSON
Beamtalk's Json class handles parsing and generation of JSON data.
Parsing primitives
Json parse: returns a Result — unwrap it to get the value:
(Json parse: "42") unwrap // => 42
(Json parse: "3.14") unwrap // => 3.14
(Json parse: "true") unwrap // => true
(Json parse: "false") unwrap // => false
(Json parse: "null") unwrap // => nil
Type mapping
JSON types map to Beamtalk types:
| JSON | Beamtalk |
|---|---|
42 | Integer |
3.14 | Float |
true / false | Boolean |
null | nil |
"text" | String |
[1, 2] | List |
{"k": "v"} | Dictionary |
(Json parse: "42") unwrap class // => Integer
(Json parse: "3.14") unwrap class // => Float
Arrays
JSON arrays become Lists:
list := (Json parse: "[1, 2, 3]") unwrap // => _
list size // => 3
list at: 1 // => 1
list at: 3 // => 3
(Json parse: "[]") unwrap size // => 0
Objects and nested structures
JSON objects become Dictionaries with string keys. Since Beamtalk uses
{...} for string interpolation, build JSON objects using Json generate:
from a Dictionary:
json := Json generate: #{"name" => "Alice", "age" => 30} // => _
json class // => String
obj := (Json parse: json) unwrap // => _
obj at: "name" // => Alice
obj at: "age" // => 30
obj size // => 2
Nested structures work naturally:
inner := #{"name" => "Bob", "scores" => #(10, 20, 30)} // => _
json := Json generate: #{"user" => inner} // => _
data := (Json parse: json) unwrap // => _
user := data at: "user" // => _
user at: "name" // => Bob
scores := user at: "scores" // => _
scores size // => 3
scores at: 2 // => 20
Generating JSON
Json generate: converts Beamtalk values to JSON strings:
Json generate: 42 // => 42
Json generate: "hello" // => "hello"
Json generate: true // => true
Json generate: nil // => null
Collections:
Json generate: #(1, 2, 3) // => [1,2,3]
Json generate: #() // => []
Pretty printing
Json prettyPrint: adds indentation for readability:
pretty := Json prettyPrint: #(1, 2, 3) // => _
pretty class // => String
Round-tripping
Parse and generate are inverses for simple values:
(Json parse: (Json generate: 42)) unwrap // => 42
(Json parse: (Json generate: "hello")) unwrap // => hello
(Json parse: (Json generate: #(1, 2, 3))) unwrap size // => 3
Error handling
Invalid JSON returns an error Result:
result := Json parse: "not valid json" // => _
result isError // => true
result isOk // => false
(Json parse: "42") isOk // => true
Summary
Parsing:
Json parse: jsonString → Result<value>
result unwrap → parsed value (raises on error)
result isOk / isError → Boolean
Generating:
Json generate: value → JSON String
Json prettyPrint: value → pretty-printed JSON String
Type mapping: Integer, Float, Boolean, nil, String, List, Dictionary.
Exercises
1. Round-trip a dictionary. Create a dictionary #{"language" => "Beamtalk", "year" => 2026},
convert it to JSON with Json generate:, parse it back, and verify both keys
are preserved.
Hint
original := #{"language" => "Beamtalk", "year" => 2026}
json := Json generate: original
parsed := (Json parse: json) unwrap
parsed at: "language" // => "Beamtalk"
parsed at: "year" // => 2026
2. Sum a JSON array. Parse the JSON string "[10, 20, 30, 40]" and compute
the sum of all elements using inject:into:.
Hint
nums := (Json parse: "[10, 20, 30, 40]") unwrap
nums inject: 0 into: [:sum :n | sum + n] // => 100
3. Handle invalid JSON. Try parsing "not valid json" — what does the
Result contain? How would you provide a fallback value?
Hint
result := Json parse: "not valid json"
result isError // => true
result isOk // => false
// Provide a fallback:
value := result isOk ifTrue: [result unwrap] ifFalse: [#{}]
// value => #{} (empty dictionary as fallback)
Next: Chapter 21 — DateTime & Time