Control flow
Forms that compile (23)
Section titled “Forms that compile (23)”| Syntax | Description |
|---|---|
if / else | Branch on a condition |
switch (n) { case 1: ... } | Branch on a value (statement) |
n switch { 1 => 10, _ => 0 } | Branch on a value (expression) |
n switch { var v when v > 0 => 10, _ => 0 } | Case with a condition |
n > 0 ? 10 : 20 | Conditional operator |
while (n < 3) | Loop while a condition holds |
do { ... } while (n < 3); | Loop with the check after the body |
for (int i = 0; i < 3; i++) | Loop a fixed number of times |
for (int i = 0, j = 3; i < j; i++, j--) | Loop with multiple variables |
foreach (int v in a) | Iterate over an array |
foreach (var (a, b) in ps) | Deconstruct while iterating |
for { for { } } | Nested loops |
break | Exit a loop |
continue | Continue to the next iteration |
while (true) { ... break; } | Exit an infinite loop |
if (...) { return; } | Return partway through |
{ … } | Block |
; | Empty statement |
const int a = 1; | Local constant |
int Twice(int x) { return x * 2; } | Local function |
static int Twice(int x) { … } | static local function |
for (;;) | Omitting parts of a for |
return; | Return without a value |
Forms that don’t compile (17)
Section titled “Forms that don’t compile (17)”| Syntax | Description | Error | Reason | Instead |
|---|---|---|---|---|
goto top; | Jump to a label | TUKI0001, TUKI0099 | by design | Rewrite with a loop |
goto case c; / goto default; | Jump to another switch case | TUKI0001 | by design | Move the shared logic into a method and call it from both case blocks |
L: stmt | Put a label on a statement | TUKI0099 | by design | There’s no goto, so rewrite without a label |
throw new Exception(); | Throw an exception | TUKI0001, TUKI0101 | runtime | Represent failure with a return value or state |
try { } catch { } | Catch an exception | TUKI0001 | runtime | Check the condition beforehand |
catch (…) when (…) | Catch an exception conditionally | TUKI0001 | runtime | Same as above |
try { } finally { } | Run cleanup whether or not an exception occurred | TUKI0001 | runtime | Write the cleanup at the end of the block |
using (r) { … } | Clean up when leaving a scope | TUKI0001 | not yet | Call the cleanup method yourself (there’s no finally, so it won’t run if you leave early) |
using var r = …; | Let the declared variable’s cleanup happen automatically | TUKI0001, TUKI0099 | not yet | Same as above |
yield return / yield break | Return values one at a time | TUKI0001, TUKI0099 | runtime | Pack them into an array and return it |
p switch { (1, 2) => … } | Deconstruct by position in a case | TUKI0001 | not yet | Write { Item1: 1, Item2: 2 }, or read the elements and compare them |
void Bump() { n = n + 1; } (writes back to an outer variable) | Rewrite an outer variable from a function inside a method | TUKI0001 | undecided | Return it as a value and let the caller assign it (a function that only reads the value can be written) |
ref int r = ref a; | Give a variable an alias | TUKI0001 | undecided | Assign the value and use it |
lock (o) { … } | Do mutual exclusion | TUKI0001 | runtime | There’s only one thread of execution, so it isn’t needed |
async Task Go() { await ...; } | Await asynchronously | TUKI0001, TUKI0101 | runtime | Use a mechanism that calls back after a delay |
n switch { 1 => 10, 2 => 20 } | Branch without a default case | TUKI0001 | by design | Always include _ =>. It can only be omitted for a union |
foreach (var (a, b) in ps) (a type with a hand-written Deconstruct) | Use your own hand-written deconstruction | TUKI0001 | by design | Read the fields by name |
Branching and loops
Section titled “Branching and loops”Branch on a condition
Section titled “Branch on a condition”using UnityEngine;using Tsukimi;
public class ExpressionsIfElse : TsukimiBehaviour{ void Start() { int n = 1; if (n > 0) { n = 2; } else { n = 3; } Debug.Log(n); // => 2 }}Branch on a value (statement)
Section titled “Branch on a value (statement)”using UnityEngine;using Tsukimi;
public class ExpressionsSwitchStatement : TsukimiBehaviour{ void Start() { int n = 1; switch (n) { case 1: n = 10; break; default: n = 0; break; } Debug.Log(n); // => 10 }}Branch on a value (expression)
Section titled “Branch on a value (expression)”A _ => case is required. Even if the cases cover every value, it can’t be omitted for int or an enum. It can only be omitted for a union.
using UnityEngine;using Tsukimi;
public class ExpressionsSwitchExpression : TsukimiBehaviour{ void Start() { int n = 1; int r = n switch { 1 => 10, _ => 0 }; Debug.Log(r); // => 10 }}Case with a condition
Section titled “Case with a condition”Writing when selects the case only when the pattern matches and the condition is true. It can’t be written on a case in a switch statement.
using UnityEngine;using Tsukimi;
public class ExpressionsSwitchArmWhen : TsukimiBehaviour{ void Start() { int n = 1; int r = n switch { var v when v > 0 => 10, _ => 0 }; Debug.Log(r); // => 10 }}Conditional operator
Section titled “Conditional operator”using UnityEngine;using Tsukimi;
public class ExpressionsTernary : TsukimiBehaviour{ void Start() { int n = 1; int r = n > 0 ? 10 : 20; Debug.Log(r); // => 10 }}Loop while a condition holds
Section titled “Loop while a condition holds”using UnityEngine;using Tsukimi;
public class ExpressionsWhile : TsukimiBehaviour{ void Start() { int n = 0; while (n < 3) { n++; } Debug.Log(n); // => 3 }}Loop with the check after the body
Section titled “Loop with the check after the body”using UnityEngine;using Tsukimi;
public class ExpressionsDoWhile : TsukimiBehaviour{ void Start() { int n = 0; do { n++; } while (n < 3); Debug.Log(n); // => 3 }}Loop a fixed number of times
Section titled “Loop a fixed number of times”using UnityEngine;using Tsukimi;
public class ExpressionsFor : TsukimiBehaviour{ void Start() { int total = 0; for (int i = 0; i < 3; i++) { total += i; } Debug.Log(total); // => 3 }}Loop with multiple variables
Section titled “Loop with multiple variables”using UnityEngine;using Tsukimi;
public class ExpressionsForMultiInit : TsukimiBehaviour{ void Start() { int count = 0; for (int i = 0, j = 3; i < j; i++, j--) { count++; } Debug.Log(count); // => 2 }}Iterate over an array
Section titled “Iterate over an array”foreach can only iterate over an array. The runtime has no enumerator.
using UnityEngine;using Tsukimi;
public class ExpressionsForeachArray : TsukimiBehaviour{ void Start() { int[] a = new int[] { 1, 2 }; int total = 0; foreach (int v in a) { total += v; } Debug.Log(total); // => 3 }}Deconstruct while iterating
Section titled “Deconstruct while iterating”using UnityEngine;using Tsukimi;
public class ExpressionsForeachDeconstruct : TsukimiBehaviour{ void Start() { (int, int)[] ps = { (1, 2) }; foreach (var (a, b) in ps) { Debug.Log(a + b); } // => 3 }}Nested loops
Section titled “Nested loops”using UnityEngine;using Tsukimi;
public class ExpressionsNestedLoop : TsukimiBehaviour{ void Start() { int count = 0; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { count++; } } Debug.Log(count); // => 4 }}Exit a loop
Section titled “Exit a loop”using UnityEngine;using Tsukimi;
public class ExpressionsBreak : TsukimiBehaviour{ void Start() { int count = 0; for (int i = 0; i < 5; i++) { if (i == 2) { break; } count++; } Debug.Log(count); // => 2 }}Continue to the next iteration
Section titled “Continue to the next iteration”using UnityEngine;using Tsukimi;
public class ExpressionsContinue : TsukimiBehaviour{ void Start() { int count = 0; for (int i = 0; i < 5; i++) { if (i == 2) { continue; } count++; } Debug.Log(count); // => 4 }}Exit an infinite loop
Section titled “Exit an infinite loop”while (true) keeps running without evaluating a condition. Exiting it needs a break in the body.
using UnityEngine;using Tsukimi;
public class ExpressionsWhileTrueBreak : TsukimiBehaviour{ void Start() { int n = 0; while (true) { n++; if (n > 2) { break; } } Debug.Log(n); // => 3 }}Return partway through
Section titled “Return partway through”using UnityEngine;using Tsukimi;
public class ExpressionsReturnEarly : TsukimiBehaviour{ private int Level() { return 1; }
void Start() { Debug.Log(1); if (Level() > 0) { return; } Debug.Log(2); }}
// Output// 1Statement building blocks
Section titled “Statement building blocks”using UnityEngine;using Tsukimi;
public class StBlock : TsukimiBehaviour{ void Start() { { int a = 1; Debug.Log(a); // => 1 } }}Empty statement
Section titled “Empty statement”using UnityEngine;using Tsukimi;
public class StEmpty : TsukimiBehaviour{ void Start() { ; Debug.Log(1); // => 1 }}Local constant
Section titled “Local constant”using UnityEngine;using Tsukimi;
public class StLocalConst : TsukimiBehaviour{ void Start() { const int a = 1; Debug.Log(a); // => 1 }}Local function
Section titled “Local function”A function can be declared inside a method. It can read outer variables, but can’t write back to them (Forms that don’t compile).
using UnityEngine;using Tsukimi;
public class StLocalFunc : TsukimiBehaviour{ void Start() { int Twice(int x) { return x * 2; } Debug.Log(Twice(2)); // => 4 }}static local function
Section titled “static local function”using UnityEngine;using Tsukimi;
public class StLocalFuncStatic : TsukimiBehaviour{ void Start() { static int Twice(int x) { return x * 2; } Debug.Log(Twice(2)); // => 4 }}Omitting parts of a for
Section titled “Omitting parts of a for”using UnityEngine;using Tsukimi;
public class StForOmitted : TsukimiBehaviour{ void Start() { int i = 0; for (;;) { i++; if (i > 2) break; } Debug.Log(i); // => 3 }}Return without a value
Section titled “Return without a value”using UnityEngine;using Tsukimi;
public class StReturnVoid : TsukimiBehaviour{ void Start() { Debug.Log(1); // => 1 return; }}