Values API
The Values API defines the runtime value system used by the Prism interpreter, including all value types, confidence tracking, and value operations.
Overview
The value system provides:
- Type-safe runtime values
- Confidence metadata support
- Value equality and truthiness
- String representations
- Automatic confidence propagation
Base Value Class
export abstract class Value {
abstract type: string;
abstract value: unknown;
abstract equals(other: Value): boolean;
abstract isTruthy(): boolean;
abstract toString(): string;
}
All runtime values extend this abstract base class.
Methods
equals()
equals(other: Value): boolean
Compares two values for equality. Each value type implements its own equality logic.
isTruthy()
isTruthy(): boolean
Determines if a value is truthy for conditional expressions.
toString()
toString(): string
Returns a string representation of the value.
Primitive Value Types
NumberValue
class NumberValue extends Value {
type = 'number';
constructor(public value: number)
}
Properties:
value
: The numeric value
Equality: Strict numeric equality Truthy: When not zero String: Standard number formatting
Example:
const num = new NumberValue(42);
console.log(num.toString()); // "42"
console.log(num.isTruthy()); // true
const zero = new NumberValue(0);
console.log(zero.isTruthy()); // false
StringValue
class StringValue extends Value {
type = 'string';
constructor(public value: string)
}
Properties:
value
: The string value
Equality: String content equality Truthy: When not empty String: The string itself
Example:
const str = new StringValue("hello");
console.log(str.toString()); // "hello"
console.log(str.isTruthy()); // true
const empty = new StringValue("");
console.log(empty.isTruthy()); // false
BooleanValue
class BooleanValue extends Value {
type = 'boolean';
constructor(public value: boolean)
}
Properties:
value
: The boolean value
Equality: Boolean value equality Truthy: The boolean value itself String: "true" or "false"
Example:
const bool = new BooleanValue(true);
console.log(bool.toString()); // "true"
console.log(bool.isTruthy()); // true
NullValue
class NullValue extends Value {
type = 'null';
value = null;
constructor()
}
Equality: Only equal to other null values Truthy: Always false String: "null"
Example:
const nullVal = new NullValue();
console.log(nullVal.toString()); // "null"
console.log(nullVal.isTruthy()); // false
UndefinedValue
class UndefinedValue extends Value {
type = 'undefined';
value = undefined;
constructor()
}
Equality: Only equal to other undefined values Truthy: Always false String: "undefined"
Example:
const undef = new UndefinedValue();
console.log(undef.toString()); // "undefined"
console.log(undef.isTruthy()); // false
Collection Value Types
ArrayValue
class ArrayValue extends Value {
type = 'array';
value: Value[];
constructor(public elements: Value[])
}
Properties:
elements
: Array of Value objectsvalue
: Same as elements (for compatibility)
Equality: Element-wise equality comparison Truthy: Always true String: "[element1, element2, ...]"
Example:
const arr = new ArrayValue([
new NumberValue(1),
new StringValue("two"),
new BooleanValue(true)
]);
console.log(arr.toString()); // "[1, two, true]"
console.log(arr.elements.length); // 3
ObjectValue
class ObjectValue extends Value {
type = 'object';
value: Map<string, Value>;
constructor(public properties: Map<string, Value>)
}
Properties:
properties
: Map of property names to valuesvalue
: Same as properties (for compatibility)
Equality: All properties must match
Truthy: Always true
String: "{ key1: value1, key2: value2, ... }"
Example:
const obj = new ObjectValue(new Map([
['name', new StringValue('Alice')],
['age', new NumberValue(30)],
['active', new BooleanValue(true)]
]));
console.log(obj.toString()); // "{ name: Alice, age: 30, active: true }"
// Access property
const name = obj.properties.get('name');
console.log(name?.toString()); // "Alice"
Function Value Type
FunctionValue
class FunctionValue extends Value {
type = 'function';
constructor(
public name: string,
public value: (args: Value[]) => Promise<Value>,
public arity?: number
)
}
Properties:
name
: Function name for displayvalue
: The async function implementationarity
: Optional parameter count
Equality: Name equality (same function) Truthy: Always true String: "[Function: name]"
Example:
const add = new FunctionValue(
'add',
async (args: Value[]) => {
if (args.length !== 2) {
throw new Error('add requires 2 arguments');
}
const a = args[0] as NumberValue;
const b = args[1] as NumberValue;
return new NumberValue(a.value + b.value);
},
2 // arity
);
console.log(add.toString()); // "[Function: add]"
// Call the function
const result = await add.value([
new NumberValue(5),
new NumberValue(3)
]);
console.log(result.toString()); // "8"
Confidence Value Type
ConfidenceValue
class ConfidenceValue extends Value {
type = 'confident';
constructor(
public value: Value,
public confidence: ConfidenceLib
)
}
Properties:
value
: The wrapped valueconfidence
: Confidence score (0-1)
Equality: Both value and confidence must match Truthy: Based on wrapped value String: "value (~confidence)"
Example:
import { ConfidenceLib } from '@prism-lang/core';
const confidentStr = new ConfidenceValue(
new StringValue("prediction"),
new ConfidenceLib(0.85)
);
console.log(confidentStr.toString()); // "prediction (~0.85)"
console.log(confidentStr.isTruthy()); // true (non-empty string)
// Access wrapped value
const innerValue = confidentStr.value as StringValue;
console.log(innerValue.value); // "prediction"
// Access confidence
console.log(confidentStr.confidence.value); // 0.85
Value Operations
Type Checking
// Check value type
if (value instanceof NumberValue) {
console.log(value.value); // Safe to access number
}
// Check for confidence
if (value instanceof ConfidenceValue) {
const confidence = value.confidence;
const inner = value.value;
}
// Type property check
if (value.type === 'array') {
// value is ArrayValue
}
Value Creation Helpers
// Create values from JavaScript types
function fromJS(value: any): Value {
if (typeof value === 'number') {
return new NumberValue(value);
} else if (typeof value === 'string') {
return new StringValue(value);
} else if (typeof value === 'boolean') {
return new BooleanValue(value);
} else if (value === null) {
return new NullValue();
} else if (value === undefined) {
return new UndefinedValue();
} else if (Array.isArray(value)) {
return new ArrayValue(value.map(fromJS));
} else if (typeof value === 'object') {
const props = new Map<string, Value>();
for (const [k, v] of Object.entries(value)) {
props.set(k, fromJS(v));
}
return new ObjectValue(props);
}
throw new Error(`Cannot convert value: ${value}`);
}
Extracting JavaScript Values
// Extract JavaScript value
function toJS(value: Value): any {
if (value instanceof ConfidenceValue) {
return toJS(value.value);
}
switch (value.type) {
case 'number':
return (value as NumberValue).value;
case 'string':
return (value as StringValue).value;
case 'boolean':
return (value as BooleanValue).value;
case 'null':
return null;
case 'undefined':
return undefined;
case 'array':
return (value as ArrayValue).elements.map(toJS);
case 'object':
const obj: any = {};
for (const [k, v] of (value as ObjectValue).properties) {
obj[k] = toJS(v);
}
return obj;
default:
return value.toString();
}
}
Confidence Propagation
When operations involve confident values, confidence is propagated:
// Example: Adding confident numbers
const a = new ConfidenceValue(new NumberValue(10), new ConfidenceLib(0.9));
const b = new ConfidenceValue(new NumberValue(20), new ConfidenceLib(0.8));
// Result will have combined confidence (e.g., min of inputs)
const result = add(a, b); // 30 with confidence ~0.8
Memory Considerations
- Value Sharing: Values are immutable and can be safely shared
- Garbage Collection: Values are GC'd when no longer referenced
- Circular References: Avoid circular references in objects/arrays
- Large Collections: Be mindful of memory with large arrays/objects
Best Practices
- Type Safety: Always check value types before casting
- Confidence Handling: Preserve confidence through operations
- Error Messages: Include value type in error messages
- Immutability: Treat values as immutable
- Equality: Use
.equals()
for value comparison
Example: Custom Value Type
// Create a custom date value type
class DateValue extends Value {
type = 'date';
constructor(public value: Date) {
super();
}
equals(other: Value): boolean {
return other instanceof DateValue &&
other.value.getTime() === this.value.getTime();
}
isTruthy(): boolean {
return true;
}
toString(): string {
return this.value.toISOString();
}
}
// Usage
const date = new DateValue(new Date('2024-01-01'));
console.log(date.toString()); // "2024-01-01T00:00:00.000Z"