Skip to content

Assigner

Leon Starr edited this page Jul 26, 2026 · 4 revisions

The / Shaft indicates that there is only competition among instances in the same Shaft. This is called a multiple assigner since competition is resolved in partially ordered sets. If competition is global, we call it a single assigner and no class is specified as indicated in the grammar.

Everything after that line — the Events section, the Initial transitions and the state blocks — is written the same way regardless of which kind you picked. The parser reports the choice back to you in the lifecycle and assigner_rnum / assigner_pclass fields of the StateModel_a named tuple. Exactly one of those will be filled in.

When do I need an assigner?

When two or more instances can compete for the same instance across a relationship, and somebody has to decide who gets it. In the elevator case study, several floors may want the same elevator cabin at once. No single Accessible Shaft Level instance can decide fairly on its own, so the competition is resolved by an assigner on R53, the relationship that links a Cabin to the Accessible Shaft Level it is currently heading toward, formalized by the associative class Transfer.

If there is no competition to resolve, you don't need an assigner. Most state models are lifecycles.

See Lifecycle and Assigner for the details of each line, and the Shlaer-Mellor modeling resources if you want the underlying theory. An assigner state model arbitrates competition for instances across a relationship. Rather than belonging to any one instance, it belongs to the relationship itself. See Lifecycle vs Assigner for when you need one.

The declaration line looks like this:

relationship R53 / Shaft

And the grammar is:

assigner = "relationship" SP rnum SP '/' SP name? EOL*
rnum = r'O?R[1-9][0-9]*' // Relationship number

Reading it left to right: the keyword relationship, one space, the relationship number, one space, a slash, one space, and then an optional partitioning class name.

Single vs multiple assigners

That optional name at the end is what distinguishes the two flavors of assigner.

A single assigner has one state machine refereeing the entire relationship for the whole domain. Leave the name off:

relationship R23 / ⎵

⚠️ That is not part of the syntax — it's standing in for a character you can't see. The grammar asks for a space on both sides of the slash (SP '/' SP name?), and only the trailing name is optional. So a single assigner line really does end with a space after the /, and if your editor trims trailing whitespace on save the file will stop parsing with Expected SP. Yes, this is a wart.

A multiple assigner partitions the competition, giving you one independent state machine per instance of some partitioning class. Name that class after the slash:

relationship R53 / Shaft

Here the competition for a Cabin is resolved separately within each Shaft, since the floors served by one shaft never compete for a cabin running in a different shaft. That's a far more scalable arrangement than one referee for the whole building, and it's the usual reason to reach for a partitioning class.

What the parser gives you

The relationship number lands in the assigner_rnum field of the StateModel_a named tuple and the partitioning class, if any, in assigner_pclass. For the R53 example above you get assigner_rnum='R53' and assigner_pclass='Shaft'. A single assigner leaves assigner_pclass set to None. Either way the lifecycle field is None.

In context

From the R53 assigner, with the metadata omitted:

domain Elevator Management
relationship R53 / Shaft
events
    Service requested
    No destination
    Transfer created
    Transfer completed
    Dest change evaluated
--
state NO TRANSFER
activity
    // Waiting for service request
transitions
    Service requested > Search for new destination
--

Apart from that second line, this is written exactly like a Lifecycle.

Clone this wiki locally