Distinguishing between Types in search scope


for my Concept Composition, I want to distinguish wether it is a G_arr or a S_arr (for Graph arrow and Set arrow)

that means, when I choose for instance G_arr on the left side, only Elements from G_arr shall be available in the scope on the right side and vice versa. 

My Concept Composition has a a "from" and "to" reference to concept "arrow":

and the concepts "Graphfunction" and Totalfunction" both extend the concept "arrow", that's why G_arr and S_arr are both found in the scope.

Now, my Idea is to make a referent constraint for concept "composition" and set referent constraints for "from" and "to".

Is this approach correct? What do I have to type in the referent set handler? I have absolutely no idea.

Thanks in advance.

Kindly regards,





Comment actions Permalink

Hi Volker,

I think your approach is indeed correct. The referent scope handlers allow you to implement the scopes you want.

If I understand your requirement correctly, you want to filter the scope of either reference depending on the value of the other.

One important thing that constantly catches me off guard when I implement these handlers is that they are called by MPS in different instances:

  1. they are called when you invoke the substitution menu, aka: when the reference you want to build a scope for is not yet part of the AST
  2. they are called ADDITIONALLY when MPS performs a constraint check on your model, aka: for the references that are already in the model (providing constraint error markers if the reference is "out of search")

Check the inspector for for the referent scope constraint, it describes this behavior as well.

For your arguments, this means that referenceNode (first argument) might be "null" (case 1. from above) or the reference in question (case 2. from above).

From an algorithmic perspective, what you roughly want to do something like this:

  1. collect all "candidate nodes" that potentially fit in the role of your reference
  2. build a "ListScope" object and pass this "complete" list to it
  3. build a "FilterScope" object that wraps above ListScope object and filter objects based on a condition

There are certainly alternative ways to achieve what you want. 

Roughly, again, you want something like this:

nlist<arrow> arrows = contextNode.model.nodes(arrow); // step 1: all arrows
Scope scopeAll = ListScope.forResolvableElements(arrows); // step 2: build ListScope

// imagine this is the implementation for the "from" role, you have to lookup the other one for the "to" role
final concept conceptToExclude = contextNode:composition.to.concept;

return new FilteringScope(scopeAll) {
public boolean isExcluded(node<> node) {
return conceptToExclude.isNull ? false : node.concept.isExactly(# conceptToExclude);

This code is untested and not compiled or anything, so beware of typos... but it should give you an idea.

On a general note: when I have to implement a hook that I never implemented before, I do the following:

  1. select the hook in question (in your case the empty reference scope handler)
  2. Got to its definition (e.g. by pressing CTRL+Shift+S on Windows, or via "Open Concept Declaration" link in the inspector)
  3. Search for its intances, globally (by opening the "Find Usages" dialog, via CTRL+Shift+Alt+F7 on windows, or via ContextMenu->Find Usages Settings ... and selecting "Concept Instances" and "Global")
  4. Look how the Jetbrains/itemis guys implemented this hook in their platform


Comment actions Permalink

Thanks for your reply. But unfortunately that doesn't work correctly, so I tried it a bit different

what I attempted to do is, to ask whether the "to" reference comes from concept Graphfunction and if yes then only arrows for Graphfunctions (G_arr) should be in the scope and for Totalfunction vice versa. 

You maybe know where the error is?

Thanks in advance

Comment actions Permalink

Well, it looks like you are not overriding the necessary "isExcluded" function of FilteringScope, but just added your own function, called "isExluded". This is never called.

I think to override the function, you can press Ctrl+O inside your implementation of FilteringScope and select it from the pop-up dialog.

Another, more direct way to get the scoping logic right is to filter early on, something like:

concept<> conceptToExclude = contextNode:composition.to.concept;
return ListScope.forResolvableElements(conceptToExclude.isNull ? contextNode.model.nodes(arrow)
: conceptToExclude.isExactly(Graphfunctions) ? contextNode.model.nodes(Totalfunction) : contextNode.model.nodes(Graphfunction));

I mean, this is horrible code and it makes several aassumptions about your structure, but it should do the trick as well.

The other solution is closer to a "best practice", I guess.

Comment actions Permalink

Thanks for this, but anyhow I can't choose the .isNull function. Which model does include it?

Comment actions Permalink

My bad, I just wrote this code here in the forum without MPS. "concept" does not have this "isNull" operation. You can just do conceptToExclude :eq: null instead...


Please sign in to leave a comment.