From: Topher Cooper (topher_at_[hidden])
Date: 2004-05-27 18:02:25
I recently joined Boost, and have been getting up to speed by following
the various discussions. I realize that this, my first contribution,
is a bit abstract, but I hope that it may provide some helpful
perspective on the constructor/destructor vs entry/exit discussion.
A common temptation in coding is to "take advantage" of some detail of
the way some mechanism happens to work, while completely ignoring the
intended meaning. The result is clever, frequently efficient, but
obscure, difficult to understand (except for the original implementor)
and inflexible. Occasionally their use with sufficient commenting is
justified, but more often it is a mistake. (Back in prehistoric times,
when I first joined the field, such tricks were called "hacks" and
programmers with a propensity to use them were called, pejoratively,
"hackers" -- but the meaning of that term has mutated three or four
times since then).
My first reaction (do note, before any hackles are raised, that I did
say my *first* reaction) when reading this thread (without having read
the material that it refers to) was that this appeared to be a classic
example of this programming error. The argument certainly seemed to
show all the ear-marks. A particular mechanism (C++
constructor/destructor behavior) having been identified as being
*analogous* to a desired behavior (entry/exit actions in an fsm), was
then strictly identified with the same, and used to implement it.
Questions as to the details of the way this worked, appeared to be
defended as necessary: the tail wagging the horse, i.e., the
implementation technique justifying the design rather than vice versa.
A number of postings seem to indicate to me that others have had a
On further thought, though, I have come to realize that this is not
really justified. The design error appears to be (remember, this is
based solely on the thread not the design itself) a much less serious
one -- an error in identification of the abstractions.
The problem, as I see it, is that what is being referred to as a finite
state machine "state" is not that at all. A "state" is a rather
static, declarative entity. Creating the "state" during execution and
then associating entry and exit actions with its construction and
destruction seems arbitrary and less than obvious -- especially when
that starts to drive the design rather than being simply a mostly
hidden detail of the implementation. In actuality, though, the objects
being referred to as "states" are, in fact a kind of process-object
corresponding to (the process of) *state activation*. What would more
traditionally be thought of as a "state" of the finite state machine
actually appears to correspond most closely to the class of the
corresponding "state activation" object.
With this in mind, identifying entry and exit of the state (beginning
and ending of the state activation) with the constructor and destructor
of the object is quite natural, and having entry/exit conform to the
specific semantics/restriction of C++ constructors/destructors is then,
quite reasonably, making the library C++ like in behavior.
Furthermore, it clarifies (to me) the static/dynamic fsm library
distinction. In a static library (like this one), the basically
declarative "states" are represented declaratively as classes. In the
absence of reflection mechanisms, the states are not actually
represented at run time at all. On the other hand, in a dynamic
library, the states are represented by some appropriate data structure
and the state activation would most likely correspond to execution of
appropriate methods specialized by delegation.
This doesn't mean, of course, that this was the best design (I still
haven't read the design, so I couldn't say), but it is certainly --
except for the terminological confusion -- a reasonable approach.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk