During syntax tree manipulation, common operations are often extracted to utility methods in order to simplify the task and reuse functionality. It is possible to extract such utilities into static methods or create node wrappers holding the utility code in virtual methods. However, in MPS a better solution is available: the behavior language aspect. It makes it possible to create virtual and non-virtual instance methods, static methods, and concept instance constructors on nodes.
The methods in the Behavior aspect are implemented using BaseLanguage, typically enhanced with extensions:
the collections language for intuitive collection API
the closures language for easy use of function literals
the smodel language for manipulating the code (structure)
Concept instance methods
A Concept instance method is a method, which can be invoked on any specified concept instance. They can be both virtual and non-virtual. While virtual methods can be overridden in extending concepts, non-virtual ones cannot. Also a virtual concept method can be declared abstract, forcing the inheritors to provide an implementation.
Concept instance methods can be implemented both in concept declarations and in concept interfaces. This may lead to some method resolution issues. When MPS needs to decide, which virtual method to invoke in the inheritance hierarchy, the following method resolution order (MRO) algorithm is applied:
If the current concept implements a matching method, invoke it. Return the computed value.
Invoke the algorithm recursively for an extended concept, if there is one. In case of success return the computed value.
Invoke the algorithm recursively for all implemented concept interfaces in the order of their definition in the implements section. The first found interface implementing the method is used. In case of success return the computed value.
Return a failure.
Overriding behavior methods
In order to override a method inherited from a super-concept, use the Ctrl keyboard shortcut to invoke the Override dialog. There you can select the method to override. By typing the name of the desired method to override you narrow down the list of methods.
When a concept instance is created, it is often useful to initialize some properties/references/children to the default values. This is what concept constructors can be used for. The code inside the concept construction is invoked on each instantiation of a new node of a particular concept.
A Behavior constructor will be called when
creating nodes with add new initialized(), set new initialized() and similar methods from
creating a node with
Using quotation like <Car()> will not call the Behaviors constructor. Consider using the smodel constructor instead.
Concept static methods
Some utility methods do not belong to concept instances and so should not be created as instance methods. For concept-wide functionality, MPS provides static concept methods. See also Constraints
Calling behavior methods on null nodes/concepts
When a behavior method is invoked on a null object that represents a node or a concept, the call does not result in a NullPointerException. Instead, a null value is returned, provided the return type of the invoked method is a ClassifierType or a StringType. For a PrimitiveType, the default value of that type is returned.