UML is known to be a huge language, and that has two problems: it is too complex, having way more features than most applications will ever need, and can still be insufficient, as no single language will ever cover everybody’s needs.
In the article “Customizing UML: Which Technique is Right for You?”, James Bruck and Kenn Hussey (both from the UML2 team) do a great job at covering the several options for extending (or restricting) UML (James also made a related presentation at last year’s EclipseCon, together with Christian Damus, of Eclipse OCL fame). Cutting to the chase, these are the options they identify:
- using keywords (featherweight extensions)
- using profiles, stereotypes and properties/tagged values (lightweight extensions)
- extending the metamodel by specializing the existing metaclasses (middleweight extensions)
- using package merges to select the parts of UML you need (heavyweight extensions)
Each option has its own strengths and weaknesses, as you can see in the referred article/presentation. At this time, the TextUML notation supports two of those approaches: profiles and metamodel extensions.
Adding closures to UML
Even though profiles are the most popular (and recommended) mechanism for extending UML, it is not enough in some cases/applications. That has been the case in the TextUML Toolkit, for instance, when implementing closures in the TextUML action language (yes, the Toolkit eats its own dog food).
According to the wikipedia entry, “a closure is a function that is evaluated in an environment containing one or more bound variables. When called, the function can access these variables. ”
It really makes sense to (meta) model a closure as some kind of UML activity, which is basically a piece of behavior that can be fully specified in UML. Methods, for instance, are better modeled in UML as activities. Activities are composed of activity nodes and actions, which are similar to blocks of code and instructions, respectively.
The only thing that is missing in the standard Activity metaclass is the ability for a closure to have an activity node from another activity as context, so it can access context’s local variables. So here is a possible (meta) modeling of closures in UML using the TextUML syntax:
[Standard::Metamodel] model meta; apply Standard; (* A closure is a special kind of activity that has another activity's activity node as context. A closure might reference variables declared in the context activity node. *) [Standard::Metaclass] class Closure specializes uml::Activity (* The activity node that provides context to this closure. *) reference contextNode : uml::StructuredActivityNode; end; end.
Or, for those of you who prefer a class diagram (courtesy of the EclipseGraphviz integration):
Note a model contributing language extensions must be applied the Standard::Metamodel stereotype, and each metaclass must be assigned the stereotype Standard::Metaclass.
Of course, there is no point in being able to metamodel closures, if there is no way to refer to them. We need a kind of type that we can use to declare variables and parameters that can hold references to closures. That also means we need to be able to invoke/dereference a closure reference, and there is no support for referring to metamodel elements in the UML action language. That means we need more language extensions. But I will leave that to another post. My goal here was to show how simple it is to create a simple UML metamodel extension with the TextUML Toolkit.
What about you, have you ever needed to extend UML using a metamodel extension? What for?