Skip to content

Guide Computations

Kris Simon edited this page Mar 1, 2026 · 5 revisions

Computations

Computations transform data within a feature set. The Compute action is the primary tool for deriving new values from existing data through built-in operations, arithmetic expressions, and custom plugins.

Overview

The Compute action belongs to the OWN semantic role - it transforms data internally without external side effects.

When to Use Compute vs Create

Use Case Action Example
Derive a value from another Compute Compute the <length> from the <message>.
Create a new object literal Create Create the <user> with { name: "John" }.
Apply a named operation Compute Compute the <hash> from the <password>.
Perform arithmetic Compute Compute the <total> from <price> * <quantity>.

Built-in Operations

The Compute action provides these built-in operations:

Operation Description Input Types
length Character/element count String, Array, Dictionary
count Alias for length String, Array, Dictionary
hash Compute hash value Any (converts to String)
uppercase Convert to uppercase String
lowercase Convert to lowercase String
identity Return input unchanged Any

String Length

Compute the <length> from the <message>.
Compute the <count> from the <text>.

Returns the number of characters in a string:

(* message = "Hello, World!" *)
Compute the <length> from the <message>.
(* length = 13 *)

Collection Size

The same operations work on arrays and dictionaries:

(* items = ["apple", "banana", "cherry"] *)
Compute the <count> from the <items>.
(* count = 3 *)

(* config = { host: "localhost", port: 8080 } *)
Compute the <length> from the <config>.
(* length = 2 *)

Case Transformations

Compute the <upper: uppercase> from the <text>.
Compute the <lower: lowercase> from the <text>.

Example:

(* text = "Hello, World!" *)
Compute the <upper: uppercase> from the <text>.
(* upper = "HELLO, WORLD!" *)

Compute the <lower: lowercase> from the <text>.
(* lower = "hello, world!" *)

Hashing

Compute the <hash> from the <password>.

Returns an integer hash value useful for comparisons and checksums.

Naming Results

By default, the operation name becomes the variable name:

Compute the <length> from the <message>.  (* binds to 'length' *)

The Qualifier-as-Name Syntax

When you need multiple results of the same operation, use a qualifier to specify the operation while the base becomes the variable name:

Compute the <variable: operation> from the <input>.

This syntax separates:

  • Base (variable): The variable name to bind the result
  • Qualifier (operation): The operation to perform

Example: Comparing Two Lengths

(Compare Messages: String Analysis) {
    Extract the <greeting> from the <input: greeting> with "Hello, World!".
    Extract the <farewell> from the <input: farewell> with "Goodbye!".

    (* Compute lengths with distinct variable names *)
    Compute the <greeting-length: length> from the <greeting>.
    Compute the <farewell-length: length> from the <farewell>.

    (* Both values are available for comparison *)
    Compare the <greeting-length> against the <farewell-length>.

    Return an <OK: status> with {
        greeting: <greeting-length>,
        farewell: <farewell-length>
    }.
}

Example: Multiple Transformations

(Text Formatting: String Operations) {
    Extract the <text> from the <input> with "Mixed Case Text".

    (* All three variables are distinct *)
    Compute the <original-length: length> from the <text>.
    Compute the <upper-case: uppercase> from the <text>.
    Compute the <lower-case: lowercase> from the <text>.

    Return an <OK: status> with {
        original: <text>,
        length: <original-length>,
        upper: <upper-case>,
        lower: <lower-case>
    }.
}

Arithmetic Operations

Compute supports arithmetic expressions with these operators:

Operator Description Example
+ Addition <price> + <tax>
- Subtraction <balance> - <withdrawal>
* Multiplication <quantity> * <price>
/ Division <total> / <count>
% Modulo <value> % 2
++ String concatenation <first> ++ <last>

Arithmetic Examples

(Calculate Order: Shopping Cart) {
    Extract the <price> from the <item: price> with 100.
    Extract the <quantity> from the <item: quantity> with 3.

    (* Compute subtotal *)
    Compute the <subtotal> from <price> * <quantity>.

    (* Compute tax (8%) *)
    Compute the <tax> from <subtotal> * 0.08.

    (* Compute total *)
    Compute the <total> from <subtotal> + <tax>.

    Return an <OK: status> with {
        subtotal: <subtotal>,
        tax: <tax>,
        total: <total>
    }.
}

String Concatenation

Compute the <full-name> from <first-name> ++ " " ++ <last-name>.
Compute the <greeting> from "Hello, " ++ <name> ++ "!".

Set Operations

ARO provides three polymorphic set operations that work across Lists, Strings, and Objects.

Operations

Operation Description Syntax
intersect Elements in both Compute the <result: intersect> from <a> with <b>.
difference Elements in A not in B Compute the <result: difference> from <a> with <b>.
union All unique elements Compute the <result: union> from <a> with <b>.

List Operations

Create the <list-a> with [2, 3, 5].
Create the <list-b> with [1, 2, 3, 4].

Compute the <common: intersect> from <list-a> with <list-b>.
(* Result: [2, 3] *)

Compute the <only-in-a: difference> from <list-a> with <list-b>.
(* Result: [5] *)

Compute the <all: union> from <list-a> with <list-b>.
(* Result: [2, 3, 5, 1, 4] *)

Multiset Semantics

When lists contain duplicates, intersect preserves duplicates up to the minimum count:

Create the <a> with [1, 2, 2, 3].
Create the <b> with [2, 2, 2, 4].

Compute the <common: intersect> from <a> with <b>.
(* Result: [2, 2] — two 2s appear in both *)

String Operations

Compute the <shared: intersect> from "hello" with "bello".
(* Result: "ello" *)

Compute the <unique: difference> from "hello" with "bello".
(* Result: "h" *)

Object Operations (Deep)

For objects, set operations perform deep recursive comparison:

Create the <obj-a> with { name: "Alice", age: 30 }.
Create the <obj-b> with { name: "Alice", age: 31 }.

Compute the <common: intersect> from <obj-a> with <obj-b>.
(* Result: { name: "Alice" } — only matching key-value pairs *)

Type Behavior Summary

Operation Lists Strings Objects
intersect Elements in both (multiset) Chars in both Keys with matching values
difference In A, not in B Chars in A, not in B Keys in A, not matching B
union A preserved + unique from B A preserved + unique from B Merge (A wins conflicts)

Extending via Plugins

The ComputationService protocol allows plugins to add custom computations.

ComputationService Protocol

public protocol ComputationService: Sendable {
    func compute(named: String, input: Any) async throws -> any Sendable
}

Creating a Custom Computation Plugin

  1. Create a plugin file in your plugins/ directory:
// plugins/HashService.swift
import Foundation
import CryptoKit

@_cdecl("aro_plugin_init")
public func pluginInit() -> UnsafePointer<CChar> {
    let metadata = """
    {
        "computations": ["sha256", "md5"]
    }
    """
    return UnsafePointer(strdup(metadata)!)
}

// Implementation of ComputationService
public struct CryptoComputationService: ComputationService {
    public func compute(named: String, input: Any) async throws -> any Sendable {
        guard let str = input as? String else {
            throw ComputationError.invalidInput
        }

        switch named.lowercased() {
        case "sha256":
            let digest = SHA256.hash(data: Data(str.utf8))
            return digest.map { String(format: "%02x", $0) }.joined()

        case "md5":
            let digest = Insecure.MD5.hash(data: Data(str.utf8))
            return digest.map { String(format: "%02x", $0) }.joined()

        default:
            throw ComputationError.unknownOperation(named)
        }
    }
}
  1. Use in ARO code:
(Hash Password: Security) {
    Extract the <password> from the <input: password>.

    (* Use custom sha256 computation from plugin *)
    Compute the <password-hash: sha256> from the <password>.

    Return an <OK: status> with <password-hash>.
}

Plugin Discovery

Plugins are automatically discovered from the plugins/ directory relative to your application. See the Plugin chapter for full details on plugin development.

Common Patterns

Aggregation

Retrieve the <orders> from the <order-repository>.
Compute the <order-count: count> from the <orders>.

Derived Values

Extract the <price> from the <product: price>.
Extract the <discount> from the <promotion: percent>.
Compute the <discount-amount> from <price> * (<discount> / 100).
Compute the <final-price> from <price> - <discount-amount>.

Normalization

Extract the <email> from the <user: email>.
Compute the <normalized-email: lowercase> from the <email>.

Chaining Computations

Compute the <base-price> from <quantity> * <unit-price>.
Compute the <discounted> from <base-price> * (1 - <discount>).
Compute the <with-tax> from <discounted> * (1 + <tax-rate>).
Compute the <final: identity> from <with-tax>.

Related Actions

Action Purpose
Create Create new objects from literals
Transform Type conversions (string → int, etc.)
Validate Check values against rules
Compare Compare two values

See Also

Clone this wiki locally