Objects & Utilities
Tova provides functions for working with objects (key-value maps). These functions make it easy to inspect, transform, and combine objects.
Inspecting Objects
keys
keys(obj) -> List[String]Returns an array of the object's keys.
keys({ name: "Alice", age: 30 })
// ["name", "age"]
keys({})
// []// Check if an object has a specific key
fn has_key(obj, key) {
contains(keys(obj), key)
}values
values(obj) -> ListReturns an array of the object's values.
values({ name: "Alice", age: 30 })
// ["Alice", 30]
values({ a: 1, b: 2, c: 3 }) |> sum()
// 6entries
entries(obj) -> List[[String, T]]Returns an array of [key, value] pairs.
entries({ name: "Alice", age: 30 })
// [["name", "Alice"], ["age", 30]]// Convert object to formatted string
config = { host: "localhost", port: 3000, debug: true }
config
|> entries()
|> map(fn(pair) "{pair[0]}={pair[1]}")
|> join(", ")
// "host=localhost, port=3000, debug=true"Combining & Copying
merge
merge(...objs) -> ObjectShallow-merges multiple objects together. Later objects override earlier ones for duplicate keys.
merge({ a: 1 }, { b: 2 })
// { a: 1, b: 2 }
merge({ a: 1, b: 2 }, { b: 3, c: 4 })
// { a: 1, b: 3, c: 4 }
// Merge multiple objects
defaults = { theme: "light", lang: "en", debug: false }
user_prefs = { theme: "dark" }
overrides = { debug: true }
merge(defaults, user_prefs, overrides)
// { theme: "dark", lang: "en", debug: true }clone
clone(obj) -> ObjectCreates a deep clone of an object. Nested objects and arrays are fully copied, not shared by reference.
original = { name: "Alice", scores: [90, 85, 92] }
copy = clone(original)
// Modifying the copy does not affect the original
copy.scores[0] = 100
print(original.scores[0]) // 90Immutability
freeze
freeze(obj) -> ObjectMakes an object immutable. Any attempt to modify the object's properties after freezing will have no effect (in strict mode, it throws an error).
config = freeze({
api_url: "https://api.example.com",
timeout: 5000,
max_retries: 3
})
// config.timeout = 10000 -- this would have no effect or throw// Freeze is useful for constants
COLORS = freeze({
red: "#ff0000",
green: "#00ff00",
blue: "#0000ff"
})Inspecting & Accessing
has_key
has_key(obj, key) -> BoolReturns true if the object has the given key. Safely handles nil.
has_key({ name: "Alice", age: 30 }, "name") // true
has_key({ name: "Alice" }, "email") // false
has_key(nil, "anything") // falseget
get(obj, path, default?) -> T | NilSafe nested property access using a dot-separated path string or array of keys. Returns nil (or the default) if any part of the path is missing.
user = { name: "Alice", address: { city: "NYC", zip: "10001" } }
get(user, "address.city") // "NYC"
get(user, "address.country") // nil
get(user, "address.country", "US") // "US"
// Array path syntax
get(user, ["address", "zip"]) // "10001"from_entries
from_entries(pairs) -> ObjectCreates an object from an array of [key, value] pairs. The inverse of entries().
from_entries([["name", "Alice"], ["age", 30]])
// { name: "Alice", age: 30 }
// Round-trip: entries → transform → from_entries
{ a: 1, b: 2 }
|> entries()
|> map(fn(pair) [pair[0], pair[1] * 10])
|> from_entries()
// { a: 10, b: 20 }Selecting & Transforming
pick
pick(obj, keys) -> ObjectReturns a new object containing only the specified keys.
pick({ a: 1, b: 2, c: 3 }, ["a", "c"])
// { a: 1, c: 3 }
// Extract public fields from a user object
pick(user, ["name", "email", "avatar"])omit
omit(obj, keys) -> ObjectReturns a new object with the specified keys removed.
omit({ a: 1, b: 2, c: 3 }, ["b"])
// { a: 1, c: 3 }
// Remove sensitive fields before sending to client
omit(user, ["password", "ssn", "internal_id"])map_values
map_values(obj, fn) -> ObjectTransforms each value in the object using a function. The function receives (value, key).
map_values({ a: 1, b: 2, c: 3 }, fn(v) v * 10)
// { a: 10, b: 20, c: 30 }
map_values({ math: 85, science: 92 }, fn(v, k) "{k}: {v}%")
// { math: "math: 85%", science: "science: 92%" }Patterns
Pipeline with Object Functions
// Clean and reshape config
config
|> omit(["internal", "debug"])
|> map_values(fn(v) to_string(v))
// Combine two sources, keeping only needed fields
merge(defaults, user_prefs)
|> pick(["theme", "lang", "timezone"])