Skip to main content
Version: 7.0

Brief: actions

State changes (<-, NEW, DELETE)

The CHANGE operator writes a value into a changeable property, the NEW operator adds an object of a concrete class, and the DELETE and CHANGECLASS operators delete an object or move it to another class:

[CHANGE] propertyId(expr1, ..., exprN) <- valueExpr [WHERE whereExpr]
NEW className WHERE whereExpr [TO propertyId(prm1, ..., prmN)]
NEW [alias =] className [AUTOSET] action
DELETE expr [WHERE whereExpr]
CHANGECLASS expr TO className [WHERE whereExpr]

A change is written for all argument sets satisfying the condition at once, as a single set operation. Analogy: UPDATE ... SET ... WHERE, not an assignment to a variable. On a class change or a deletion the platform clears the stored values of the data properties the object is no longer valid in.

setDiscount () {
discount(Customer c) <- 15 WHERE totalOrders(c) > 100;
NEW o = Order { date(o) <- currentDate(); }
}

Calls and sequencing

An action is dual to a property: a property says what the value is, an action says how it changes. It is declared by the ACTION statement:

name [caption] [(param1, ..., paramN)] { actionBody } [options]

The body in braces is a sequence: nested actions run in the order written; inside the block LOCAL properties can be declared that live only while the block runs. An action call is written as the name with arguments, [EXEC] actionId(expression1, ..., expressionN) [TO toProperty], or substituted directly as a value. Analogy: a procedure call.

Loops (FOR, WHILE)

The FOR operator runs its body once per object set for which the condition is not NULL; the WHILE operator recomputes the condition at every step, so the changes made by the body are taken into account:

FOR expression [ORDER [DESC] orderExpr1, ..., orderExprN]
[TOP topExpr] [OFFSET offsetExpr]
[NEW [alias =] className]
DO action
[ELSE alternativeAction]

WHILE expression [ORDER [DESC] orderExpr1, ..., orderExprN]
[NEW [alias =] className]
DO action

A loop is used when the body is genuinely row-by-row — a dialog, a message, an external call. The mechanisms are described in loop and recursive loop.

createDetails (Order o) {
FOR in(Sku s) NEW d = OrderDetail DO {
order(d) <- o;
sku(d) <- s;
}
}

Branching (CASE, IF)

Branching runs the action matching the condition that holds; a condition holds if its value is not NULL. In the IF ... THEN and CASE operators the condition is written out; in the MULTI operator it is that the call arguments match an action's signature, that is, dispatch by the argument class:

IF condition
THEN action
[ELSE alternativeAction]

CASE [exclusionType]
WHEN condition1 THEN action1
...
WHEN conditionN THEN actionN
[ELSE elseAction]

MULTI [exclusionType] action1, ..., actionN
message (Shape s) { MULTI { message[Square](s); }, { message[Circle](s); } }

The deferred variant is an abstract action, ABSTRACT: a base module declares the extension point and other modules add implementations to it (action extension).

Flow control

Form actions

  • SHOWopening a form in the interactive view; the passed objects become the current ones.
  • DIALOG — the same opening as a value-input dialog: every object marked INPUT or CHANGE returns its last current value to the DO block.
  • ACTIVATEactivation of a form, a tab, a property, or a set of objects in an object group.
  • EXPAND / COLLAPSE — expanding and collapsing a form container and the nodes of an object tree.
  • MESSAGE and INPUT — a message and a value input without a separate form.
ACTIVATE FORM formName
ACTIVATE TAB formName.componentSelector
ACTIVATE PROPERTY formPropertyId

ACTIVATE [seekDirection] formObjectId = expr
ACTIVATE [seekDirection] formGroupObjectId [OBJECTS formObject1 = expr1, ..., formObjectK = exprK]