Scope Provider and smart reference extends another smart reference

I have a smart reference called SignalSettingRef which references an interface concept called ISignal.

concept ISignalRef extends Expression

references:
signal: ISignal[1]

I then have another smart reference called SignalSettingRef which extends ISignal and references concept SignalSetting.

 

interface concept ISignal extends INamedConcept
concept SignalSetting extends Signal
abstract concept Signal extends BaseConcept
implements ISignal

 

concept SignalSettingRef extends ISignalRef

references:
settingSignal : SignalSetting[1] specializes: signal

Concept SignalSetting extends a concept Signal which then extends the interface concept ISignal.

The idea is Signal, ISignal, ISignalRef are the base concepts and others (for example SignalSetting and SignalSettingRef) extend them. I use this to have many type of signals but still allow them to be referenced using ISignalRef. Sometimes I want users to pick from all signals, other times just from one type of signal say signalSetting.

In my root concept (called App) I provide a scopeprovider. The app root concept uses the reference ISignalRef.

This is my scope provider for App:

public Scope getScope(concept<> kind node<> child)
{
if(kind.isExactly(ISignal)
{
// code here to return all references to ISignal...
}
}

The problem is that this "if statement" is being called twice. I think that's because MPS calls it once for ISignalRef and then again for SettingsSignalRef (which extends ISignalRef). This causes some items to appear twice in the drop down box that the user sees.

The only way to eliminate this is to have SignalSettingRef extend Expression directly (with it's own editor and reference constraint) and handle as a separate case in scope provider like this:

if(kind.isExactly(ISignal))
{
// code here to return all references to ISignal...
} elseif(kind.isExactly(SignalSetting))
{
// code here to return all references to SignalSettings...
}

This is OK but does not seem as elegant. Especially when I have to import extra languages to provide for SignalSetting and etc... into the app language.

A related issue is if I have a different editor for signalSettingRef and ISignalRef, the first implementation always uses the ISignalRef editor.  The second implementation (when I break them apart) it uses the correct editor.

3 comments

Is your ISignalRef concept abstract or interface? (You say so but the code snippet doesn't.) If not, make it abstract and it should be removed from the menu.

Another thing, if you have a child of concept ISignalRef[1] then MPS will instantiate ISignalRef (even if it's abstract) and show its editor. And then allow you to replace it with a concrete subconcept which should then use that subconcept's editor.

0

ISignal is an interface but ISignalRef is not an interface or abstract. I updated the ticket to make it clearer.

I will try making it abstract; that does make sense.

0

1. I did make ISignalRef abstract.

2. Then created editor component for both ISignalRef and ISettingSignalRef like this:

editor component ISignal_Ref        
overrides:
<no EditorComponent>
applicable concept:
ISignalRef

component cell layout:
[> ( % signal % -> { name } ) <]
editor component ISignalSettingRef                  
overrides:
ISignal_Ref
applicable in context:
<default>
applicable concept:
SignalSettingRef

component cell layout:
[> setting- ( % settingSignal % -> { name } ) <]

... so that the proper editor will be shown.

 

0

Please sign in to leave a comment.