8. Dynamic values
A dval holds data whose shape is known only at run time. JSON, YAML, request data, task props, and unit calls use dval values.
Read decoded data
function RENDER(request : dval) {
var profile := json_decode("{\"name\":\"Ada\"}")
print(profile.name, "\n")
}
Output
Ada
json_decode returns a dval. Member syntax reads a map key. Bracket syntax also works:
function RENDER(request : dval) {
var profile := {name: "Ada"}
print(profile["name"], "\n")
}
Use brackets for a dynamic key, a key that is not an identifier, or a list index.
Missing data
A missing read returns none instead of changing the map or trapping:
function RENDER(request : dval) {
var profile := {name: "Ada"}
var nickname := profile.nickname
if nickname? {
print(nickname)
} else {
print("guest")
}
}
value? is false only when the dval is none. An empty string, false, an empty map, and an empty list are present values.
A key can exist and contain none. Use has(profile, "nickname") when that distinction matters.
Convert a scalar
Scalar constructors convert a dval to a static Capy type:
function RENDER(request : dval) {
var profile := {name: "Ada"}
var name := string(profile.name)
var visits := s32(profile.visits)
print(name, " ", visits, "\n")
}
The options map can set fallback. Capy uses it when the converted text is empty or cannot convert to the requested type. Omit the map when the type default is correct.
Use has(profile, "name") before get(profile, "name") when a missing value is an error.
Create dynamic data
A map literal creates a dval map:
function RENDER(request : dval) {
var user := {name: "Ada", active: true}
var empty := {}
print(user.name, " ", empty?, "\n")
}
A bare list is a typed array. Wrap it with dval when it must be a dynamic list. length(value) returns the number of entries in a dval map or list. It traps if the dval is a scalar:
function RENDER(request : dval) {
var tags := dval(["math", "logic"])
print(tags[0], "\n")
}
Mutate a dval
A dval is a mutable reference value inside one workspace. Assignment, parameters, returns, and captures share its identity:
function set_email(profile : dval) {
profile.contact.email = "ada@example.test"
}
function RENDER(request : dval) {
var profile := {}
var alias := profile
set_email(alias)
print(profile.contact.email, "\n")
}
Content mutation through the parameter affects the caller. The parameter binding remains immutable, so profile = {} is invalid.
Nested assignment mutates its target and returns the same identity. The root must be a named local, parameter, or captured dval binding. Temporary, call, member, array-item, and loop-item roots are invalid. Nested assignment creates missing maps. An existing list accepts only an in-range nonnegative index. Capy does not create sparse lists.
The set, push, pop, delete, clear, and get_or_create functions mutate their target. Each function returns that same identity. Reassignment remains valid:
function RENDER(request : dval) {
var profile := {}
profile = set(profile, "active", true)
print(profile.active, "\n")
}
Member and index reads return copied child values. Pure transformations return copies when their API specifies a copy.
Iterate a dval
Use the value-first loop forms:
function show(values : dval) {
for item := values { print(item, "\n") }
for item, key := values { print(key, ": ", item, "\n") }
}
function RENDER(request : dval) {
show({name: "Ada"})
}
The key has type string. dval list keys are decimal strings. Each item is a copied dval. The loop uses a live view and rechecks the current count. A loop that keeps growing its iterable can continue.
Boundaries
A dval keeps identity only inside one workspace. Bearer, module, component, task, custom export, codec, request, and serialization boundaries copy BRRB. Identity never crosses a boundary. A dval can hold a named function or closure only in its current workspace. A typed read requires the exact function signature. A mismatch traps. Public BRRB, JSON, YAML, and XML replace callable entries with none. Maps keep keys. Lists keep indexes. JSON and YAML preserve none as null. XML writes none as empty text and cannot recover the distinction.