04 — Core

Bindings

A Binding is a named, typed variable. A Bindings container holds multiple bindings and acts as the shared workspace for rules — conditions read from it, and actions write to it.

Creating Bindings

// Create a standard bindings container
Bindings bindings = Bindings.builder().standard();

// Simple bind (type is inferred)
bindings.bind("name", "Alice");
bindings.bind("age", 30);

// Typed bind (explicit type)
bindings.bind("score", Integer.class, 95);

// Generic types using TypeReference
bindings.bind("tags", new TypeReference<List<String>>() {}, new ArrayList<>());

Lambda Shorthand

When running rules, you can pass bindings as lambdas. The parameter name becomes the binding name:

// These two are equivalent:

// Explicit
Bindings b = Bindings.builder().standard();
b.bind("name", "Alice");
b.bind("age", 30);
rule.run(b);

// Lambda shorthand
rule.run(name -> "Alice", age -> 30);

Reading Values

// Get value (returns Object)
Object val = bindings.getValue("name");

// Get the Binding object itself
Binding<String> binding = bindings.getBinding("name");
String name = binding.getValue();  // "Alice"

Updating Values

// Update via the Binding object
Binding<Integer> ageBind = bindings.getBinding("age");
ageBind.setValue(31);

// Or directly on the container — returns the previous value
Integer prev = bindings.setValue("age", 31);  // prev == 30

// setValueOrBind: sets the value if the binding exists,
// otherwise creates a new binding. Returns the previous value or null.
Integer old = bindings.setValueOrBind("score", 100);

Checking Bindings

// Does a binding exist?
boolean exists = bindings.contains("name");  // true

// How many bindings?
int count = bindings.size();

// View as a Map (returns this — no copy made)
Map<String, Object> map = bindings.asMap();

Bindings as a Map

As of 1.2.0, Bindings directly implements java.util.Map<String, Object>. You can pass a Bindings instance anywhere a Map is expected — useful for scripting integration and interop with libraries that consume Map.

// Full Map contract — read operations
bindings.containsKey("name");     // true
bindings.containsValue("Alice");  // true
bindings.get("age");               // 30
bindings.keySet();                  // Set of binding names
bindings.values();                  // Collection of values
bindings.entrySet();                // Set of name-value entries

// Mutation via Map API uses bind/setValue semantics
bindings.put("status", "approved");

// remove() and clear() throw UnsupportedOperationException

Insertion order: DefaultScopedBindings now preserves insertion order (backed by LinkedHashSet instead of HashSet). The iteration order of bindings is predictable and matches the order they were added.

Scoped Bindings

Scoped bindings create a child scope that inherits from a parent. Changes in the child don't affect the parent:

Bindings scoped = Bindings.builder().scoped();
// Useful for isolating rule execution contexts

Duplicate names: By default, binding the same name twice will throw an exception. Each binding name must be unique within a container.