Execution
What happens when your program runs: how numbers behave, how memory is managed, the limits you can hit, and what is and isn't deterministic.
int big = 9223372036854775807;
int wrapped = big + 1; // wraps to -9223372036854775808
int q = 7 / -2; // -3: integer division rounds toward zero
float inf = 1.0 / 0.0; // Infinity, no error
int hits = 3;
int misses = 0;
int r = hits / misses; // traps: misses is 0
Running a program
Before anything runs, the whole program is checked. Any compile error in any
loaded file stops it from starting. Then the host starts an
entry point (gameMain, uiMain or main).
Your scripts behave the same whether they are interpreted, translated to machine code as they load (JIT), or compiled ahead of time into the game executable (AOT) (see deployment modes); only speed and start-up time differ. Debug builds behave the same too, but run slower so that stepping matches your source.
A running program cannot be changed in place. To pick up script changes, the host recompiles and restarts the program.
Numeric semantics
int
- Signed 64-bit.
+,-,*and unary-wrap around on overflow./rounds toward zero:7 / -2 == -3,-9 / 2 == -4.%takes the sign of the left operand:-7 % 3 == -1./and%by zero trap. So does dividing the minimumintby-1.
int32
- Signed 32-bit.
+,-,*,/and unary-wrap around on overflow, including the minimumint32divided by-1./and%by zero trap.
byte
Values 0 to 255. Arithmetic on bytes gives an int. Storing an int in a
byte takes byte(x), which keeps the low 8 bits (byte(300) is 44).
float
- 64-bit double precision with standard IEEE 754 rounding.
- Never traps: dividing by zero gives infinity,
0.0 / 0.0gives NaN, and NaN carries through further maths. The literalsNaNandInfinityname these values directly. %doesn't work on floats; usefmodorremainderfrommath.mathfunctions never fail; they return NaN or infinity where the maths requires. Functions such assinandexpmay differ in the last digit between Windows and Linux.- Integers above 2^53 lose precision when converted to
float.
float32
- 32-bit single precision with standard IEEE 754 rounding; otherwise the same
rules as
float. - A
mathcall whose float arguments are allfloat32returnsfloat32.
Memory
- Memory is automatic. There is no manual allocation or freeing and there are no pointers.
- Objects, arrays, maps, strings and the like are freed by a garbage collector once nothing refers to them, including objects that only refer to each other in a cycle.
- There are no destructors and you can't tell when something is freed.
Close files, sockets and processes explicitly; use
&& { ... }so cleanup always runs. - A slice keeps its whole array alive; a task keeps the objects it uses alive until it finishes; a channel keeps its queued values alive.
- Running out of memory traps.
Limits
| Limit | Value | If you hit it |
|---|---|---|
| Values a single function can hold at once (parameters, locals, temporary results and distinct constants) | 255 | function 'NAME' needs more than 255 frame slots .... Split the function into smaller ones. |
| Nesting depth of brackets, blocks and operators | 256 | nesting is too deep (limit 256). Move inner parts into helper functions. |
| Recursion depth | Grows as needed, up to a share of system memory | Trap -3. Use a loop or an explicit stack. |
| Integer literal | 9223372036854775807 | integer literal ... is out of range |
| Array, map and buffer size | int, bounded by memory | Out of memory traps. |
Determinism
You can rely on:
- left-to-right evaluation (see Evaluation order);
selectchoosing the earliest ready arm;- first-in, first-out order in channels and
Mutex; - map reads and writes behaving the same from run to run.
You cannot rely on:
- the order in which tasks interleave or which ready task runs first;
- the order in which a
for ... inloop visits a map's keys; - when memory is freed.
Timers, file and network I/O, and engine events come from outside the
program. If your result must be the same every run, order dependent work with
join, channels or a Mutex rather than relying on timing.