In the following model code, the context variable this should refer to instances of the structural context for the behavior, that is to instances of the part type ElevatorCabin, as explained by Ed Seidewitz in a post on the Google Groups forum SysML v2 Release.
action def MoveUp {
in elevCab : ElevatorCabin;
assign elevCab.cabinState := CabinState::MOVINGUP;
}
part def ElevatorCabin {
attribute cabinState : CabinState;
perform action moveUp[*] : MoveUp;
perform action goUp[*] {
perform moveUp[1] { in elevCab =this; }
…
}
…
}
However, Syside Modeler shows me the error message “Occurrences::Occurrence::this does not conform to ElevatorSystem::ElevatorCabin“?
Thanks for the report. I will look into adding yet another edge case to the type checker. In the meantime, you can silence the diagnostic with an explicit cast this as ElevatorCabin.
If only this were a keyword instead of a library feature that needs to be redefined…
After adding this support, it would still not fix the type error - this would resolve to moveUp only.
Sample modified with implicit specializations (skipping fully qualified names for brevity) to standard elements gives a clue as to why:
action def MoveUp :> Action {
in elevCab : ElevatorCabin :> objects;
}
part def ElevatorCabin :> Part {
//* ref */ perform action moveUp : MoveUp [*] :> performedActions;
//* ref */ perform action goUp [*] :> performedActions {
//* ref */ perform moveUp [1] :> enclosedPerformances { in elevCab = this; }
}
}
Went through the standard library and found 4 cases of this:
viewpointSatisfactions and checkedConstraints - that.that
ownedActions and ownedPerformances - that
subactions and subperformances - that.this
self otherwise
enclosedPerformances does not override the default this, thus it resolves to moveUp. And it implicitly subsets enclosedPerformances because perform actions are implicitly referential, i.e. non-composite.
Thanks for your analysis.
I think missing the enclosedPerformances in the redefinitions of this is a bug and not a feature.
What shall we do? We could either post this as a questions to the SysML v2 Release forum or directly submit an issue.
I do not know the solution to this, might be best to ask on the official group first.
On the other hand, if perform actions were not implicitly referential, the sample would be correct, as perform actions would implicitly specialize subperformances or subactions instead.
Hello Gerd,
In fact, this is a feature (in every meaning of this heavily overloaded sentence :)).
The feature “this” is supposed to refer to the context of the behavior, which is always the part that directly or indirectly owns it. A perform action is a referential action. The performer performs the action (like a method call), but it is not the context in which the action runs (~the instance of the class defining the method). The action is supposed to access and manipulate the features of its owner, not the performer.
In your example, you simply want to pass the ElevatorCabin instance as the elevCap argument. To refer to the ElevatorCabin, you would use “self”, but the perform action also has a self, so you have to write ElevatorCabin::self.
Alternatively, you can use the “this” feature to directly navigate to the ElevatorCabin instance if “goUp” is not a perform action - it does not refer to anything, so it should probably be a composite action instead.
It is very tempting to use perform actions everywhere. However, they are referential, and - even though referential features can also have values of their own - they are supposed to reference subset a composite action (or another perform action in some cases, but the chain should lead to a composite action).
I hope this helped.
Thanks for your explanations, Vince.
I still have some open questions concerning the use of “perform” and the meaning of “this”.
You say it is “tempting to use perform actions everywhere”, but isn’t it correct to declare a “perform action” feature in a part type definition whenever I want to express that the parts of that type are not just the owners, but the performers of these types of actions? That’s the semantics why I have declared moveUp, stop and goUp as perform action features in the following example, and not because I want them to be “referential”. Since they are not declared with reference subsettings, “the performed action is the perform action usage itself” (7.17.6).
action def MoveUp {
in elevCab : ElevatorCabin;
assign elevCab.cabinState := CabinState::MOVINGUP;
}
part def ElevatorCabin {
attribute cabinState : CabinState;
perform action moveUp[*] : MoveUp;
perform action stop[*] : Stop;
perform action goUp[*] {
perform moveUp[1] { in elevCab =this; }
perform stop[1] { in elevCab = ElevatorCabin::self; }
…
}
…
}
Then the natural expectation is that “this” still refers to the context part (the elevator cabin) as the owner/performer of these actions.
@Daumantas : It seems that Syside Modeler cannot resolve ElevatorCabin::self as suggested by Vince and used above!?
self, that, and this being library features there is not much we can do as in the AST any qualified references are resolved to specific library features - the path to get to those features is not in the AST. Without adding yet even more edge cases we can only resolve those features in the enclosing scope. Also chainings of those features are not currently supported, e.g. this.that.
A better solution would be to treat them as keywords during expression result type inference so that the inferred types propagate through expression chains but this would also affect name resolution for feature chains as the inferred type is used for resolving dependent names. I would like to have this at least as an opt-in flag in the future because manually redefining them in the models is both error prone and very noisy.
Okay, I understand that Syside Modeler can currently not resolve a qualified feature name like ElevatorCabin::self, but it should at least not flag it as an error for avoiding false negatives. Otherwise, usability is severely hampered.