Noob: don't understand usage of curly brackets in if-statement

Well, the last 16 posts or so have been about this, so that is hopefully clear by now. As for.

Your example A is defective because ~wahr expects an argument, but you’re not providing one that makes sense from the 5.do context. So i in ~wahr is going to be nil in that example A call.

~wahr = {|i| ("wahr" + i).postln};
~wahr.() // wahr nil

What {~wahr.(i)} does is to return a function that sends to ~wahr the proper argument from the 5.do context (which is also a function). So {~wahr.(i)} is not the same function as ~wahr because i in the former is already bound; a clue is that {~wahr.(i)} is a function that does not take any arguments! This is really called creating a closure.

Here’s a simpler example

~wahr = {|i| ("wahr" + i).postln}; 

z = {~wahr.(42)} // also a function
// but takes no arg and always gives the same arg to ~wahr

z.() // 42

z.(111)  // still 42

Now every time the do does a loop it creates a new function like z, but with a different constant bound inside, from the current loop iteration.

Well, that is what happens conceptually. In reality, the if there gets inlined
at line 13 below because you’ve used braces, i.e. functions on both branches of if and because the two branch functions like {~wahr.(i)} don’t declare any variables of their own! So the if practically works like in a traditional imperative language in your case, meaning no actual functions get created from {~wahr.(i)}.

{ if ( [false, true].choose, {~wahr.(i)}, {~falsch.(i)} ) }.def.dumpByteCodes

/*
BYTECODES: (34)
  0   06 19    PushSpecialClass 'Array'
  2   65       PushSpecialValue 2
  3   C2 00    SendSpecialMsg 'new'
  5   6D       PushSpecialValue false
  6   C2 08    SendSpecialMsg 'add'
  8   6C       PushSpecialValue true
  9   C2 08    SendSpecialMsg 'add'
 11   C1 24    SendSpecialMsg 'choose'
 13   F8 00 0A JumpIfFalse 10  (26)
 16   41       PushLiteral Symbol 'wahr'
 17   C1 3C    SendSpecialMsg 'envirGet'
 19   1A       PushInstVar 'i'
 20   B0       TailCallReturnFromFunction
 21   C2 06    SendSpecialMsg 'value'
 23   FC 00 07 JumpFwd 7  (33)
 26   40       PushLiteral Symbol 'falsch'
 27   C1 3C    SendSpecialMsg 'envirGet'
 29   1A       PushInstVar 'i'
 30   B0       TailCallReturnFromFunction
 31   C2 06    SendSpecialMsg 'value'
 33   F2       BlockReturn
-> < closed FunctionDef >
*/

For the hardcore geeks, the magic stuff happens in compileIfMsg. The test for inlining isAnInlineableBlock is indeed whether both branch functions in an if declare no arguments and no variables of their own.

1 Like