« Updated Poly Subsystem | Main | Collaboration Diagrams »
Sunday
Mar112012

Testing Polymorphism

A conversation with Andrew Mangogna revealed that he and I had two different, and conflicting interpretations of how polymorphic events are supposed to be delegated on a compound generalization (multiple specializations from the same class as illustrated).  Unfortunately, the Mellor-Balcer Executable UML book, specifically rule 6, p228 is ambiguous:

6. If a superclass has multiple specializations, the polymorphic signal occurrence is received by at most one state machine instance in each specialization hierarchy.

The question being:  Must an Event Specification declared as polymorphic on a Class be delegated down (1) ALL Generalizations rooted in that Class or (2) AT LEAST ONE.  Both cases satisfy rule 6.  In either case, a run-time event is guaranteed to be processed by at least one Subclass instance.  In a given Generalization, again, in either case, each Subclass must define an Event Response for the delegated Event Specification unless there deeper delegation is specified (thorugh another level of Generalization).

Until we get this resolved (meeting with Stephen Mellor here in SF in a couple of weeks), the API will assume case (2) as it is the least restrictive and can be readily extended to case (1) if necessary.

References (38)

References allow you to track sources for this article, as well as articles that were written in response to this article.
  • Response
    For this article. I think the authors write very well. Content lively and interesting. Details are as follows:http://www.weissenburg.de/longchamp.asp
  • Response
    855 You'll need 9 dark strips and eight white strips with the weave. The only consistent that continues to be inside our children's lives, year in, year out, louis vuitton business would seem to generally be their more or less phobic distaste for strolling.
  • Response
    Response: castle clash hack
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    Response: this contact form
    miUML - News - Testing Polymorphism
  • Response
    Response: website
    miUML - News - Testing Polymorphism
  • Response
    Response: click here
    miUML - News - Testing Polymorphism
  • Response
    Response: website
    miUML - News - Testing Polymorphism
  • Response
    Response: blog
    miUML - News - Testing Polymorphism
  • Response
    Response: blog
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    Response: games.gun.uk.com
    miUML - News - Testing Polymorphism
  • Response
    Response: blog
    miUML - News - Testing Polymorphism
  • Response
    Response: emilysnyder.com
    miUML - News - Testing Polymorphism
  • Response
    Response: yahanet.org
    miUML - News - Testing Polymorphism
  • Response
    Response: web site
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    Response: blog
    miUML - News - Testing Polymorphism
  • Response
    Response: website
    miUML - News - Testing Polymorphism
  • Response
    And I HAVE read wordpress support page. Just want to know, if my files over 3GB will be deleted if I will not extend my upgrade for another 12 months..
  • Response
    miUML - News - Testing Polymorphism
  • Response
    Response: Markus Arambulo
    I found a great...
  • Response
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    Response: investing news
    miUML - News - Testing Polymorphism
  • Response
    Response: red bottom shoes
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    Response: curso revit
    miUML - News - Testing Polymorphism
  • Response
    Response: curso revit
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    Response: youth pastor
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    miUML - News - Testing Polymorphism
  • Response
    I found a great...

Reader Comments (26)

Doesn't rule three cover this case? What exactly is a "branch" in a super class's hierarchy?

March 14, 2012 | Registered CommenterDan George

As far as I can tell, no, rule 3 does not. To wit '3. The polymorphic signal must be able to be received in every branch in the superclass's hierarchy, so that the polymorphic signal occurrence always has a receiving state machine instance.'

Now, since 'hierarchy' is singular in rule 3, I take 'branch' to mean a path from a superclass to a subclass in a generalization. So a branch identifier could be: superclass_name + subclass_name + gen_rnum + domain_name

Let's also, for the sake of discussion, define the term 'subclass set' to mean the set of subclasses defined in a single generalization.

Rule 3 does not say 'every branch in each superclass's hierarchy' which would make case 1 decisive. Case 2 satisfies rule 3 by ensuring that at least one state machine handles an event occurrence. That is because, for at least one subclass set, an event response would be defined for each subclass. Thus, if a polymorphic event occurs, we know that at least one subclass will field it, satisfying Rule 3.

But it has been argued (and implemented in at least one existing tool) that every subclass set in a compound generalization must provide responses and as defined in case 1. As far as I can tell, MB supports Case 2 and nothing more.

As always, natural language is often (and almost always) ambiguous which executable models don't tolerate well. For pretty much every language decision in MB's Executable UML I can give you a solid reason 'why'. But in this particular case, I can argue 'why' for case 2, but not for case 1, though I would be open to hearing any solid reasoning that supports case 1 instead.

March 15, 2012 | Registered CommenterLeon Starr

It might be easier to think of it in terms of instances. An event is directed at an instance, therefore it can only be received in one state machine instance. There is only one state machine, no matter how often the specialization is repeated or how many specializations the superclass has. Even if there are multiple state models within a branch or across the multiple specializations that compose the instance, there is only one state machine (a composition of all the traversed models).
This is why arguments for polymorphism within an Executable UML domain are fairly specious; the target of the event is always a known instance (unambiguous modeling). The output of the model compiler, however, might need to use polymorphism for a more efficient implementation, so it might be a good pattern for the compiler to recognize.

March 15, 2012 | Registered CommenterLee Riemenschneider

@Lee: Are you suggesting that polymorphism, with regard to events, is not useful at all as a modeling concept?

March 15, 2012 | Registered CommenterLeon Starr

@Leon: IIRC, there were two big discussions on the subject in the SMUG mailing list and the Yahoo! Executable UML group. What I've always taken away the debate is that it is as useful (to the modeler) as the modeling tool decides to make it.

Generalizations represent a single instance at the modeler's level, therefore all events are already exposed to the modeler. The arguments for polymorphic events involve cases where:
1) The modeler would have to take unnecessary extra steps to access the set or subset of instances; and
2) Behavior can be enforced by the super class.

Argument 1 is clearly imposed by tool limitations, and argument 2 is substandard to more rigorous behavior validation. (i.e., it doesn't impose correct behavior, and therefore already has to be checked by other means.)

In the Checking Account / Savings Account example in the miUML Polymorphism Subsystem documentation, each state model in the subclass will have a close event, even without polymorphic events, and both events can be named "close". (Now if the behavior is the same, we could open the subject of split state models, but I don't think we want to go there. ;-) )

March 16, 2012 | Registered CommenterLee Riemenschneider

@Leon, Case 2 would allow a new hierarchy to be added to WarehouseClerk in which no subclass in the new set supports <<event>> goOffDuty. Given this new hierarchy added to WarehouseClerk, would the first action language example on page 229 become invalid? Would the corrected example have the like this:

select any luckyClerk from instances of WarehouseClerk[R27]
...

March 17, 2012 | Registered CommenterDan George

After re-reading the original question, I am missing the significance of the two cases. What does it mean to not delegate down a Generalization? Can you give an example where the decision makes some difference to the modeler?

March 17, 2012 | Registered CommenterDan George

@Lee Well, I'm not sure what the tool has to do with anything. (Especially since I don't have one anyway!)

But let's consider the bank account example as suggested. Say we have the Account object where Account.ID = A37. Just to be clear on terminology (from MB's book), A37 is a single 'object' manifested by multiple 'instances' in the Generalization hierarchy. Let's say A37 is a Regular Checking Account. Then we have object A37 appearing with three instances, in the Account, Checking and Regular Checking classes.

As you rightly point out, an Account has a lifecycle, period. But let's say that there is a whole bundle of interesting state behavior peculiar to Regular Checking Accounts. And perhaps some almost as interesting special behavior for Savings Accounts. As a modeler, again, the tool has nothing to do with it, I'm drawing on paper here, I've got a choice between drawing an unwieldy lifecycle all on the Account class or dividing it up. I choose to divide it up because it is easier to see what's going on with the specialized behavior factored out. Still, there is only one conceptual lifecycle, but it's been seperated out a bit for clarification. BTW, if the behavior was only subtly different in each of the two subclasses, I might want to emphasize the commonality with a single state model on the Account class. Either way, it seems to me this is a modeler's decision, with an eye toward creating the clearest specification, rather than having anything to do with the tools.

Now let's assume that we're going with the splintered lifecycle solution across Savings and Regular Checking. Now some other object wants to signal A37 to close. It seems to me that the key feature of polymorphism is that I can have that object simply generate signal A4:Close() to A37. Without polymorphism, it would be necessary for the sender to first resolve the subclassification of A37 and then generate either, say, S6: Close() or RC12: Close(). As a modeler, I want to specify the sender so that it doesn't care about the Account subclass so polymorphism offers a nice feature that clarifies the specification. So I believe that's why it is included in Shlaer-Mellor (and MB's Executable UML) and that's why we have it here in miUML.

March 19, 2012 | Registered CommenterLeon Starr

@Dan: If you've got your copy of MB handy, check page 102. (That will save us some drawing!) This is a compound generalization because, using miUML terminology, the Product class simultaneously plays more than one superclass role. In this case, one on R12 and the other on R11. Here is a case where the metamodel provides more precision than the book! So there is one class, Product, and two superclasses, Product-R11 and Product-R12 (or superclass roles, if you prefer).

Now let's define a polymorphic event P1*:Order on Product. Since it is polymorphic, we must delegate it. If this were a non-compound generalization, we would mean: delegate it down to the subclasses. But there are two generalizations to consider. We must delegate P1, otherwise it is not a polymorphic event. BTW, the term 'delegate' is not an MB term, I chose it in the process of metamodeling.

Now we can delegate P1* down R11, R12 or both. Let's consider each case.

As I responded (and agreed with) Lee, above, Product has only one conceptual lifecycle, even if we split it out into multiple subclass fragments for clarity. Let's say that the ordering process is quite different for In Stock Products and Special Order Products. Let's also say that the media (Book, Software, Recording) makes zero difference. I would expect then to delegate P1* down only R12. MB's rule 2 on p.228 says that the Product statechart (let's say one was constructed) may not respond to P1 (transition/ignore/can't happen). Rule 4 means that I must specify a response on BOTH In Stock Product and Special Order Product. We'll see why when considering what happens at run-time with specific instances.

Okay, the model has been specified and we are now running it in a simulator. There is one instance of Product, P33 and it happens to be a Special Order/Book Product. Some sender fires off the signal P1 addressed to P33. The sender has no idea how P33 is sub-classified. Through the magic of polymorphism, the instance of Special Order that is part of the overall P33 object, received the event and responds to it. Now some sender fires off a P1 signal addressed to P54 which happens to be an In Stock Product/ Recording Product. No problem, thanks to Rule 4 which mandated that the event be receivable by all subclasses. So the instance of In Stock Product corresponding to P54 gets the event and responds to it.

Okay, so the question is this: Is the above scenario good enough, or shall we mandate that P1* be delegated down both R11 and R12, irregardless of how we divided up the statecharts? In other words, if I define P1* as polymorphic, am I required to delegate down ALL generalizations?

Case 1 (from the original post) says yes, and Case 2 says no. But both cases require that delegation must occur through at least one generalization, otherwise, the event is not polymorphic.

As far as I can tell from the rules in p.228 of MB, Case 2 is adequate. But there is potential ambiguity, as is often the case in any natural language specification!

At this point I don't think either of us has made a persuasive argument and I am hoping that Steve Mellor can shed some insight when he's in town in the next week or so.

March 19, 2012 | Registered CommenterLeon Starr

@Leon - I think we need to clarify terminology further, because "Just to be clear on terminology (from MB's book), A37 is a single 'object' manifested by multiple 'instances' in the Generalization hierarchy." doesn't seem very clear. If you look at an Account as a set of objects, then an individual member is identified by "A37". Where are the "instances"? ???

The subclasses define subsets, so member A37 belongs to a specific subset of the Account set. Now if we say that behavior is defined per subset and A37 belongs to a subset with behavior, then any events targeted at A37 must be defined by the state model associated with A37's subset.

What I'm trying to say is that at the point that you've identified A37, you've already resolved the subset. Maybe it's unfair to blame the tool, if the metamodel the tool is based on doesn't model set membership resolution correctly.

Is broadcasting an event (i.e., no identifier needed) even allowed under Executable UML?

March 20, 2012 | Registered CommenterLee Riemenschneider

@Leon, Thanks for juggling Lee and me at the same time. At least we are both interested :).

I think "delegate down" is the thing that is hanging me up. A Product instance can have an In Stock or a Special Order part but not both. If the Product instance selected by the action statement in the sender happens to have either one, the right state machine will receive the event. Obviously, only the parts of Product that exists can receive the an event. I'm thinking that the part of Product that has the Product instance state machine will not even see the event; Product doesn't delegate, dispatch or anything. So, I'm stuck on what it means to "delegate."

March 20, 2012 | Registered CommenterDan George

@Lee

I do think the sense is captured in MB on page 98. It says: 'Definition: An object is an instance of a class, or an instance of several classes in a generalization-specialization hierarchy'.

So, using the earlier example, if a Product object comes into existence, it must instantiate three classes, and you therefore get three instances. But there is still only one real world object.

MB's definition is a bit vague, but it does communicate, to me at least, the key idea. Were I to reword it, I might say : "Each Object is fully manifested as either a single Instance of a Class which does not play any role in any Generalization or as a set of Instances spread across one or more connected Generalization Relationships." Better, but this is till too informal for my taste as 'connected' isn't defined and it misses various constraints captured in the miUML metamodel. For example, an Object in a single Generalization will be manifested by exactly two Instances, etc. That's why I just let the metamodel do the talking instead.

I realize that other definitions of 'instance' and 'object' are possible, but I think this one works well, especially when you use instance as a verb. This will be all the more apparent when the Population Subsystem is defined.

March 20, 2012 | Registered CommenterLeon Starr

@Dan

Ah, I see the confusion. You are trying, quite logically, but incorrectly, to apply the term in the runtime context. It's meaning is relevant only in the specification context. So when I am editing my model and Defining P1*, I am DELEGATING P1* such that responses must be defined in all subclass along one or more Generalizations. In other words, I am saying 'Hey, I've got this event P1 specified on the Product class, but we're not going to specify any response to it here. Instead, we will delegate the response definition to the subclasses. Does that help?

March 20, 2012 | Registered CommenterLeon Starr

I was looking for a consequence. By creating the concept of delegation, I think you are allowing the analyst to omit support for the event in all but one of the generalization hierarchies. That is, objects in the "omitting" hierarchy need not specify anything for P1 in their state models. I must have it wrong because it seems more likely to be done by mistake than on purpose, and frequently too.

March 20, 2012 | Registered CommenterDan George

Oh! For the simpler days of just objects and instances! I'm not sure I want to move away from there. Another reason to dislike UML. :-)

OK. Point taken. Now I just need to figure out if MB mean instance-based or object-based when they talk about state machines. The discussion on 225 & 227 seems to indicate the former, which rules out split lifecycles.

I like the set membership view better; it seems more "real world" and simpler. Maybe I should just go back to using the Shlaer-Mellor method. :-D

March 20, 2012 | Registered CommenterLee Riemenschneider

@ Lee

The set membership view is the RIGHT way to think about things! It's really just a terminology issue: instance = set membership, class = set definition. So with a single non-generalization class, instantiation = create a set element. With a generalization, object creation = multiple instantiation = create multiple set elements. Just two ways of describing the same thing. Of course, the set way of thinking is more natural when we have an action language built nicely upon relational algebra.

This set thinking is critical when you get to the action language. One nice thing about the stored procedure language I'm using for the API coding is that I get concise access to powerful set operations. Often I just do a set intersection, or take a set complement to reach some logical conclusion without having to do any !#(%$ looping. So I'm looking forward to defining an object-oriented action language with the full power of relational algebra exposed.

March 20, 2012 | Registered CommenterLeon Starr

@ Dan - You might be on to something there. You've got me digging up my old Shlaer-Mellor instructor notes and the Object-Lifecycles book. I think I see now why delegation must be forced down all directions all the time (Case 1).

BTW, I've NEVER built spliced statecharts across a compound generalization and would be reluctant to do so. There are certainly cases where you get simplification across a single generalization, which is probably why I've been drawn toward Case 2. When you do splice statecharts, you've got to be know what you're doing and not end up with an object that is effectively in two states at the same time. And there's the rub, as you are indicating. If we splice across TWO generalizations, it is very easy to break things.

I suspect that by forcing the modeler to specify a response a polymorphic event in all subclasses (on both generalizations) that either A) the modeler will see the folly of the compound generalization, state model splicing or both or B) define the responses such that there is proper coordination ensuring that an object is never in two states at the same time.

BTW, when I say two states at a time, I don't mean it literally. The nature of splicing forces you to be in two states at the same time (see the picture in Object Lifecycles). But, conceptually, one of those states is simply a 'wait' state representing the counterpart (super or subclass) splice.

Yeah, I'm not describing this well, but my point is that I think you've pointed me in the direction of a clear argument for Case 1. And also that 99.99% of the time you should never splice statecharts across a compound generalization. That said, the metamodel must handle 100% of legal cases which makes this metamodeling work all the more painful :P

March 20, 2012 | Registered CommenterLeon Starr

@Leon - "So with a single non-generalization class, instantiation = create a set element. With a generalization, object creation = multiple instantiation = create multiple set elements."

Shouldn't the second sentence read, "With a generalization, object creation = multiple instantiation = create a set element.", because you only get one set element. All the generalization does is partition the set into subsets, and an object represents a single member of the set.

March 21, 2012 | Registered CommenterLee Riemenschneider

@Leon - Which picture in Object Lifecycles are you referring to on spliced state models. I was looking at that section last night and thought the "splice" was indicated by events to/from nowhere. If we're thinking of the same picture, I'll have to look more closely. This could work as long as the tool would allow either A) an event to nowhere or B) external states. Either would satisfy a metamodel constraint on events between states. Enforcement/parsing would need to check that either case resulted in a completion of the transition within the same object.

March 21, 2012 | Registered CommenterLee Riemenschneider

Wow, I didn't think my comments about this to Leon would entail all this discussion. There are a lot of technical details to polymorphism and in its most general case can be mind baffling. I'll chime in on my view for what that is worth.

To me, the essential part of the question is what does it mean to have a superclass that is the root of multiple generalization hierarchies and which the problem semantics dictate has lifecycle behavior? I ask myself if it makes sense to have one generalization rooted off of a superclass respond to a polymorphic event and another not. Or is it possible to define several polymorphic events on such a superclass and have some go down one hierarchy and others down the other hierarchy? I keep coming back to the position that if you are partitioning the superclass set in multiple ways (presumably by multiple criteria) and the lifecycle behavior also partitions, then, at least to me, it seems that the lifecycle must also partition across all generalization hierarchies rooted at the superclass. If that is _not_ the semantics of the problem, I would contend that you have chosen the wrong construct to model those semantics. So, I interpret rule #6 to mean that any polymorphic event directed at a superclass is dispatched at run time to _all_ the generalization hierarchies for which it is a superclass. It then follows that the polymorphic event must then be consumed by exactly one instance somewhere along each generalization hierarchy.

Leon and I have gone round and round on this and I think we still disagree. Time for some "third party arbitration".

March 21, 2012 | Registered CommenterAndrew Mangogna

@Andrew, I do not get this: "... must then be consumed ... along each ..." Is it possible for an instance to be more than one kind of specialization of the same superclass? It seems like that is the only way it would be necessary for the event to be dispatched for each. But, isn't that what is shown in Fig. 6.17 to be improper? I just cannot figure out how there would be more than one state machine to receive an invent.

We might be in violent agreement but I, impractically, hate coming to the right conclusion for the wrong reasons.

March 21, 2012 | Registered CommenterDan George

@Dan -- this is hard to do in words.

Consider Fig 6.18 as an example of a superclass with multiple generalization hierarchies, namely R12 and R11. The rules of polymorphism as I interpret them are that a polymorphic event defined for Product must be able to be consumed by classes on both R11 and R12. So at run time, sending a polymorphic event to an instance of Product will result, in this particular example, in delivering an event to either InStockProduct or SpecialOrderProduct _AND_ to either BookProduct, RecordingProduct or SoftwareProduct (that's right, two events spring to life). This implies that there are state models for each of the five classes and that those state models have some means of handling the polymorphic event defined by the superclass, Product, as a local event on those state models. Of course, which instance of which class actually receives any event directed at an instance of Product depends upon the way the relationships are instanciated at the time of the event dispatch. So, "each generalization hierarchy" means both R11 and R12 in this particular case.

The general case is even a bit more complex as a hierarchy may have a depth greater than two and the mid-level classes may introduce their own polymorphic events. But even in the simpler case as this, the essential question for me is, "does defining lifecycle behavior on Product that is to be delegated to subclasses imply that the delegation apply across all generalization hierarchies (both R11 and R12 in this case)?" My contention is that it does and that if the ramifications of delegating the lifecycle among all the hierarchies does not correspond to the problem semantics then I suggest that the problem should be modeled another way.

March 21, 2012 | Registered CommenterAndrew Mangogna

@Lee p60 fig 3.10.4

March 21, 2012 | Registered CommenterLeon Starr

@Leon - OK. That's where I was looking, but I don't see an instance (I can use that term with respect to this book) being in two states at the same time or any mention of a wait state.

March 21, 2012 | Registered CommenterLee Riemenschneider

@Andrew - It reads to me in the MB book like you are interpreting rule #6 correctly. I would like to hear what reasoning led from a single instantiation of a generalization in Shlaer-Mellor to multiple instantiations in Executable UML. Maybe Steve will clear this all up.

March 21, 2012 | Registered CommenterLee Riemenschneider
Member Account Required
Welcome to miUML. We want your input, but to ward off evil spam, we request that you create a user account first.