Every publish-subscribe interface I have ever seen in OO languages used
polymorphism. Function pointers are used in languages that don't
directly support polymorphism. IMHO, the only thing access to
subprograms is good for is interfacing to C (or other low-level) code;
dispatching handles this type of stuff more cleanly. For instance, you
can carry data in the dispatching object, which is quite handy in most
instances.
-Corey
C. Daniel Cooper wrote:
>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 <http://www.adaic.org/docs/95style/html/sec_7/7-3-2.html>
>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
>subprogram?
>
>
>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 |
>==================================================='
>
>