title::Conditional Execution
summary:: conditional expressions in SuperCollider
categories:: Language
related:: Classes/Boolean, Classes/Function, Classes/Exception, Reference/Syntax-Shortcuts, Reference/loop

This page gives an overview of the conditional expressions in SuperCollider and the many ways to write them.

section:: Quick Overview
subsection:: Recommended syntax

table:: 
## link::#if:: || code:: if(expr) { trueFuncBody } { falseFuncBody } ::
## link::#case:: || code:: case { testFuncBody1 } { trueFuncBody1 } ... { testFuncBodyN } { trueFuncBodyN } ::
## link::#switch:: || code:: switch(value) { testValue1 } { trueFuncBody1 } ... { testValueN } { trueFuncBodyN } ::
## link::#while:: || code:: while { testFuncBody } { loopFuncBody } ::
::
More syntax variants exist, see link::#Syntax of conditional expressions#below::.

note:: 
Throughout this file, the placeholder code::someFuncBody:: is distinct from code::someFunc:: 
(e.g., code::trueFunc:: vs. code::trueFuncBody::, code::testFunc:: vs. code::testFuncBody::, etc.).
In distinction from code::someFunc::, code::someFuncBody:: does emphasis::not:: stand for an already instantiated Function object (a lambda function),
but rather for an expression that can serve as a Function definition. 

In other words, if code:: { "doThis".postln }:: is your code:: someFunc ::,
then code:: "doThis".postln; ::---without the curly Brackets---is your code:: someFuncBody::.

Consequently, strong::do not:: write
code:: if([false,true].choose) { { "doThis".postln; } } ::, 

but strong::do:: write
code:: if([false,true].choose) { "doThis".postln; } ::. 
::

subsection:: Examples
table::

## code::
x = 6.rand;
if(x < 3) {
	"oh"
}  {
    "weh"
}
:: || code::
x = 0;
while { x < 6 } { x.postln; x = x + 1}
:: ## code::
x = 6.rand;
case 
	{ x <= 1 } 	{ "oh" } 
	{ x == 2 } 	{ "weh" } 
	{ x == 3 } 	{ "oi" } 
	{ x < 5 } 	{ "moi" }
	{ "default" }
:: || code::
x = 6.rand;
switch(x)
	{ 0 } 	{ "oh" }
	{ 1 } 	{ "weh" } 
	{ 2 } 	{ "oi" } 
	{ 3 } 	{ "moi" }
	{ "default" }
::
::

Quick links to sections:

numberedlist:: 
## link::#if::,  link::#case::, link::#switch::, link::#while:: (specifics),
## link::#Optimization through inline expansion#optimization/inlining::, 
## link::#Audio Control Structures: Do not use .if etc. in Synths!#if-statements in Synths:: (strongly discouraged).
## link::#Syntax of conditional expressions::,
::

For other control structures, see link::Reference/loop:: and link::Classes/Exception::.

section:: Overview of Basic Conditional Expressions

note:: 
Reminder: code:: falseFunc == { falseFuncBody }::. 

For instance, when code:: falseFunc == { "aaa" } ::, 
then code:: falseFuncBody == "aaa".  ::
::	

subsection:: if

The code::.if:: method is called on a receiver teletype::expr:: which must return a link::Classes/Boolean:: value.
(In other words, code::if:: is a method of Boolean.)

In addition the method call takes two arguments: 
a link::Classes/Function:: teletype::trueFunc:: to execute (call .value on) if the expression is true, 
and another optional Function teletype::falseFunc:: to execute (call .value on) if teletype::expr:: is false. 

The code::.if:: method returns the value of the function which is executed
(i.e., code:: trueFunc.value :: if receiver is code::true::, 
code:: falseFunc.value :: if receiver is code::false::).

If teletype::falseFunc:: is not present and teletype::expr:: is false, then the code::.if:: method returns code::nil::.

subsubsection:: Syntax
code::
// function call notation
if(expr, trueFunc, falseFunc);
if(0 < 3, {"aha"} {"brb"}); 

// function call notation with trailing argument block
// looks almost like C (without the "else").
if(expr) { trueFuncBody } { falseFuncBody };
if(0 < 3) {"aha"} {"brb"}; 

// not recommended: receiver notation, 
// reflects the fact that .if is a method like any other;
// but is hard to read and rarely used in practice 
expr.if(trueFunc, falseFunc);
::

subsubsection:: Examples

code::
// function call notation with trailing argument block
// note the indentation and linebreaks,
// which are recommended, but not mandatory.
(
if([false, true].choose) {
	"expr was true".postln  // trueFuncBody
} {
	"expr was false".postln  // falseFuncBody
};
)

// assignment of value according to condition
(
var a = 1, z;
z = if(a < 5) { 100 } { 200 };
z.postln;
)

// same as
(
var a = 1, z;
if(a < 5) { z = 100 } { z = 200 };
z.postln;
)

// no falseFunc, expr is true
(
var x = 1;
if(x > 0) { 90 + x }; // returns { 90 + x }.value
) // -> 91

// no falseFunc, expr is false
(
var x = 1;
if(x < 0) { 90 + x}; 
) // -> nil
::

subsection:: case

Function also implements a code::case:: method which allows for conditional evaluation with multiple cases. 
The receiver here but can be thought of as simply the zeroth argument, representing the first of multiple "cases".
Thus, the arguments including the receiver can be written as pairs of teletype::testFunc::s and corresponding teletype::trueFunc::s. 
if a teletype::testFunc:: returns true, its corresponding teletype::trueFunc:: is evaluated and its code::.value:: returned.
If no teletype::testFunc:: returns true, either teletype::nil:: is returned, or the code::.value:: of a teletype::defaultFunc:: supplied as the final argument.
Case is inlined (under the conditions outlined link::#Optimization through inline expansion#below::), and is therefore just as efficient as nested if statements.

subsubsection:: Syntax

code::
// { testFuncBody1 } is technically the receiver.
// trailing receiver and argument block notation
// (possible because receiver and all arguments are Functions):
case
	{ testFuncBody1 } { trueFuncBody1 }
	{ testFuncBody2 } { trueFuncBody2 }
	...
	{ testFuncBodyN } { trueFuncBodyN }
	{ defaultFuncBody }; // defaultFunc can be omitted.

// function call notation:
case(   
		testFunc1, trueFunc1,
    	testFunc2, trueFunc2,
		...,
		testFuncN, trueFuncN,
		defaultFunc // defaultFunc can be omitted.
	); 
// in some cases the function call notation will appear to work even if 
// arguments are not Function objects, as long as they respond to .value;
// however, no inlining will take place then.
::


subsubsection:: Example

code::
(
var i, x;
i = [0, 7, 2, 329, 4, 5000].choose;
x = case
	{ i == 0 }     { \no }   
	{ i == 7 }     { \wrong }
	{ i == 2 }     { \worng }
	{ i == 329 }   { \wrnog }
	{ i == 4 }     { \wnorg }
	{ i == 5000 }  { \true };
x.postln;
)
::
or
code::
(
case(
    {[true,false].choose}, {"first test was true"},
    {[true,false].choose}, {"second test was true"},
    {[true,false].choose}, {"third test was true"},
    { "no test was true" }
);
)
::

subsection:: switch

Object implements a switch method which allows for conditional evaluation with multiple cases. 
Each case is represented by a pair of two arguments: a teletype::testValue:: followed by a teletype::trueFunc::.
In distinction to link::#case::, the receiver is emphasis::not:: the first test function, but rather an object that other teletype::testValues:: are all compared to. 
The receiver is compared against the teletype::testValue::s, and if the comparison returns true, the corresponding teletype::trueFunc:: will be evaluated and its value returned.
If it is false, the next teletype::testValue:: is compared, and so on. 
The return value of code::switch:: in case of emphasis::no:: matching teletype::testValue:: is dependent on whether the number of arguments passed to it is even or odd. 
If the number of arguments is even, code::switch:: will return teletype::nil:: in such cases, whereas if it is odd, the last argument should be a teletype::defaultFunction:: whose code::.value:: will be returned.

The strong::comparison function:: used is equality, i.e., code::==::, 
unless the switch statement is inlined (see also link::#Optimization through inline expansion#below::), 
in which case switch compares by identity, i.e., code::===::. (See link::Guides/EqualityIdentity::)

The switch statement will automatically be inlined if two conditions are met: 

strong::First::, the test objects are all values with unique representations (Floats, Integers, Symbols, Chars, nil, false, true) and 
strong::second::, functions used in the switch statement have no variable or argument declarations. 
The inlined switch uses a hash lookup (which is faster than nested if statements), so it should be very fast and scale to any number of clauses. 

note:: 
strong::Avoid using String or Float as test objects for switch.:: 
The former is simply less efficient than Symbol, as it will not inline; 
the latter will inline, but may yield unexpected results due to floating-pointing representation,
e.g., code::(2/3) == (1 - (1/3)):: returns code::false::.
::

subsubsection:: Syntax

code::
// function call syntax with trailing argument blocks
// linebreaks are optional but recommended
switch(value)
	{ testValue1 } { trueFuncBody1 }
	{ testValue2 } { trueFuncBody2 }
	{ testValue3 } { trueFuncBody3 }
	...
	{ testValueN } { trueFunchBodyN }
	{ defaultBody }; // defaultbody can be omitted.

//function call syntax without trailing arguments 
switch(value,
	testValue1, trueFunc1,
	testValue2, trueFunc2,
	...
	testValueN, trueFuncN,
	defaultFunc // defaultFunc can be omitted
);
::

subsubsection:: Examples

code::
//function call syntax without trailing arguments 
(
var x = 0; //also try 1
switch(x, 
    0, { "hello" }, 
	1, { "goodbye" }
	)
)


// function call syntax with trailing argument blocks
(
var x = 0; //also try 1
switch(x) 
	{ 0 } { "hello" } 
	{ 1 } { "goodbye" };
)

(
var x, z;
z = [0, 7, 2, 329, 4, 5000].choose;
switch (z.postln,
	7,    { \no },
	2,    { \wrong },
	329,  { \worng },
	4,    { \wrnog },
	5000, { \wnorg },
	0,    { \true }
).postln;
)
::
or:
code::
(
var x, z;
z = [0, 7, 2, 329, 4, 5000].choose;
x = switch(z)
	{7}    { \no }
	{2}    { \wrong }
	{329}  { \worng }
	{4}    { \wrnog }
	{5000} { \wnorg }
	{0}    { \true };
x.postln;
)
::

subsubsection:: Inlined vs non-inlined comparison

The following code will inline, but will compare by identity:
code::
(
switch(1)
	{ 1.0 } { "yes" }
	{ "no" }
) // -> no
::

The identity comparison code::1 === 1.0:: returns false. 
While 1.0 and 1 represent the same numeric value, one is a Float and the other is an Integer, so they cannot be identical.
On the other hand, if we prevent inlining by declaring a variable within one of the functions, the code will compare by equality:
code::1 == 1.0:: returns true. 


code::
(
// 'var x' prevents inlining
switch(1)
	{ 1.0 } { var x; "yes" }
	{ "no" }
)  // -> yes
::


subsection:: while

The code::while:: method implements conditional execution of a loop; 
it is a method of link::Classes/Function::.
If the teletype::testFunc:: answers true when evaluated, 
then the teletype::loopFunc:: is evaluated and the process is repeated. 
Once the teletype::testFunc:: returns false, the loop terminates.

Note the distinction to code::if::: 
teletype::testFunc:: is a Function (which returns itself), e.g., code::{x < 0}::, 
whereas teletype::expr:: above was an expression, e.g., code::x < 0::, which returned a Boolean.

subsubsection:: Syntax
code::
// function call with receiver and argument as trailing function block
// this is _different_ from C!
while { testFuncBody } { loopFuncBody };
// abbreviation of:
while ({testFuncBody}) { loopFuncBody };
// but the following (C syntax) will not work in SuperCollider:
while (testFuncBody) { loopFuncBody } ; // Syntax Error

// function call without trailing argument.
while({ testFuncBody }, { loopFuncBody });

// receiver notation 
// hard to read and rarely used in practice 
{ testFuncBody }.while({ loopFuncBody });
::

subsubsection:: Example 

code::
(
i = 0;
while { i < 5 } { i = i + 1; "boing".postln };
)
::

code::while:: expressions are also optimized by the compiler if they do not contain variable declarations in the teletype::testFunc:: and the teletype::loopFunc::.

section:: Other Control Structures 

Conditional expressions are a type of control structures; another useful type are iterations such as code::.do:: and code::.for::. 
These are discussed separately in the page on link::Reference/loop##iteration:: (also see link::Classes/Collection#Iteration::).
Finally, the methods link::Classes/Function#-try:: and link::Classes/Function#-protect:: are technically conditional expressions, 
but their intended use is in the handling of exceptions, which is why their are discussed in link::Classes/Exception:: rather than here.

section:: Optimization through inline expansion

code::if::, code::while::, code::switch::, and code::case:: expressions are optimized (i.e., inlined) by the compiler if they do not contain variable declarations in the functions. 
We can see this if we dump the bytecodes of the receiver function definition. 
(Bytecodes are a lower-level representation of the code sent to the interpreter.) 
The optimization does not use function calls within the bytecodes and instead uses a jump statement, which is faster.

subsection:: Failure to inline: Functions include variable declaration.

code::
(
{
	if(6 == 9) {
		var notHere; // variable declaration 
		"hello".postln;
	} {
		"world".postln;
	}
}.def.dumpByteCodes
)
::

This returns the following warning,footnote::
You can switch on and off the above warning (see: link::Classes/LanguageConfig#*postInlineWarnings::):
code::
LanguageConfig.postInlineWarnings_(true) // warn
LanguageConfig.postInlineWarnings_(false) // ignore it.
::
::
and below it we can see what the bytecodes look like without inlining:

teletype::
WARNING: FunctionDef contains variable declarations and so will not be inlined.
  in file 'selected text'
  line 4 char 14:

  		var notHere;

  		"hello".postln;
-----------------------------------
BYTECODES: (13)
  0   2C 06    PushInt 6
  2   2C 09    PushInt 9
  4   E6       SendSpecialBinaryArithMsg '=='
  5   04 00    PushLiteralX instance of FunctionDef - closed
  7   04 01    PushLiteralX instance of FunctionDef - closed
  9   B0       TailCallReturnFromFunction
 10   C3 0B    SendSpecialMsg 'if'
 12   F2       BlockReturn
-> < closed FunctionDef >
::

That is, entries 5 and 7 are proper function calls, which are costly (i.e., slow/inefficient).

subsection:: Successful inlining: Functions do not include variable declarations.

Here is the opposite example, where inlining has taken place:

code::
(
{
	if(6 == 9) {
		"hello".postln;
	} {
		"world".postln;
	}
}.def.dumpByteCodes
)
::

The bytecodes read as follows:
teletype::
BYTECODES: (20)
  0   2C 06    PushInt 6
  2   2C 09    PushInt 9
  4   E6       SendSpecialBinaryArithMsg '=='
  5   F8 00 07 JumpIfFalse 7  (15)
  8   41       PushLiteral "hello"
  9   B0       TailCallReturnFromFunction
 10   C1 3A    SendSpecialMsg 'postln'
 12   FC 00 04 JumpFwd 4  (19)
 15   40       PushLiteral "world"
 16   B0       TailCallReturnFromFunction
 17   C1 3A    SendSpecialMsg 'postln'
 19   F2       BlockReturn
-> < closed FunctionDef >
::
Entries 5 and 12 are jump statements, instructing to jump to entries 15 and 19 respectively.  
In between those lines, we can recognize the contents of the two Functions, 
but they are now no longer implemented as function calls, but as direct instructions, which saves resources.


section:: Audio Control Structures: Do not use .if etc. in Synths!

The control structures discussed here is intended for use in sclang (i.e., language/client), not in scsynth (i.e., server). 
Use of .if in signal processing contexts may appear to work in simple cases but is strong::not advised::. 
Intead, use link::Classes/Select:: or link::Classes/SelectX:: and related classes.
Also see link::Guides/UserFAQ#SynthDef Issues:: for more details.

The following code runs (does not produce an error), but is strong::not good usage::,
because it is not very obvious what is going on: 
code::
(
	var freq = 100;
    {
        if(LFTri.kr(0.1).unipolar, //receiver is a UGen. 
			SinOsc.ar(freq), //as are arguments
			Saw.ar(freq)
		) * 0.2;
    }.scope(bufsize: s.sampleRate/freq; //bufsize to match the period of the oscillators
)
::
Here, the receiver LFTri is a UGen. 
The UGen class in turn implements an link::Classes/UGen#-if:: method by translating it into a linear crossfade using binary operators:

code::
	if { arg trueUGen, falseUGen;
		^(this * (trueUGen - falseUGen)) + falseUGen;
	}
::

The regular link::Classes/Boolean#-if:: discussed above does emphasis::not:: crossfade. 
Hence, if the crossfade is desired, it is better practice to make this explicit by using link::Classes/LinSelectX::: 

code::
(
	var freq = 100;
    {
        LinSelectX.ar(
			LFTri.kr(0.1).unipolar, 
			[SinOsc.ar(freq), Saw.ar(freq)]
		) * 0.2;
    }.scope(bufsize: s.sampleRate/freq); 
)
::

On the other hand, in the case where not a crossfade but a simple either/or analogous to language-side code::Boolean.if:: is desired, link::Classes/Select:: is preferable:

code::
(
	var freq = 100;
    { Select.ar(
		LFPulse.ar(1), 
		[SinOsc.ar(freq), Saw.ar(freq)]
		) * 0.2;
	}.scope(bufsize: s.sampleRate/freq);
)
::  

section:: Syntax of conditional expressions

In SuperCollider, control structures implemented as strong::methods to be called on a receiver and which return a value::.
This is distinct from many other languages where, e.g., code::if:: is a reserved
identifier (keyword) independent of a particular receiver, and does not return a value. 
For instance, in C or in python, you cannot create a variable called code::if::, whereas in SuperCollider, you can (which does not mean that you should...).
In SuperCollider, it is also possible to implement an code::.if:: method for a particular class that does something rather different
(see link::#Audio Control Structures: Do not use .if etc. in Synths!#below::);
despite these differences, SuperCollider's flexible syntax can make it emphasis::look:: as if code::if:: were just such a reserved identifier, 
whereas it is in fact a method of link::Classes/Boolean::.

Thus, SuperCollider's link::Reference/Syntax-Shortcuts##flexibility with respect to syntax:: is a potentially confusing factor when it comes to conditional expressions. 
For instance, there are four equivalent ways to write a simple if-expression:

table::
	##                           || Receiver notation || Function call notation
    ## Regular argument notation ||  code:: condition.if(trueFunc, falseFunc):: || code::if(condition, trueFunc, falseFunc)::
    ## Argument(s) as trailing blocks || code:: condition.if { trueFuncBody } { falseFuncBody }:: || code::if(condition) { trueFuncBody } { falseFuncBody }::
::

While the receiver notation reflects the implementation in SuperCollider most closely, it is hard to read and rarely used in practice. 
The two function call notations are the most commonly used. 
The version with trailing argument blocks superficially resembles conditional syntax familiar from C or javascript:

teletype::
//if-statement in C or javascript:
if (condition) { 
	trueFuncBody
} else { 
	falseFuncBody
}
::

code::
//if-statement in SuperCollider, function call notation with trailing argument block 
if (condition) { 
	trueFuncBody
} {  //no "else" in SuperCollider!
	falseFuncBody
}
::

subsection:: Trailing argument blocks

The above C-like syntax is enabled in SuperCollider by a syntactic mechanism called "trailing argument blocks". 
A strong::block:: is any expression enclosed in curly brackets, e.g. code:: { trueFuncBody } ::. 
The syntax code::receiver.method { expr1 } { expr2 }:: is equivalent to code::receiver.method({ expr1 }, { expr2 })::. 
That is, the round brackets and comma are omitted. 
This can be combined with the function call syntax such that we can write code::method(receiver) { expr1 } { expr2 }::; 
this in turn gives the above form of the if-statement in function call notation with trailing argument block. 

However, even if the curly brackets now indicate where one argument ends and where the next one starts, 
they also retain their usual role of showing that the enclosed expression should serve as the definition of a link::Classes/Function:: instance.  

This means, strong::first::, that the use of trailing argument syntax implies that teletype::expr1:: and teletype::expr2:: emphasis::define:: Functions;
strong::second::, that teletype::expr1:: and teletype::expr2:: should not
already emphasis::be:: Functions in their own right (unless you intend them to be). 

In examples:
code::
if(condition, trueFunc, falseFunc)
// is NOT equivalent to
if (condition) {
    trueFunc //trueFunc is distinct from trueFuncBody above!
} {
    falseFunc //similarly here
}
// however, when we write
t = { trueFuncBody };
f = { falseFuncBody };
// then indeed the following two expressions are equivalent
// (though only the latter will inline):
if(condition, t, f);
if (condition) {
    trueFuncBody 
} {
    falseFuncBody
}
// On the other hand, the following cases are either wrong
// or do different things than if(condition, t, f)
if(condition) t f; //Syntax Error:
//    there are no curly brackets here that could indicate that t and f are arguments to if;
if(condition) {t} {f}; //permissible but it may not be what you want to do.
// equivalent to if(condition, {t}, {f});
// i.e.will return t rather than t.value as usually intended.
if(condition, trueFuncBody, falseFuncBody); // the bodies are expressions, not Function objects;
// whether this works depends on how those expressions respond to the .value method.
::

subsubsection:: Receiver blocks (.case, .while)

If the receiver is itself an expression surrounded by curly brackets, a special version of the trailing argument block syntax can be used:
Here, not only the arguments can be written as trailing {}-enclosed blocks, but also the receiver itself.
For instance, code::{ funcBody }.fork:: is often written as code::fork { funcBody }::.

When the method takes arguments, these arguments must also be written as {}-enclosed blocks, and follow the receiver:

code:: method { receiverFuncBody } { arg1FuncBody }  { arg2FuncBody }::

Among the conditional expressions discussed here, this applies to .while and .case (because they are methods of link::Classes/Function::.)

Example:
code::
//function call notation with receiver block and trailing argument block
while { testFuncBody } { loopFuncBody }; 
// abbreviation of  function call notation with trailing argument block
while ({ testFuncBody }) { loopFuncBody };
// in receiver notation
{ testFuncBody }.while({ loopFuncBody })
// distinct from C-style while, which will not work in SuperCollider:
while (testFuncBody) { loopFuncBody }; // -> Syntax Error
::

subsubsection:: Return values (.if, .case, .switch)

Unlike other common programming languages, conditional expressions (code::.if::, code::.case::, and code::.switch::) in SuperCollider have return values by default;
these in turn can be assigned to variables. 
For instance, in python, the following will produce an error:
teletype::
a = if True: "gobbledeegook"
:: 
and for conditional assignment, one has to write
teletype::
if True: a = "gobbledeegook" 
::
Whereas in SuperCollider, both analogous cases work:
code::
(
var a = "oink"
a = if([true,false].choose, {"gobbledeegook"});
a.postln;
)

( 
var a = "oink";
    if([true,false].choose, {a = "gobbledeegook"});
a.postln;
)
::

However, this does not change the syntactic requirement that the assignment
statement, when it is an argument to a conditional expression, must be a
Function. In other words, the following is wrong:
code::
 ( 
var a = "oink";
    if([true,false].choose, a = "gobbledeegook"); //syntax error
a.postln;
)
::
This is because a Function is expected after the comma in code::if(expr, arg)::.
