Great! That clarifies the main question I had: whether we are going to support code generation for "partial" models.
Now, regarding your question about how I view "incomplete" or "partial" models, let me use the textual notation to describe what I have in mind.
In general, for me, an incomplete or partial model is what I call a "Swiss model", that is, a model with "holes" ;) Take this basic example:
model M
{
capsule A
{
port p : ?;
}
}
Here port A.p does not have a protocol assigned to it, so the interrogation mark is the hole. The hole can be filled out with a protocol name. Now, in general, it's preferable to use some identifier for holes, because there may be more than one:
model M
{
capsule A
{
port p : <P1>;
port q : <P2>;
}
}
But this is a bit subtle: <P1> and <P2> are not protocol names. They are meta-variables. They are entities at the meta-language level, which could be filled in later on. But this gets more interesting because there meta-variables do not necessarily stand for simple names in the target language, but they could stand for entire constructs. For example,
model M
{
capsule A
{
port p : <P1>;
port q : <P2>;
part <X>;
part <Y>;
}
}
where <X> and <Y> are meta-variables that could be filled in with something like "m:B" (part m of type B for a capsule B). The point of such declaration is to say "I want a part here, but I don't want to commit yet to a particular part name or capsule".
Furthermore, depending on what is encompassed by meta-variables, these could cover larger constructs or sets of constructs:
model M
{
capsule A
{
port p : <P1>;
port q : <P2>;
part <X>;
part <Y>;
<W>
}
}
Here <W> could be filled out later by
part m : B;
part n : C;
connect m.i to n.j;
Or it could even be filled out by something containing meta-variables:
part m : B;
part n : C;
<U>
connect m.i to n.j;
This "filling holes" would correspond to a certain form of refinement.
What's more, if one uses this approach to refinement, these meta-variables could even be assigned a "may/must" modality. If a meta-variable is marked as a "may" variable, it means that any refinement may fill it. With a "must" modality, any refinement must fill it. Alternatively the modality could be "must/must-not", where "must-not" would be used to explicitly forbid the addition of elements. But I digress.
Now, in general, such Swiss model would not yield an executable program as it would not have a well-defined semantics, but that doesn't necessarily mean that generating code from them would yield as useless artifact. A code generator could produce, for such a model, different kinds of artifacts, such as:
1) code with comments in places to be filled-out by a programmer
2) code with predetermined defaults
3) C++ templates
4) Xtend templates
For example, for this model
model M
{
capsule A
{
port p : <P1>;
port q : <P2>;
}
}
we could generate:
1) code with comments in places to be filled-out by a programmer
class Capsule_A : public UMLRTCapsule
{
protected:
/* P1 */::Base p;
/* P2 */::Base q;
// ...
};
2) code with predetermined defaults
class Capsule_A : public UMLRTCapsule
{
protected:
DefaultProtocol::Base p;
DefaultProtocol::Base q;
// ...
};
for some "default" protocol, e.g. a symmetric protocol with one inOut message.
3) C++ templates
template <class P1, class P2>
class Capsule_A : public UMLRTCapsule
{
protected:
P1::Base p;
P2::Base q;
// ...
};
4) Xtend templates
class Capsule_A_template
{
def generate( Protocol p1, Protocol p2 )
'''
class Capsule_A : public UMLRTCapsule
{
protected:
«p1.name»::Base p;
«p2.name»::Base q;
// ...
};
'''
}
The first two kinds would be useful mostly for illustration, allowing the modeller to understand "the code behind the scenes", much in the same way that when you program in Xtend, it is useful to see the generated Java code to understand what's really going on (which is one of the most attractive features of Xtend).
Types 1, 2 and 3 can also be directly modified by the developer, as some developers might prefer starting with an incomplete model, but finishing the implementation in the generated code. I see this approach as enabling rapid prototyping: you sketch the idea in the model, but do not provide all implementation details there. Rather, you generate an artifact like these from the incomplete model and finish the prototype implementation in the code itself. That might be particularly attractive to users who are not completely sold on modelling.
Type #2 looks silly at first, but it could actually be more powerful for supporting some forms of analysis. For example, a capsule could be generated to have a default state machine that accepts all messages. Now, in general, you wouldn't do formal verification on the generated code, so it wouldn't be very useful for say model-checking, but it could be useful for generating test-harnesses.
Type #3 is useful, but limited, due to the limitations of C++ templates. I would go for type #4 which gives the most flexibility, by producing not code but actually a generator which can then be invoked with the specifics. That would make the main generator a "higher-order" generator. This approach would be particularly useful for Software Product Lines. In this case, the partial model is a blueprint, but not a blueprint of a single, specific system, but a blueprint of a *family* of systems.