Is there a sigil to indicate a "return" value for a standard function like there is for a class function?

for classes, a function looks like this:

MyClass {
    someMethod {
        ^returnObject
    }

    someOtherMethod { | aBoolean |
        if(aBoolean) {
            ^someObject
        } {
            ^someOtherObject
        }
    }

}

For non-class functions, the last statement in a function is the return value:

x = { arg a, b, c;  var d;   d = a * b; c + d }
x.value(1,2,3).postln;

You can’t put a “^” sigil to indicate a return. Is there any standard syntax to indicate the return from a function that’s not just leaving the “;” off ? If a function needs multiple exit points, what’s the general accepted syntax ?

leaving the ; off isn’t an indication that there is a return. All Functions return the last line evaluated - so you ALWAYS have a return, and can return nil if you want to.

So for an if/else, the appropriate syntax would be:


y = {|a, b| if(a == b, { "equal" },{ "not equal" }) }

y.value(2,3).postln;

y.value(3,3).postln;

And there’s no equivalent to:

y = {|a, b| if(a == b, { return "equal" },{ return "not equal" }) }

correct ?

Asking because that function could get screwed up if you did:

y = {|a, b| if(a == b, { "equal" },{ "not equal" }) ;"whoops" }

This is obviously contrived, but I can see myself getting a bit turned around if there was a longer piece of logic I was working with.

correct

(and since the post must be 20 chars, I’ll add this parenthetical)

1 Like

You’re basically correct, though there’s maybe a slight subtlety to this…

There is a strong semantic difference in SuperCollider between returning from a function and returning from a method. You CAN do:

if (condition) {
   ^"true"
} {
  ^"false"
}

… where ever you want, but the ^'s are not function returns. Imagining if they were… You would of course be able to do “early” returns from a { block } - very useful - but you would no longer be able to early return for a wide variety of cases in a method;

findItem {
    |function|
    items.do {
         |item|
         if (function.value(item)) {
             ^item
         }
    };
    ^nil
}

If the ^ were a function return, it would return from the function passed to the if. This would be a no-op, and the do loop would continue though the items and always return nil.

There’s not an easy way to resolve this without either making method definitions very ugly (e.g. explicitly specifying this at the end of every chainable method), or introducing a second syntax for function returns vs method returns.

One other note - and this is more or less my coding style with most things - but I often will assign the result of an ‘if’ statement to a variable, then return that variable at the end of the function. This is more readable to me, and removes ambiguity. I actually just had some back and forth about this at work - and while this means a little more typing, the clarity I feel is worth it.

y = {|a, b| 
   var result; 
   result = if(a == b, { "equal" },{ "not equal" }) ; 
   result 
}
1 Like

That’s super interesting. I would expect that the example you gave would return from the outermost scope - the function.value(item) would return a value that’d be enclosed in the if () and that’d in turn be used by the check to “^item”.

If the sigil “^” doesn’t mean return, what is its meaning ?

I go back and forth on this myself.
I tend to like only one exit statement from a function, but sometimes if i basically have a switch … I revert. I find that if you’re in a situation where high-pressure debugging (like on a trading floor) is required, then one exit statement is your best bet.

It’s a hard line to walk, though, because it can sometimes make the code awkward to read.

1 Like

code is awkward to read by nature - we’re just trying to find ways to make it better :wink:
why else would they call it code?

2 Likes

It does mean return, but specifically it’s return for the context where the block containing it was constructed (I think this is referred to as a home context in the code). In a method this is pretty well defined - if your function is defined in methodA, that’s it’s home context. There are more ambiguous cases, which at best give you weird behavior and at worst give you an OutOfContextReturnError, I believe indicating that the home context for the function is no longer available. This will give you an error, for example:

+SomeClass {
    *getFunc { ^{ ^"returned" } }
    *callFunc { |f| f.() }
}
// SomeClass.callFunc(SomeClass.getFunc());

This somewhat unexpectedly does NOT give an error, but still behaves incredibly weirdly:

SomeClass.callFunc({ ^"return" });

This is a pretty arcane part of sclang tbh…

The moral of the story is basically: use ^ as a part of inline functions inside of methods, and nowhere else.

1 Like

Thank you for the clarification! It’s weird the syntax is different between classes and normal coding, but I can live with it.

Yeah, it does feel very weird. I think maybe the better way to think about it is as syntactic sugar to solve one specific problem (marking explicit returns in methods, so you can have a default return value of this) - it’s not a deeply integrated part of the language, but rather just something that saves you from having to make all your simple methods end with this; (if methods followed the “return the last thing on the stack” pattern).

Makes sense. I was trying to think of some way to make my code more explicit, but I guess I’ll just leave it as-is and be a bit careful in how I write things.