Extend multiple return value syntax functions to be more usable

The addition of multiple return value syntax functions in IP8 were a very nice addition. Now you can finally have a nice way of returning multiple values and don't need pass-by-reference parameters anymore.

This makes it also feasible to have functions return a string and a variable like in

Function [variable real, string text] GetValue()

    return 1, "abcd"
End

One example for such functions are generic getters which can return a string or a variable. The call site for functions like that do look a bit odd still, if you only care about one value.

Function DoStuff()
    variable var
    string junk

    [var, junk] = GetValue()
End

Now we come to my request :)

I would like to have a way to select one of the multiple return values at the call site. Something like

Function DoStuff()
    variable var

    var = GetValue().num
End

sprang to mind. This would make the call site less cluttered.
And would also allow to have MRS functions return correctly typed waves as in

Function [WAVE num, WAVE/T text] GetWave()

    Make/FREE num = { 1 }
    Make/FREE/T text = { "abcd" }
End

Function DoStuff()
    WAVE num = GetWave().num

    WAVE/T text = GetWave().text
End

I don't have very good reasons for the ".$name" syntax addition and are happy to be persuaded to even better syntaxes.

Have you seen in IP9 that you can declare the parameters in-line? i.e:

Function DoStuff()
   
    [double var,String junk] = GetValue()
End

I use this a lot now..... though it is not quite what you're requesting it does clean up the syntax quite a bit.

Doesn't MatLab use a syntax something like 

Function DoStuff()
    variable var

    [var,] = GetValue()
End

to skip or throw away unneeded return values?  Would something like that help?

One problem with the ".$name" syntax would arise for a function returning more than one value of the same type.

@jtigor - whatever this so-called 'matlab' is looks like it has a sensible solution for the multiple return syntax ;)

In all seriousness I like the matlab way as you can see better what the code is doing rather than the python style. 

I'm also fine with just leaving it off. But of course this would need to work with anyone entry.

> One problem with the ".$name" syntax would arise for a function returning more than one value of the same type.

My syntax suggestion uses the name of the MRS return value and not the type. And the name is unique. Does that make sense?

Perhaps these look prettier to you:

 

Function [variable real, string text] GetValue()
    return [1, "abcd"]
End

Function DoStuff()
    variable var
    String junk

    GetValue(var, junk)
End



Function [WAVE num, WAVE/T text] GetWave()
    Make/FREE num = { 1 }
    Make/FREE/T text = { "abcd" }
End

Function DoStuff2()
    WAVE/Z num
    WAVE/T/Z text
    GetWave(num, text)
    print num, text
End

 

@aclight: Thanks for reminding me about this alternative syntax for MRS functions.

At least for me this does not help, as it uses pass-by-references parameters explicitly which get's confusing quickly if you also have normal parameters.

What I understand is that under the hood, the multiple-return syntax is using pass-by-reference parameters, so the parameters have to be declared ahead of time -- whether in their own lines (ala IP8) or using the condensed single-line version offered by IP9.

In Matlab, you can define a function [a, b, c] = f(x,y) and then you can assign to local variables only those return values you care about. (@thomas_braun, I think that's what you're after... am I right?) So, for example, you can declare

function [s, v, A] = f(X, Y)

and when calling function f you can assign any of the following:

[s1, v1, A1] = f(X)
[s1, v1] = f(X)    ' ignoring the returned A value
s1 = f(X)          ' ignoring last two values

(Is there a way in Matlab to skip assigning values from the middle, like v? Even if not, Matlab does not require declarations, which makes it easy to just assign it to a dummy variable and ignore it.)

What would an optional return MRS syntax in Igor look like, and how would it work? If an output variable is not provided, perhaps Igor could detect that the reference is null and maybe create a valid local variable or free wave (as the case may be) to be used in its place during the function run (in case the function uses that parameter or assigns to it). So if a function is defined as follows:

Function [string s, variable v, WAVE A] f()

Then maybe if you don't care about assigning v to a local variable you could make a call like:

[String s1, $"", WAVE A1] = f()

or better:

[String s1, , WAVE A1] = f()

If this is possible, is something like this what you had in mind?

You also mentioned something along the lines of "var = GetValue().num". I do like the compactness of that syntax. You would want to support more than just one output, since you certainly wouldn't want to call GetValue() twice just to get .num and .text. That suggests having the MRS support Struct outputs -- but at that point, it seems to make more sense to simply pass a Struct by reference as a regular variable. That's just my two cents.

I do like the idea of having optional return values.

> In Matlab, you can define a function [a, b, c] = f(x,y) and then you can assign to local variables only those return values you care about. (@thomas_braun, I think that's what you're after... am I right?)

Yes!

[...]

> If this is possible, is something like this what you had in mind?

Yes this would be an option.

> You would want to support more than just one output, since you certainly wouldn't want to call GetValue() twice just to get .num and .text.

The idea behind the dot syntax is that you can just select one return value from the existing ones. So this would be optional only. If you need all return values you can just grab these with the existing syntax.

What the matlab solution has in advantage of the dot proposal is that you can ignore multiple values while fetching more than one. The dot proposal on the other hand has/could have the advantage that the return value can be used like a variable. So if the returned value is a wave and you get that via .wv you can immediately start indexing it as in .wv[5].