I am trying to understand how the UML specifies templates. In general, templates whose parameters are not bound to concrete types are represented in most programming languages with a notation including placeholder strings, i.e. the T
, K
or V
in List<T>
or Map<K,V>
.
Formal TemplateParameter
s expose one or more ParameterableElement
s and are owned by their TemplateSignature
. But I cannot see any attributes for ParameterableElement
which would enable a modeler to store the placeholder names she might define when modeling a new template. Instead of List<T>
, it could be named List<NodeType>
or maybe List<MyStrangeAndWonderfulThing>
...
In order to do this, it seems that there should be a name
attribute (or operation) in the abstract interface either of TemplateParameter
or ParameterableElement
which could be accessed by TemplateSignature
. But Both TemplateParameter
and ParameterableElement
inherit directly from Element
which has no such interface.
Under section 7.3.4 Notation on p. 68 of the UML 2.5.1 specification, it says this about the template signature:
The formal TemplateParameter list may be shown as a comma-separated list, or it may be one
formal TemplateParameter per line. The general notation for a TemplateParameter is a string
displayed within the TemplateParameter list for the template:
<template-parameter> ::= <template-param-name> [‘:’ <parameter-kind> ] [‘=’ <default>]
where <parameter-kind> is the name of the metaclass for the exposed element.
The syntax of <template-param-name> and <default> depend on the kind of ParameteredElement
for this TemplateParameter.
The last sentence in that paragraph is worth re-reading.
IOW, must a conforming C++ implementations of UML first perform an ugly dynamic_cast
on the pointer or reference to ParameteredElement
in order to fetch the placeholder name? The point is, we don't know what type to cast to yet if the template is not bound to a concrete type. And when we do create a binding, we need to know which name (especially since the same placeholder can be used more than once).
Perhaps this is related to this UML issue raised by Ed Willink back in 2017? https://issues.omg.org/issues/UMLR-741
I am answering my own question because I have found the answer in the meantime: Yes, downcasting from ParameterableElement
to NamedElement
is apparently necessary (see my last comment above). The placeholder string is queried from the NamedElement::name()
function. Fortunately, all concrete classes of ParameterableElement
also derive from NamedElement
, so this will work.
Whether or not this is a good OOP design is another story. There might be good reasons for ParameterableElement
not to inherit from NamedElement
, but this is the current state of the UML.
(EDIT: Copying and pasting the comment into this answer as suggested above:)
Well, looks like this is more or less what the OCL constraint on page 100 does (OCL equivalent of a dynamic_cast to NamedElement): 7.8.19.6 Constraints (...) unique_parameters The names of the parameters of a TemplateSignature are unique. inv: parameter->forAll( p1, p2 | (p1 <> p2 and p1.parameteredElement.oclIsKindOf(NamedElement) and p2.parameteredElement.oclIsKindOf(NamedElement) ) implies p1.parameteredElement.oclAsType(NamedElement).name <> p2.parameteredElement.oclAsType(NamedElement).name)