Osy#betaRun it on Osyrin: osyrin.com

Reference / Workflow

on — a route and its arms

on Event(params) { when (guard) { …; goto X; } default { …; goto Y; } }

An `on` route is what a state does when an event arrives: a flat body, or guarded `when` arms tried top to bottom with a `default`. Inside an arm, a nested `when (…) { …; goto X; }` is a branch out of the state.

stable1 example compiled by CIworkflowauthoring

Summary#

on <Event> { … } inside a state says what happens when that event arrives there. Its body is either one flat body or a list of ARMS: when (guard) { … } arms, tried top to bottom, and an optional default { … }. An arm usually ends in goto <State>;. Inside an arm, a when (…) { …; goto X; } may NEST — a branch out of the state.

Signature#

on Event { …; goto Next; }                         // a flat body: one implicit default arm

on Event(Decision d) {
  when (d == Decision.Reject) { goto Rejected; }   // arms are tried top to bottom
  default {
    when (this.Item.Urgent) { Page(); goto Urgent; }   // a NESTED when must end in goto
    goto Approved;
  }
}

Description#

Arms#

The arms of a route are its top level. The first when whose guard holds runs; if none does, default runs; if there is no default, the event changes nothing. An arm's goto is where the run goes next — an arm without one stays in the state, which is how a route records something and keeps waiting.

A when nested inside an arm#

Inside an arm, when (guard) { …; goto X; } is a branch OUT of the state: if the guard holds, its body runs and the run goes to X; otherwise the arm carries on. It is exactly if (guard) { …; goto X; }, and that is how an exported app spells it.

It must end in goto. A nested when that stays in the state would read as one more arm to pick from, and it is not one — the rest of the enclosing arm runs after it — so it is refused, and the message names both ways to write what you meant:

  • a branch that leaves the state: end it with goto <State>;;
  • a step that stays: write if (…) { … }.

A when outside any on route (in an enter { }, in a function) is not an arm at all; write if.

Why nest at all#

Without it, "urgent work goes to the urgent state, everything else to the queue — but both are accepted first" has to be two top-level arms that repeat the shared part:

on Accept {
  when (this.Item.Urgent) { Stamp(); goto Urgent; }
  default { Stamp(); goto Queued; }
}

Examples#

A whole app, compiled: an urgent job leaves for Urgent from inside the default arm, every other one for Done.

using Osysharp.Workflow;

enum JobStage { Open, Urgent, Done }

entity Job {
  [Required, MaxLength(100)] string Title;
  bool Urgent;
  [MaxLength(100)] string Note = "";
  JobStage Stage;
  security { allow read, create, update when IsAuthenticated || IsAnonymous; }
}

workflow JobFlow {
  Tracks    = Job.Stage;
  Autostart = true;
  Initial   = Open;

  event Go();

  state Open {
    on Go {
      default {
        when (this.Item.Urgent) { this.Item.Note = "paged"; goto Urgent; }
        goto Done;
      }
    }
  }
  state Urgent {
    on Go { goto Done; }   // paged — the next Go closes it
  }
  terminal success Done { }
}

void Start(Job j) { JobFlow.RaiseGo(j); }

See also#

Related

Raising a workflow event

Raise a typed event on the run bound to an entity, from anywhere — an ordinary server function, a webhook handler, a…

subscribe

Declares that a workflow state waits on an event, and configures the wait — who may hold it, who may hand it on…

Transitions — where this item may go next

One row per move this instance can make right now, with each arm's guard evaluated against it. A board offers only the…

enter and exit (a state's arrival and departure hooks)

Run code when a run arrives in a state, and when it leaves. enter may redirect the run somewhere else; exit may not…