Membership

Login

ACCU Buttons

The Curate's Wobbly Desk

The Vicar's
Lodger

The story of the curate's egg is well known [story], but I bet you've never heard about the
curate's wobbly desk.

When Aubrey Jones was first ordained he was appointed curate to
St Michael's church, Belton Braces. It was a small parish serving
just a few quiet hamlets and there would have been nowhere for Mr.
Jones to stay if he had not been offered lodgings at the vicarage.
The vicar, the Reverend Cuthbert Montague-Smith, was a large and
imposing man with strong opinions on how to do God's bidding. The
timid Aubrey Jones found him rather... well, intimidating.

The bishop had suggested that Aubrey would benefit from studying
the early history of the Christian church and the vicar expressed a
hope that this research would turn up some interesting material for
the parish magazine. Eager to please, Aubrey went out and bought a
cheap, mass-produced, self-assembly desk to work at. The D.I.Y.
shop was running a special offer - free delivery - and the curate
felt he was getting a bargain.

Secret
Drawers

Reading through the assembly instructions Aubrey was delighted
to find that the desk contained a secret drawer. He had fond
notions of keeping a diary and one day, perhaps, writing a book on
the life of an English pastor based on his own ministry and
experiences. But he suspected that Cuthbert would regard such
activities as of little practical value and it would be better for
the vicar to remain ignorant of those particular jottings.

As chance would have it, the vicar's desk also had a secret
drawer. I don't know what Cuthbert kept in that drawer, or even if
he knew it was there. But I do know that both Aubrey's and
Cuthbert's secret drawers were operated by two catches. If you
press both catches at the same time the drawer slides out. I
remembered the vicar, the curate and the secret drawers when I was
working on the software for a computer game. (It would have been
called "Murder at the Vicarage", but Agatha Christie got there
first.) "Let's use that in the game", I thought, and wrote an
interface class representing the secret drawer based on classes
from my Event/Callback library [Bass]. Listing
1 shows the Event class template used for the drawer release
mechanism and the Callback::Function
class template used for the catches.

The Drawer class interface is shown
in Listing 2. The key feature here is that Digital_Input is an abstract base class with a
pure virtual function call operator. When catch A's Digital_Input callback is invoked the lock/unlock
state for catch A must be updated, the state of catch B must be
read and, if both catches are in the unlock position, the drawer
release mechanism must be activated by triggering the Digital_Output event. The overall effect is that
the Drawer class behaves like an And
gate in an electronic circuit.

In the game, a Drawer object is
created and GUI push-button widgets are attached to the drawer's
inputs (the catches). The drawer itself is represented by an
Image widget which shows either a closed
drawer or an open drawer. A callback that toggles between the open
and closed images is attached to the drawer's output (the drawer
release mechanism). The player has to find a way of pressing both
of the catches at the same time to open the drawer - not easy using
just a mouse. A rough sketch of the client code is shown in Listing
3.

The rest of this paper describes two ways of implementing the
Drawer class with the help of our curate, his vicar and their
furniture.

The Curate's
Self-Assembly Desk

As soon as he had a spare half-hour Aubrey Jones opened the box
containing his flat-pack desk, carefully laid out the panels,
runners, feet, dowels, nuts and bolts, and began to assemble them.
He paid particular attention to the secret drawer. The drawer
itself had a grain-effect finish that looked remarkably like real
wood, but probably wasn't. The release mechanism was an integral
part of the drawer, located at the back. The secret catches were
separate - metal, with knobs in the same fake wood as the drawer
and disguised as decorative features. The catches had to be
fastened to the front of the drawer and connected to the release
mechanism with two long, thin and worryingly flimsy metal rods.

The structure of my code was very similar, as you can see from
the overview in Listing 4 and the function bodies in Listing 5. The
drawer release mechanism was represented by Digital_Value and Digital_Output members of the Drawer class. The catches were separate classes
(Catch_A and Catch_B) and they were attached to the Drawer class by pointers. With this design the
functions in the public interface are trivial and shown here
defined within the class declaration.

This design is conceptually simple, but it didn't feel quite
right. Like cheap, mass-produced furniture it seemed inelegant and
unsatisfying. Did the Catch classes
really have to store a pointer to their parent object? After all,
the address of the Drawer object is a
fixed offset from each of the Catch
objects. Couldn't we just subtract that offset from the Catch object's this pointer and apply a suitable
cast?

After some thought I decided that pointer arithmetic and casting
would be worse than the disease I was trying to cure. A case of
premature optimisation, and an ugly one at that. I needed to think
like the master craftsmen of old. And that reminded me of the
vicar's desk.

The Vicar's
Antique Writing Table

Cuthbert Montague-Smith loved his big sturdy old desk. It was
reminiscent of the magnificent library writing table at Harewood
House, near Leeds [chippendale].
Cuthbert suspected it was built by Thomas Chippendale himself,
although he was unable to provide a shred of evidence to support
that view.

I don't suppose the great furniture maker would appreciate the
finer points of software design in C++, but I tried to imagine the
approach he would use. He would surely pay considerable attention
to detail and not rest until he had discovered a method that was
both elegant and practical.

With this in mind I thought again about the Drawer class implementation. The curate's desk
design in Listings 4 and 5 contains Catch classes that reference an external object
(the Drawer itself); that is why it
needs those inelegant pointers. If we could move the external data
into the Catch classes the pointers
would not be necessary. So the question is, how can we make the
Drawer state variables part of two
separate Catch objects?

It's no good putting member variables into the concrete
Catch classes because that would just
duplicate the data; and we can't put data into the Digital_Input class because that would compromise
the Event/Callback library. The only option is to put them in a
shared base class. The key to the desk is virtual
inheritance.[1] Listing 6 and Listing 7 show how I chose to
use this technique.

All the variables have been moved to the private nested class,
Data. As this is an implementation
detail of the Drawer class I have not
bothered to create separate interface and implementation sections
for Data. Purists can add a private
section and suitable access functions if they wish. It is
appropriate, however, to provide Data
with a constructor and a function that sets the drawer release
mechanism's state from the Catch values
to avoid duplicating these operations in both the Catch classes.

The Catch classes themselves use
virtual inheritance to "import" the shared Data object. They also provide a function that
updates their own lock/unlock state, calculates the drawer release
state and publishes the drawer release state to the client
code.

The Drawer class could inherit
directly from the Catch classes, but
that would mean exposing the Data class
and the concrete Catch classes to its
clients. Instead, I have chosen to write a nested Body class that completes the virtual inheritance
diamond and then store a Body member
within the Drawer class. That way, none
of the classes used in the Drawer
implementation pollute the namespaces used in the client code.

The Catch class member functions in
the vicar's desk design are slightly simpler than those in the
curate's version. Moving the data to a base class enables them to
access the variables directly instead of via those ugly and
unnecessary pointers. Initialisation of the data members is also
slightly simpler because there are no pointer values to set (which
means one less opportunity for a bug). And the sync() function is
the same in both designs. Chippendale would have been proud.

It All Falls
Apart

The curate struggled to assemble his desk. The instructions
seemed to have been translated from a foreign language (badly), the
diagrams didn't seem to match the parts he had and Aubrey Jones'
mind wasn't good at 3D visualisation. The release mechanism for the
secret drawer, in particular, baffled the poor man. Eventually, the
desk was completed and moved into position under the window of
Aubrey's bed sitting room where he could look out over the
garden.

The desk was always a bit wobbly and the secret drawer never did
work. (The connecting rods were not installed correctly, so the
drawer release would not activate.) Aubrey never quite found the
time to research the early history of the Christian church and with
no place to hide his private writings he soon lost the urge to keep
a diary. Indeed, after a few years as the vicar of a provincial
parish on the borders of London and Essex his ecclesiastical career
took a turn for the worse [genesis]. He may
yet write a book. If he does, it will be about temptation, greed
and the frailty of man, but sadly it will not be about a life of
service to the church.