State Oriented Programming
State Oriented Programming
Asher Sterkin
1 Introduction
well for a large number of potential states/transitions. The same happens when
an Object-Oriented solution for plain Final State Machines (FSMs) is proposed:
it is not scalable for a large number of states and thus is impractical to be used
unless the FSM is built automatically from some other formal description, as
usually happens with regular expressions and formal grammar [6].
Originally, Statecharts were associated with big money complex CAD tools
such as iLogic Rhapsody or IBM/Rational Rose Real-Time. As such, they were
disliked by many developers due to an excessive license cost and a special coding
style generated by these tools. However, the main problem with these tools
is probably not the license cost, since even free tools are not always popu-
lar. The problem is the huge gap between statechart diagrams and the code
generated from them. This does not occur with class diagrams where a close
correspondence between graphical and textual representation is easily recogniz-
able for most popular programming languages. Therefore, a new programming
paradigm, let’s call it State-Oriented Programming, is required in order to in-
troduce statecharts in mainstream software development. In order to make it
practical, the State-Oriented Programming paradigm should come as an exten-
sion of the established Object-Oriented Programming paradigm. More specifi-
cally, any prospective State-Oriented Programming language should come as a
Domain-Specific Language (DSL) [2] embedded directly in an Object-Oriented
programming language such as Java, Groovy, Ruby, etc.
The first time the idea of using the Statechart mechanism directly in a Gen-
eral Programming Language (GPL) was realized was in the Quantum Event
Processor (QEP) framework [9], which supports hierarchical states in C/C++.
Later, a Boost Statechart Library (BSL) with full UML 2.0 Statechart support
via C++ templates was developed as part of the Boost project [10]. The W3C
consortium issued an XML schema for Statechart specification, called SCXML
[11], and Apache Group developed a Commons SCXML library, which supports
SCXML interpretation in Java [12]. All this demonstrates a growing interest in
the use of Statecharts by software developers.
Still, the question of whether to support the Statechart programming paradigm
directly within modern Object Oriented Programming languages such as Java,
Groovy, Ruby, etc. remains open.
Perhaps the simplest possible statechart diagram consists of two states as pre-
sented in the diagram below.
This kind of behavior is very common for all devices with a toggle button:
TV, STB, Handheld computers, and mobile phones. Some GUI applications also
use this behavior extensively. The main reason for using toggles is the lack of
space: we would like to minimize the number of buttons and thus utilize the same
button for mutually exclusive operations. Which operation to invoke depends on
the current state: switch on if it’s off and vice versa.
The most straightforward implementation of toggle behavior would be to use
a single boolean variable reflecting the current state. For example:
This is not the whole story. Events are seldom processed via direct method
invocation and too often need to first be mapped from some string or integer
6
value. For this purpose, the Command design pattern [16] is usually applied as
follows:
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Method;
class State {}
The proposed alternative looks pretty close to the original statechart: each
state is represented by a separate anonymous class, and each event is represented
by a separate method. In principle, this is the same as it was in the previous
solution, but due to its terse form the Java code delivers the intent more directly.
Another crucial difference is that in that proposal, events are not implemented
in a polymorphic way, but rather are invoked through Java reflection.
The main problem with declaring all possible events in the base State class
is that the event/state matrix is usually very sparse: very seldom all events are
handled at all states. Declaring all possible events upfront in the base State class
could easily obscure the original statechart. It also eliminates a need for elab-
orated mapping between external event representation (e.g. String) and event
methods.
The proposed method will not work, however, if events are encoded in non-
string format, for example as numbers.
Another potential issue with this solution is that we will explicitly create
a separate State object for each context. While for simple UI applications it
is not a problem, it might be too wasteful for high-throughput communication
software. Conceptually, State is supposed to be stateless, e.g., not hold any data.
This is considered as an important “divide and concur” principle of the State
pattern: the context holds data and knows how to manipulate it, the state knows
when which operation has to be performed. This drawback could be overcome
by using Java enumerations as follows:
import java.lang.reflect.Method;
enum State {
INITIAL() {
void powerUp(final DeviceController4 ctx) {
ctx.switchOn(); ctx.setState(ON);
}
},
ON() {
void standBy(final DeviceController4 ctx) {
ctx.switchOff(); ctx.setState(OFF);
}
},
OFF() {
void standBy(final DeviceController4 ctx) {
ctx.switchOn(); ctx.setState(ON);
}
}
}
State state = State.INITIAL;
void setState(final State state) {
this.state = state;
}
}
import java.lang.reflect.Method;
9
enum State {
INITIAL() {
void init(final DeviceController5 ctx) {
ctx.setState(ON);
}
},
ON() {
void onEntry(final DeviceController5 ctx) {
ctx.switchOn();
}
void onExit(final DeviceController5 ctx) {
ctx.switchOff();
}
void standBy(final DeviceController5 ctx) {
ctx.setState(OFF);
}
},
OFF() {
void standBy(final DeviceController5 ctx) {
ctx.setState(ON);
}
};
void onEntry(final DeviceController5 ctx){/* nothing by default*/}
void onExit(final DeviceController5 ctx) {/* nothing by default*/}
}
State state = State.INITIAL;
The method proposed above will work pretty well for relatively simple stat-
echarts. However, it does not scale up when nested states need to be imple-
mented. For example, imagine that when the device (for example, digital TV
Set Top Box) is switched ON, it should process a special key “+”in order to
show on/off a banner with some useful information about the current TV Chan-
nel and program:
Even this simple nested statechart would enforce us to abandon onEntry and
onExit mechanisms in this implementation, thus reverting to substantial code
duplication.
import java.lang.reflect.Method;
We have again came up with a solution which is very verbose and looks too
far from the original statechart.
Although inheritance is the most natural way for implementing nested states
and indeed could be used for implementing simple models, it comes at odds
with onEntry, onExit mechanism, at least in programming languages which do
not have explicit destructors. These two onEntry()/onExit() functions cannot be
automatically inherited, but rather a decision which to invoke should be made
using the “Least Common Ancestor” [9] algorithm. Apparently, the Statechart
and Object-Oriented run-time models are not compatible: they have some fun-
damental differences.
Also, Java seems to be not very meta-programming [2] friendly and enforces
us to put quite a lot of extra code (called “noise”) in order to get even this
trivial model to work. Extracting even a simple framework from this code would
be almost impossible due to some Java security limitations.
It seems that the core problem is with suboptimal mapping between statecharts
and Java elements. Mapping states onto anonymous Java classes looks like a
useful idea. The same is with mapping special events such as onEntry and onExit
onto Java class methods. The problem seems to be with implementing nested
States via inheritance and implementing transitions as methods. Let’s see if we
could somehow change these two mappings (for nested states and transitions) in
order to get better solution.
One possible alternative is to use object composition for implementing nested
states and representing transitions as objects. Here is an implementation of the
previous Statechart using this new approach:
13
import org.gsl.java.*;
In the proposed method, the decision was made to give up on the event
lookup algorithm and to stick with a generalized guard() method. This guard()
method is internally invoked by framework for each transition in order to find
the first transition, which is enabled. Defining and supporting a general-purpose
Event class could unnecessarily complicate the framework without any significant
benefit. Surprisingly, it’s easier to store event information outside the statechart
framework and to rely on inner classes access to its content.
This approach was implemented in a form of Generic Statechart Library
(GSL), which supports all main UML Statechart constructs in a cost-effective
way: nested and parallel states, dynamic choices and actions. The first version of
GSL was implemented in Java as an initial proof-of-concept that State-Oriented
Programming is possible in principle.
However, many useful ideas needed to be rejected: annotations, reflection
and deeply nested classes as potential means to naturally reflect nested state
hierarchy. Neither of these options lead to a workable solution and after spend-
ing some time on experimenting, we were forced to give up. Apparently, Java
is quite resistant to advanced meta-programming. Something like the code frag-
ment presented below just will not work in Java:
In order to achieve this or an even higher level of code clarity, we shall turn
our attention to the next generation scripting languages: JRuby, Groovy, and
Scalla.
Even the most recent Java 6 lacks some ingredients crucially important for im-
plementing a fluent embedded Domain-Specific language like what we are trying
to achieve: closures, relaxed syntax, and advanced meta-programming. All these
features are supported out of the box in the next generation of Object-Oriented
Programming languages: Groovy[13], Ruby[14], Scala[15], etc. Sometimes these
languages are called dynamic, reflecting the fact that these languages are effec-
tively Object-Oriented scripts not too different in this regard from Perl, Tcl,
or Python. The difference is a cleaner syntax supporting both Object-Oriented
and functional programming and good integration with Java Virtual machine.
16
a digital TV Set- Top Box. It describes a very small subset of EPG function-
ality, yet it is still challenging enough to be implemented using a conventional
Object-Oriented method. The question is not whether it is possible to imple-
ment sophisticated GUI functionality just in plain Java or even ”C”. The fact
is that such applications are implemented. The question is rather how quickly
programmer will lose control over the application behavior due to unmanage-
able complexity. In our experience, lack of a proper statechart model directly
supported in a programming language is the number one reason for so many
UI inconsistencies and extra features: very soon it starts to get so complex that
nobody dares to make any changes except for fixing the most severe bugs or
introducing a completely new functionality such as support for the Personal
Video Recording (PVR) functionality. Usually after the change is made, it trig-
gers a new vicious circle of unmanageable complexity and the situation just gets
worse until somebody manages to convince upper management to rewrite the
application from scratch. This is hardly a sustainable business model.
epg.TestUI
Events isConfigured Actions?
start true switchOn
standBy n/a switchOff
standBy true switchOn
The basic StandBy behavior test is presented in Table 1. This particular test
scenario merely states that when a STB is configured, nothing specific happens
during power up (represented as a special ”start” event) except for switching
18
video on. It also states that video is switched off/on each time the ”standBy”
button is pressed.
epg.TestUI
Events isConfigured Actions?
start false switchOn, showSetup
standBy n/a hideSetup, switchOff
standBy false switchOn,showSetup
select n/a hideSetup, setConfigured
start true switchOn
package epg
import fit.ColumnFixture
TestUI()
{
controller = new UIController()
controller.switchOn = {actions << ’switchOn’}
controller.switchOff = {actions << ’switchOff’}
controller.showBanner = {actions << ’showBanner’}
controller.startTimer = {actions << ’startTimer’}
controller.stopTimer = {actions << ’stopTimer’}
controller.isTimeout = {guardMap[isTimeout]}
controller.hideBanner = {actions << ’hideBanner’}
19
controller.isConfigured = {guardMap[isConfigured]}
controller.showSetup = {actions << ’showSetup’}
controller.hideSetup = {actions << ’hideSetup’}
controller.setConfigured = {actions << ’setConfigured’}
}
String[] Actions() {
return actions
}
void execute() {
actions = []
if(’start’==Event)
controller.start()
else
controller.handleEvent(Event)
}
}
Now we are ready to take a look at the source of our tiny Electronic Program
Guide UIControler:
package epg
import org.gsl.groovy.*
on(’standBy’).to(’OFF’)
initial choice {
20
guard(isConfigured).to(’CLEAR_VIDEO’)
to(’CONFIGURE’)
}
state(’CLEAR_VIDEO’) {
on(’help’).to(’BANNER_ON’)
}
state(’BANNER_ON’) {
onEntry startTimer, showBanner
onExit stopTimer , hideBanner
on(’help’).to(’CLEAR_VIDEO’)
on(’tick’).guard(isTimeout).to(’CLEAR_VIDEO’)
}
state(’CONFIGURE’) {
onEntry showSetup
onExit hideSetup
on(’select’).action(setConfigured).to(’CLEAR_VIDEO’)
}
}
state(’OFF’) {
on(’standBy’).to(’ON’)
}
}
The script is fairly simple, is much shorter than than any alternative encoded
in plain Java, and, most importantly, is very close to the original statechart. This
script demonstrates all major GLS elements: state machine, states including
nested, initial and dynamic choice pseudo-states, transitions, guards, actions
onEntry and onExit, special handlers.
Each element is described in more detail in the following subsections.
21
void define() {
state(’state label goes here’) {
//state specification goes here
}
}
void define() {
state state-label {
//state specification goes here
}
}
In GSL, the initial pseudo-state[8] is specified as an inital prefix for some state.
In accordance with the UML specification, there should be only one initial state-
ment for each composite state, including the state machine itself:
void define() {
initial state(’state1’) { //initial state for the state machine
initial state(’sub-state2’) { //initial sub-state for state1
//sub-state specification goes here
}
//state specification goes here
}
}
All this might look like magic to those who are unfamiliar with modern
scripting language meta-programming capabilities. For those who are familiar,
there is nothing magical here: initial is a function taking a reference to state
object as an argument. Parenthesis could be omitted due to the Groovy relaxed
syntax convention, which makes this definition more readable and similar to
elements of the host programming language itself.
23
state(’state1’) {
oEntry namedClosure, {/*in-place closure*/}, //more closures
//the rest of state specification goes here
}
In GSL, all actions in transitions, onEntry, and onExit handlers are defined
using Groovy closures[13]: tiny anonymous classes which have full access to the
enclosing class (e.g., the controller) internals and encapsulating a particular func-
tionality (see the EPG example above and Calculator example below).
state(’state1’) {
on(’trigger’).guard(guardClosure)
.action(actionClosure).to(’target1’)
}
As with onEntry and onExit handlers, the transition specification could use
named or in-place closure for actions and guards. Following the UML 2.0 specifi-
cation[8], the main actions are supposed to perform some modifications in Model
or View, while guards are supposed to validate some conditions (normally in
Model).
action(’label’) {
action(actionClosure).to(’target2’)
}
In the previous section, we described all basic GSL features: state machine, state,
initial pseudo-state, onEntry, onExit, transitions, actions and guards. In order
to illustrate more advanced features, we will use a more complex example - a
basic calculator originally used in[9] (see Fig.6).
This statechart, though non-trivial but much simpler than its original version
presented in [9], illustrates the point that statecharts, as a visual tool, still have
a scalability challenge: almost any real-life application would lead to a diagram
which would be hard to manage. Having an adequate and formal textual repre-
sentation turns out to be a practical necessity and GSL was especially designed
to address this need.
The corresponding Groovy script is presented below:
package calculator
import org.gsl.groovy.StateMachine
class UIController extends StateMachine {
void define() {
initial state(’CALC’) {
on(’C’).to(’CALC’)
initial state(’FIRST_OPERAND’) {
onEntry eraseOperands
25
on(’+’,’-’,’*’,’/’)
.action(storeOperand,setOperation).to(’SECOND_OPERAND’)
on(’=’).action(storeOperand).to(’OPERATION’)
initial state(’OPERAND’)
}
state(’SECOND_OPERAND’) {
on(’+’,’-’,’*’,’/’)
.action(storeOperand,calculate,setOperation).to(’SECOND_OPERAND’)
on(’=’).action(storeOperand,calculate).to(’OPERATION’)
initial state(’OPERAND’)
}
state(’OPERATION’) {
on(’+’,’-’,’*’,’/’).action(setOperation).to(’SECOND_OPERAND’)
on(’CE’).to(’FIRST_OPERAND’)
}
state(’OPERAND’) {
on(’CE’).to(’OPERAND’)
on(’.’).to(’REAL’)
initial state(’ZERO’) {
onEntry setZero
26
on(’1’..’9’).action(setFirstDigit).to(’NON_ZERO’)
initial state(’POSITIVE’) {
on(’-’).action(setNegative).to(’NEGATIVE’)
}
state(’NEGATIVE’) {}
}
state(’NON_ZERO’) {
on(’0’..’9’).action(addDigit)
initial state(’INTEGER’) {}
state(’REAL’) {
onEntry setReal
def parts
def operands
def ops = [
’+’:{a1,a2->a1+a2},
’-’:{a1,a2->a1-a2},
’*’:{a1,a2->a1*a2},
’/’:{a1,a2->a1/a2}
]
def operation
def current
String getResult() {
parts[0] + parts[1] + ’.’ + parts[2]
}
def setZero = {
parts = [’’,’0’,’’]
current = 1
}
def setNegative = { parts[0] = ’-’ }
def setFirstDigit = {String d ->
parts[1] = d
}
def addDigit = { String d ->
parts[current] += d
27
}
def setReal = {current = 2}
def eraseOperands = {operands = []}
def storeOperand = {
operands << getResult().toBigDecimal()
}
def setOperation = {String o-> operation = ops[o]}
def calculate = {
def BigDecimal a2 = operands.pop()
def BigDecimal a1 = operands.pop()
def BigDecimal res= operation(a1,a2)
operands << res
parseResult(res)
}
state(’stateLabel’) {
//range specification:
on(low..high).guard(guardClosure)
.action(actionClosure).to(’targetLabel’)
//list specification:
on(t1,t2,t3).guard(guardClosure)
.action(actionClosure).to(’targetLabel’)
//mixed specification:
on(low1..high1,t1,t2,low2..high2)
.guard(guardClosure).action(actionClosure).to(’targetLabel’)
1. Global namespace: all states need to have unique labels across the whole
state machine
2. Scoped namespace: each super-state has its own name space
problem with target specification in transitions since following the strict scoping
rule, we would need to put an outer state prefix for almost any transition. In
other words, rather than specify it using more intuitive and short form:
state(’state1’) {
on(trigger).to(’state2’)
...
}
state(’state2’) {
...
}
One would need to use a more verbose, although more formally correct, form:
state(’state1’) {
on(trigger).to(’outerState.state2’)
...
}
state(’state2’) {
...
}
After spending some time on evaluating the both options we decided to adopt
for GSL the global state namespacing schema since the scoped namespaceing,
even though it is more formally correct, might introduce too much confusion.
Whether the global namespaceing schema is better than the scoped names-
pacing is too early to tell. Only after gaining some practical experience, a final
decision regarding state labels namespacing could be made.
state(’stateA’) {
initial state(’C’) \\state A will use an extern state C
}
state(’stateB’) {
initial state(’C’) \\state B will use an extern state C
}
state(’stateC’) { \\state C will be used by A and B
...
}
Some UML 2.0 statechart elements which have yet to be implemented by GSL
are planned for the next version:
1. Final Pseudo-state
31
5 Concluding Remarks
completion, syntax coloring and statechart refactoring. The latter is a very in-
teresting topic by itself. These productivity tools would allow supporting the
State-Oriented Programming as a first class citizen paradigm. Once they are in
place, only the sky is the limit.
References
1. M. Fowler, Patterns of Enterprise Application Architecture, Adisson-Wesley, 2002
2. M. Fowler, Domain Specific Languages book, work in progress, available at
http://www.martinfowler.com/dslwip/
3. J. Huges, Why Functional Programming Matters, Chalmers memo, 1984, available
at http://http://www.cs.chalmers.se/ rjmh/Papers/whyfp.html
4. J. Armstrong, Programming Erlang: Software for a Concurrent World, Pragmatic
Bookshelf, 2007
5. F. Buschmann et al, Pattern-Oriented Software Architecture Volume 4: A Pattern
Language for Distributed Computing, Wiley, 2007
6. T. Parr, The Definitive ANTLR Reference: Building Domain-Specific Languages,
Pragmatic Bookshelf, 2007
7. D. Harel, Statecharts: A Visual Formalism for Complex Systems, Sci. Comput.
Program, 1987, vol. 8, 231-274
8. OMG Unified Modleling Language (OMG UML), Superstructure: V2.1.1, 2007
9. Miro Samek, Practical Statecharts in C/C++: Quantum Programming for Em-
bedded Systems, CMP Books, 2002
10. The Boost Statecharts Library, available at http://www.boost.org
11. State Chart XML (SCXML): State Machine Notation for Control Abstraction 1.0,
available at http://www.w3.org/TR/2005/WD-scxml-20050705/
12. Apache Commons SCXML, available at http://commons.apache.org/scxml/
13. D.Koening, et al, Groovy in Action, Manning Publications, 2007
14. D.Thomas, et al, Programming Ruby: The Pragmatic Programmers’ Guide, Second
Edition, Pragmatic Bookshelf, 2007
15. M. Odersky, et al, Programming in Scala, Aritma Developer, 2008
16. E. Gamma, et al, Design Patterns: Elements of Reusable Object-Oriented Software
, Addison-Wesley, 1994
17. M. Cohn, User Stories Applied: For Agile Software Development, Adisson-Wesly,
2004
18. R. Mugridge, W. Cunningham, Fit for Developing Software: Framework for Inte-
grated Tests, Prentice Hall PTR, 2005
19. G. Hohpe, B. Woolf, Enterprise Integration Patterns: Designing, Building, and
Deploying Messaging Solutions, Addison-Wesley , 2003
20. B. Stroustrup, The Design and Evolution of C++, Addison-Wesley, 1994