State diagrams: support a `<<junction>>` pseudostate distinct from `<<choice>>`

0 votes
asked Sep 16 in Wanted features by dmf19 (420 points)

PlantUML state diagrams currently only expose <<choice>> (e.g. state c <<choice>>) for conditional branching. UML also defines a separate junction pseudostate, which PlantUML has no way to express - modeling a junction today means reusing <<choice>>, which doesn't capture the intended semantics.

Per the UML spec, the two are not interchangeable:

  • Choice is a dynamic conditional branch: guards are evaluated at run time and may depend on effects executed on the transition leading into the choice.
  • Junction is a static conditional branch: it merges multiple incoming transitions into a single compound transition, and its outgoing guards must be evaluated against state that existed before the compound transition began - no side effects from reaching the junction can influence the branch. This makes the whole path atomic: if no outgoing guard matches, the machine stays in its original state with nothing executed.

Junction also natively supports multiple incoming transitions merging into shared outgoing branches (fan-in + fan-out in one compound transition), which is a common pattern in things like retry/attempt-counter logic (e.g. an ATM PIN check where both "first attempt" and "retry" paths merge into one junction that then branches on attemptsRemaining).

Potential Solution

Add a new stereotype, e.g. <<junction>>, alongside the existing <<choice>>, <<fork>>, and <<join>>:

@startuml
state EnterPIN
state RetryPIN
state PromptRetry
state CardLocked
state j <<junction>>

EnterPIN --> j
RetryPIN --> j
j --> PromptRetry : [attemptsRemaining > 0]
j --> CardLocked : [attemptsRemaining == 0]
@enduml

Ideally rendered distinctly enough from <<choice>> (UML tools often draw junction as a filled circle/dot rather than a diamond) so the semantic difference is visible in the diagram, not just in the source.

Alternatives

Continuing to reuse <<choice>> for junction-style merges - works visually but is semantically incorrect and doesn't communicate the atomic/static-guard intent to readers of the diagram or to any tooling that might validate transition semantics.

Additional context

Relates to existing pseudostate support for <<choice>>, <<fork>>, and <<join>> in state diagrams.

2 Answers

0 votes
answered 2 hours ago by The-Lu (91,520 points)
 
Best answer

Hello D.,

Thanks for the report, and for your PR. (And Thanks to PlantUML Team)

That will be now fixed on next release and on last snapshot.

Ref. :

Regards,
Th.

0 votes
answered Sep 17 by The-Lum

Hello D.,

Perhaps, as a first step, we could make "junction" a synonym for "start"...

@startuml
state EnterPIN
state RetryPIN
state PromptRetry
state CardLocked
state j <<start>>

EnterPIN --> j
RetryPIN --> j
j --> PromptRetry : [attemptsRemaining > 0]
j --> CardLocked : [attemptsRemaining == 0]
@enduml

Regards,
Th.

commented 2 days ago by dmf19 (420 points)
edited 2 days ago by dmf19

Thanks for the suggestion.  Yes that would work.  I am compiling an MR...

https://github.com/plantuml/plantuml/pull/2905

...