In my job I get to look at lots of Ada, written in many styles across
a variety of large programs. Despite this diversity, I have noticed
the following common pattern that is consistently implemented using
a risky Ada construct. Please excuse this rather long email; but I'm
hoping this prestigious group can offer some enlightening comments.

The common pattern is "publish and subscribe", which is not surprising
in the event-driven systems that I see. Typically, there is a package
whose job it is to maintain some state with respect to some sequence
of incoming events. Other parts of the application that need to know
about the state-changes can "subscribe" to the event handler; when a
state-change occurs, the handler will "publish" the fact to all the
current subscribers.

The normal implementation of this is to encapsulate the code that
needs to know about the state-changes into a "callback" procedure,
and then subscribe to the event handler by giving it a pointer to that
procedure. The event handler adds the pointer to a list, and later
publishes events by calling each procedure on the list. So far, so
good. In fact, this implementation matches those described in public
literature (in Ada books as well as books about patterns), and even
the Ada95 Rationale advocates such an approach.

However, large real-world systems are not as static as this: they
usually include requirements for dynamic reconfiguration. The "publish
and subscribe" pattern can support this quite well: all that is needed
is capability to edit the callback list. The "subscribe" operation
-adds- to the list; and an "unsubscribe" operation can be provided to
-remove- from the list. For generality, we can even provide a boolean
query such as "is_subscribed" to assure, for example, that a subscriber
doesn't add itself more than once. These latter two operations are
-not- described anywhere that I have seen -- but the implementation
is intuitive enough: simply traverse the list looking for a matching
pointer, and if found, act accordingly.

But that's where the risky Ada construct comes in: Ada95 does not
guarantee comparisons of subprogram 'Access values. As explained
in [RM 3.10.2(39)], [RM 4.5.2(13)], and other places, a compiler
"implementation may consider two access-to-subprogram values to be
unequal, even though they designate the same subprogram. This might
be because one points directly to the subprogram, while the other
points to a special prologue that performs an Elaboration_Check and
then jumps to the subprogram." Thus, each 'Access attribute reference
for a given subprogram is allowed to designate a distinct wrapper if
needed, to support an indirect call.

So: given this context, please comment on the following, preferably
-not- at the level of detail I'm providing. What I'm looking for is
overall conceptual insights: forest-level wisdom derived from the
tree-level observations I'm describing.

1) Alternative Implementations
Invariably, when I point out the above issue to developers, they
react with surprise. It is not common knowledge that Ada95 lacks this
guarantee, and the bugs it can manifest are elusive, since dynamic
reconfiguration is typically a massive operation (akin to startup) with
a combinatorial explosion that consequently sees little testing. So
it's quite disappointing that the above straightforward implementation
cannot be retained; yet all the alternatives I've seen are more complex
and/or cumbersome. Some examples include:

a) single 'Access: The "proper" thing to do is a technical tweak, as
described at <>
Define a single 'Access constant along with each callback subprogram
declaration, and use that constant for all references. This isn't a
bad solution, but it presumes the subscribers know how the publisher
is implemented (or will evolve). Maybe such a rule should be added to
program coding standards -- as a cliche.

b) use 'Address: The System.Address of the callback could be used
instead of its 'Access value. This would require a system service for
performing the call (usually provided by the OS), but it defeats the
type checking that 'Access enjoys. And besides, it's not clear that
'Address has any more guarantee for matching than 'Access does.

c) subscriber id: This approach assigns a unique identifier to each
subscriber and uses that instead of the 'Access value for matching
in the callback list. This adds complexity and maintenance concerns,
and resists the introduction of a new subscriber into the system
-- although I've heard it argued that that is a -good- thing: only
"authorized" subscribers will be able to subscribe, by virtue of having
been assigned an id.

d) sockets: A variation of this is that every possible subscriber is
allocated a "socket" and the socket table replaces the callback list:
no search (involving a match) is needed, since each subscriber has its
own socket. The table is statically maximal, the equivalent of every
subscriber having been added at system startup. Dynamic reconfiguration
is achieved via a boolean flag in each socket, indicating whether a
given subscriber participates in the current configuration (ie, whether
or not the event handler should call that subscriber's callback). This
may be efficient but can consume a great deal of memory, much of it
wasted on non-configured subscribers.

e) dispatching: This is a more sophisticated approach, wherein the
callbacks are mediated via tagged type dispatching rather than by
'Access subprogram values.

...and there are certainly other designs. But the point I'm making
is that there seems to be no equivalent for the simplicity of the
original implementation, which alas, Ada95 precludes. And worse, we
are misled by the public literature, which encourages us to -expect-
that the original implementation is advised.

2) Language Revision
This issue naturally leads to the question: can the next language
revision for Ada provide the missing guarantee, assuring a match
in comparisons of subprogram access values that designate the same

C. Daniel Cooper ==========v=======================.
Adv Computing Technologist | All opinions are mine |
206-655-3519               | and may not represent |
[log in to unmask]  | those of my employer. |
The question is not "What is the answer?"; rather, |
the question is "What is the question?" --Poincare |