Nested dereferencing of dicts and declaring trigger variables from dicts

Hey Chris,

I’m currently exploring, how powerful mwel can be in comparison to the xml approach of earlier versions.

I came across two behaviors, that I unfortunately fail to solve myself:

%define present_stim(stim_fix_id, position_id)
    // Queue fixation point
    fixation_points[stim_fix_id]['x_position'] = positions[position_id]['x_position']
    fixation_points[stim_fix_id]['y_position'] = positions[position_id]['y_position']
    // This works:
    queue_temp = fixation_points[stim_fix_id]['stim_fix_id']
    queue_stimulus(stim_fix[queue_temp])
    // This does not:
    //queue_stimulus(stim_fix[fixation_points[stim_fix_id]['stim_fix_id']])

    update_stimulus_display()
%end

As far as I understand how most parameters work, they are not assigned by value but by reference. Hence, you can change the value in the variable somewhere else, and it also gets updated across all components.
So I guess in this example the parameter for dereferencing stim_fix does not get correctly dereferenced before it is evaluated, or am I missing something? Is there a workaround for this?

The parser at least is not very happy about it:

00:29:40:  ERROR: Illegal stimulus dimension reference: stim_fix
Extended information:
	location: line 81, column 5; via line 111, column 17
	object_type: action/queue_stimulus
	parent_scope: Press the Circle
	ref_id: idp105553178068607
	parser_context: mw_anonymous_create

Second behavior:

When I for example want to organize my stimuli in a dictionary like this:

var trigger_correct = false
var trigger_incorrect = false

var STIM_CORRECT = 0
var STIM_INCORRECT = 1

var fixation_points = [
    {'stim_fix_id': 0, 'x_position' : 0, 'y_position': 0, 'trigger': false},
    {'stim_fix_id': 1, 'x_position' : 0, 'y_position': 0, 'trigger': false}
]

var stim_size = 30

stimulus_group stim_fix {
        fixation_point 'stim_fix_correct'(
            color = 0, 1, 0
            x_size = stim_size
            y_size = stim_size
            trigger_width = stim_size
            trigger_watch_x = pointer_x
            trigger_watch_y = pointer_y
            trigger_flag = trigger_correct // <-this works, but this does not work (or at least the variable stays unchanged on expected trigger): fixation_points[STIM_CORRECT]['trigger']
            x_position = fixation_points[STIM_CORRECT]['x_position']
            y_position = fixation_points[STIM_CORRECT]['y_position']
        )
        fixation_point 'stim_fix_incorrect'(
            color = 1, 0, 0
            x_size = stim_size
            y_size = stim_size
            trigger_width = stim_size
            trigger_watch_x = pointer_x
            trigger_watch_y = pointer_y
            trigger_flag = trigger_incorrect // <-this works, but this does not work (or at least the variable stays unchanged on expected trigger): fixation_points[STIM_CORRECT]['trigger']
            x_position = fixation_points[STIM_INCORRECT]['x_position']
            y_position = fixation_points[STIM_INCORRECT]['y_position']
        )
}

Here I try to have all my triggers organized together with the coordinates of the stimuli I’d like to present. The parser is also happy with this, but at runtime the values in the dictionaries don’t get updated, and I can’t use them for conditional goto’s. That feels a little strange to me, since in the other direction with the x_position for example this approach works like a charm.

As seen, I came up with a workaround for both cases, but I’m curious of the why, and I would like to do it the way I want if possible :sweat_smile:

Thanks in advance for your help and time!

Minimum example file (unfortunately, I cannot upload files yet here):

Hi Louis,

Just to be clear, neither of your issues has anything to do with MWEL vs. XML.

// This works:
queue_temp = fixation_points[stim_fix_id]['stim_fix_id']
queue_stimulus(stim_fix[queue_temp])
// This does not:
//queue_stimulus(stim_fix[fixation_points[stim_fix_id]['stim_fix_id']])

This issue here is that stimulus groups (e.g. stim_fix) are not related in any way to dictionaries (e.g. fixation_points[stim_fix_id]). They are parsed (after conversion from MWEL to XML) using completely different code. Unfortunately, the code for parsing stimulus group expressions is a little dumb, and it’s getting confused by all the additional square brackets in the indexing expression. I’ve opened an issue to correct this. In the meantime, your current workaround looks good.

trigger_flag = trigger_correct // <-this works, but this does not work (or at least the variable stays unchanged on expected trigger): fixation_points[STIM_CORRECT][‘trigger’]

The problem here is that trigger_flag must be the name of a variable. This is true for any component parameter that has values assigned to it. While you can technically use an arbitrary expression, anything other than a plain variable name won’t be writable, which is why the trigger isn’t being set.

I see the logic in what you were trying to do, but, sadly, it just doesn’t work. I also don’t see a way to change this, short of a drastic reworking of MWorks’ basic handling of variables and expressions.

As far as I understand how most parameters work, they are not assigned by value but by reference. Hence, you can change the value in the variable somewhere else, and it also gets updated across all components.

It really depends on the component. In general (but not always), input-only parameters are stored as unevaluated expressions, and the component can evaluate and re-evaluate them as needed. Output parameters, on the other hand, can’t be anything other than a variable name, as I noted above. It’s all rather frustrating and inconsistent, but there’s not a lot to be done about it at this point, short of some very major revisions to a lot of basic functionality.

Cheers,
Chris

Hello Chris,

thanks for the clarification. I had just assumed that since the editor is no longer included in the current version, that there must have been something like a major revisions from an XML-based parser to a MWEL-based parser, with backward compatibility using an XML-to-MWEL converter.

I imagine this is not the prettiest approach, but would it be possible to update the parser to look for illegal characters like “[” “]” and issue a warning for parameters that are not evaluated, like the trigger_flag?

Furthermore, I would also appreciate if the documentation would include information about the requirements of each parameter. Maybe I take a look at that too. I guess the main difference is between
“registerVariable” and “VariablePtr”?

Hi Louis,

I had just assumed that since the editor is no longer included in the current version, that there must have been something like a major revisions from an XML-based parser to a MWEL-based parser, with backward compatibility using an XML-to-MWEL converter.

The editor is gone, but XML experiments are still 100% supported. As the MWEL documentation says:

At runtime, MWEL experiments are translated into MWorks’ XML, after which they are parsed and executed in exactly the same way as traditional, XML-based experiments. This ensures that equivalent experiments written in MWEL and XML perform identically. (However, it also means that some of the limitations of XML-based experiments apply to MWEL-based ones, too.)

Maybe someday we’ll be able to get rid of the XML parser, but I don’t think it’s going to happen soon.

I imagine this is not the prettiest approach, but would it be possible to update the parser to look for illegal characters like “[” “]” and issue a warning for parameters that are not evaluated, like the trigger_flag?

A simpler and more robust approach would be to check if the relevant Variable instance is writable, and issue an error if it isn’t. This already happens for variable assignments. If the “variable” were an expression, then the Variable instance would be a ParsedExpressionVariable, which is not writable.

Actually, after considering it some more, I think it might be possible to support what you originally wanted to do. There’s already a class that handles parsing of and assignment to both simple variables and variable subscript expressions, which is used for variable assignment actions. I don’t see any reason why other components that need to assign outputs to a variable couldn’t use it, too. Making this change could be a pretty big job, since every component that generates outputs would need to be updated, parameter by parameter, but maybe it’s worth it. I’ve opened an issue and will consider it further.

I would also appreciate if the documentation would include information about the requirements of each parameter.

Well, the docs for trigger_flag already say “variable to which fixation status is written”. But, yes, more documentation is always helpful.

I guess the main difference is between “registerVariable” and “VariablePtr”?

No, not really. registerVariable makes a stimulus parameter “frozen” when the stimulus is queued. The difference, as I said above, is between input parameters and output parameters: Input parameters can be stored as unevaluated expressions (e.g. ParsedExpressionVariable) and re-evaluated as needed, while output parameters must be simple Variable references in order to support assignment.

Also, not all input parameters are stored as expressions. For example, in the code you referenced, activeWhenHidden is evaluated only at experiment load time and thereafter stored as a const bool value. This is another detail that could use documenting, and doing that is on my to-do list.

Cheers,
Chris