Dynamic

The Dynamic global is your escape hatch for working with schema-free data. When you need to deal with JSON-like values that don't fit neatly into a record definition -- API responses, user-provided payloads, configuration blobs -- this is where you go.

Creating Dynamic Values

Convert typed values into dynamic:

Function Description Returns
Dynamic.dyn(bool) Create from boolean dynamic
Dynamic.dyn(int) Create from integer dynamic
Dynamic.dyn(long) Create from long dynamic
Dynamic.dyn(double) Create from double dynamic
Dynamic.dyn(string) Create from string dynamic
dynamic d1 = Dynamic.dyn(true);      // true
dynamic d2 = Dynamic.dyn(42);        // 42
dynamic d3 = Dynamic.dyn(3.14);      // 3.14
dynamic d4 = Dynamic.dyn("hello");   // "hello"

Extension methods work too:

dynamic d = (42).dyn();              // 42
dynamic s = "hello".dyn();           // "hello"

Parsing

Function Description Returns
Dynamic.parse(str) Parse JSON string maybe<dynamic>
Dynamic.to_dyn(str) Parse JSON string (alias) maybe<dynamic>
maybe<dynamic> parsed = Dynamic.parse("{\"name\": \"Alice\", \"age\": 30}");

if (parsed as data) {
  // use data
}

Type Extraction

Pull typed values out of dynamic data:

Function / Method Description Returns
Dynamic.str(d) Extract as string maybe<string>
Dynamic.i(d) Extract as int maybe<int>
Dynamic.l(d) Extract as long maybe<long>
Dynamic.d(d) Extract as double maybe<double>
Dynamic.b(d) Extract as boolean maybe<bool>
dynamic data = @dynamic 42;
maybe<int> val = Dynamic.i(data);         // 42
maybe<string> str = Dynamic.str(data);    // empty (not a string)

Field-Based Extraction

When you have a dynamic object and want to pull out a specific field, there are overloads that take a field name -- and versions with defaults so you don't have to deal with maybe when you know what you want:

Function Description Returns
Dynamic.str(d, field) Extract field as string maybe<string>
Dynamic.str(d, field, default) Extract with default string
Dynamic.i(d, field) Extract field as int maybe<int>
Dynamic.i(d, field, default) Extract with default int
Dynamic.l(d, field) Extract field as long maybe<long>
Dynamic.l(d, field, default) Extract with default long
Dynamic.d(d, field) Extract field as double maybe<double>
Dynamic.d(d, field, default) Extract with default double
Dynamic.b(d, field) Extract field as bool maybe<bool>
Dynamic.b(d, field, default) Extract with default bool
Dynamic.date(d, field) Extract field as date maybe<date>
Dynamic.datetime(d, field) Extract field as datetime maybe<datetime>
dynamic user = @dynamic {"name": "Alice", "age": 30, "active": true};

maybe<string> name = Dynamic.str(user, "name");     // "Alice"
string safe_name = Dynamic.str(user, "name", "?");   // "Alice"
maybe<int> age = Dynamic.i(user, "age");              // 30
int safe_age = Dynamic.i(user, "age", 0);             // 30
maybe<bool> active = Dynamic.b(user, "active");       // true

Type Checking

Sometimes you need to know what kind of value you're dealing with:

Function Description Returns
Dynamic.is_array(d) Check if value is an array bool
Dynamic.is_object(d) Check if value is an object bool
Dynamic.is_string(d) Check if value is a string bool
Dynamic.is_number(d) Check if value is a number bool
Dynamic.is_bool(d) Check if value is a boolean bool
Dynamic.is_null(d, fld) Check if field is null maybe<bool>
dynamic arr = @dynamic [1, 2, 3];
dynamic obj = @dynamic {"x": 1};

bool is_arr = Dynamic.is_array(arr);   // true
bool is_obj = Dynamic.is_object(obj);  // true

Structure Inspection

Function Description Returns
Dynamic.size(d) Get array length or object size maybe<int>
Dynamic.has(d, field) Check if field exists bool
Dynamic.keys(d) Get list of object keys list<string>
dynamic obj = @dynamic {"a": 1, "b": 2, "c": 3};

maybe<int> sz = Dynamic.size(obj);        // 3
bool has_a = Dynamic.has(obj, "a");       // true
bool has_z = Dynamic.has(obj, "z");       // false
list<string> ks = Dynamic.keys(obj);      // ["a", "b", "c"]

Access and Navigation

Function Description Returns
Dynamic.atIndex(d, index) Access array element by index dynamic
Dynamic.atField(d, field) Access object field by name dynamic
dynamic arr = @dynamic [10, 20, 30];
dynamic second = Dynamic.atIndex(arr, 1);   // 20

dynamic obj = @dynamic {"x": 42};
dynamic x_val = Dynamic.atField(obj, "x");  // 42

Transformation

Function Description Returns
Dynamic.merge(target, patch) Merge two dynamic objects dynamic
Dynamic.to_str(d) Convert to JSON string string
Dynamic.arr(items) Convert list to dynamic array dynamic
dynamic base = @dynamic {"a": 1, "b": 2};
dynamic patch = @dynamic {"b": 3, "c": 4};
dynamic merged = Dynamic.merge(base, patch);  // {"a":1,"b":3,"c":4}

string json = Dynamic.to_str(merged);          // "{\"a\":1,\"b\":3,\"c\":4}"

Json Global

The Json global works with the json type -- a structured variant of dynamic that supports field navigation directly.

Function Description Returns
Json.parse(str) Parse JSON string maybe<json>
Json.parsen(str) Parse JSON (null on failure) json
maybe<json> j = Json.parse("{\"x\": 123}");

// Field navigation on json
json data = Json.parsen("[42]");
formula first = data[0];     // 42

Common Patterns

Processing API Responses

procedure handle_response(dynamic response) {
  string status = Dynamic.str(response, "status", "unknown");
  if (status == "success") {
    maybe<int> count = Dynamic.i(response, "count");
    if (count as c) {
      // process count
    }
  }
}

Building Dynamic Objects

procedure build_payload() -> dynamic {
  return Dynamic.merge(
    @dynamic {"type": "event"},
    @dynamic {"timestamp": Time.now()}
  );
}

Method Summary

Function Returns Description
Dynamic.dyn(value) dynamic Create from typed value
Dynamic.parse(str) maybe<dynamic> Parse JSON string
Dynamic.to_dyn(str) maybe<dynamic> Parse JSON string (alias)
Dynamic.str(d) / .str(d,f) maybe<string> Extract string
Dynamic.i(d) / .i(d,f) maybe<int> Extract integer
Dynamic.l(d) / .l(d,f) maybe<long> Extract long
Dynamic.d(d) / .d(d,f) maybe<double> Extract double
Dynamic.b(d) / .b(d,f) maybe<bool> Extract boolean
Dynamic.is_array(d) bool Type check: array
Dynamic.is_object(d) bool Type check: object
Dynamic.is_string(d) bool Type check: string
Dynamic.is_number(d) bool Type check: number
Dynamic.is_bool(d) bool Type check: boolean
Dynamic.is_null(d, field) maybe<bool> Check null field
Dynamic.size(d) maybe<int> Array/object size
Dynamic.has(d, field) bool Check field exists
Dynamic.keys(d) list<string> Object keys
Dynamic.atIndex(d, i) dynamic Array element access
Dynamic.atField(d, f) dynamic Object field access
Dynamic.merge(a, b) dynamic Merge objects
Dynamic.to_str(d) string Convert to JSON string
Dynamic.arr(list) dynamic List to dynamic array
Json.parse(str) maybe<json> Parse to json type
Json.parsen(str) json Parse (null on failure)
Previous Globals
Next Utilities