A first look at Jvav.
Start with familiar functions and values. Then preview a computation before applying its result to state.
Jvav is under active design. These examples follow the working draft.
Functions and values
A function declares its parameters and result type. Here, twice takes an integer and returns the sum of that value with itself.
pure fun twice(x: Int): Int {
return x + x
}
val result = twice(21)pure declares that the computation derives its result from its declared dependencies and produces no externally observable side effect. Returning a value does not, on its own, make a function pure.
Jvav keeps familiar control flow, including conditions, loops, and early returns. Their syntax does not by itself imply an external effect.
A computation you can preview
A transition describes a computation over state that can be previewed before its result is applied. A pure function can calculate that result and return a transition T without changing the original state.
pure fun swap(
pair: transition Pair
): transition Pair {
return {
a = pair.b
b = pair.a
}
}The input provides the old state of a particular pair. Both reads refer to that state: describing the new a does not change the value read by pair.a.
The result describes replacement values for a and b. Any omitted fields retain their old values on a valid application. Computing or returning this result does not modify the pair.
Applying a change
The caller chooses the point at which a computed change is applied. With the necessary mutation authority and a valid target, the working notation is:
val change = swap(pair)
transition(pair) = change
a = 2, b = 7a = 7, b = 2The first line calculates a value. The second line performs a side effect. This separation lets the same decision logic support inspection, simulation, and execution.
A stored transition represents the calculation already performed; applying it later does not rerun that calculation. The rules for a target that has changed in the meantime remain Pending in the working draft.
Explore the movement exampleAccess and dependencies
Parameter types make access explicit. view T provides read-only, non-owning access. mut T grants authority to modify existing state, subject to the function's effect contract.
context T declares a typed dependency that the calling environment can supply. A damage calculation can read an entity and consult combat rules without changing the world:
pure fun resolve(
damage: Damage,
target: view Entity,
context: context CombatContext
): DamageResultDifferent combat rules can produce a different result. The context remains a real dependency even when its argument is supplied implicitly. Its access and effect restrictions still apply.
Representation transparency
An ordinary Vec3 parameter means the same thing whether its value comes from storage or from a computation carried across the call boundary.
pure fun lengthSquared(v: Vec3): Float {
return v.x * v.x +
v.y * v.y +
v.z * v.z
}
lengthSquared(a + b)With suitable pure component arithmetic, an implementation can combine the addition with the calculation without constructing a complete intermediate vector. It must preserve the required numerical results, effects, and other observable behavior.
This representation choice does not make ordinary values lazy. Explicit runtime deferral uses defer T, a separate part of the design.
Continue with the draft.
Find precise definitions, evaluation rules, and more examples in the working draft. Questions that still need a design decision, including ownership, capture, and transition validity, are marked Pending.