Expressions
Expressions calculate values inside String and Number inputs. They read declared variables and fields; they do not replace the visual editor’s methods, conditions, or loops.
String interpolation
Section titled “String interpolation”A String can mix normal text with any number of expressions:
Score: ${private.score}, doubled: ${private.score * 2}Hello, ${private.playerName}!If score is 7, the first String becomes Score: 7, doubled: 14. The result of each expression is converted to text, while surrounding spaces and punctuation remain as entered. Null prints as null. Number display removes unnecessary trailing decimal zeros.
Enter this text into a String item’s dialog or an inline String argument. Compile the draft after changing the argument.
Number expressions
Section titled “Number expressions”A Number input must consist of one complete expression, optionally surrounded by whitespace:
${private.score * 2}${(private.base + environment.bonus) / 2}${save.bestScore ?? 0}The result must be a non-null Number. Score: ${private.score} is valid as a String but invalid as a Number. Bare arithmetic such as 2 + 3 is not Number-expression syntax; enter ${2 + 3}.
Declare names before using them
Section titled “Declare names before using them”Create typed Variable declarations first. For example, declare Private Number score, assign it 7, then use ${private.score * 2}. Writing a name in an expression does not declare or assign it.
| Form | Meaning |
|---|---|
score |
Current routine’s Private score |
private.score |
Explicit Private binding |
public.round |
Shared Public binding |
save.bestScore |
Persistent Save binding |
environment.bonus |
Live read-only setting |
private.stats.points |
Field points on the custom object in stats |
Field access follows class visibility and type rules. An unassigned field still needs initialization or a fallback. Expressions cannot bypass Private/Protected restrictions.
Identifiers begin with a letter, _, or $, followed by letters, digits, _, or $. Unicode letters/numbers are supported by the identifier check. Dots separate scopes and fields. Names containing spaces remain usable through Variable items; rename an expression-facing binding if necessary. Preserve capitalization consistently.
Arithmetic and precedence
Section titled “Arithmetic and precedence”| Priority, highest first | Operators | Behavior |
|---|---|---|
| Grouping | ( ... ) |
Evaluate the grouped expression |
| Power/unary | ^, unary +, unary - |
Powers associate right; unary signs enclose a power expression |
| Multiplication | *, /, % |
Multiply, divide, remainder |
| Addition | +, - |
Add/subtract; String concatenation for + |
| Fallback | ?? |
Lazy null/unassigned fallback; associates right |
${2 ^ 3} is 8. Use ^ for exponentiation; ** is no longer accepted.
${2 + 3 * 4} is 14; ${(2 + 3) * 4} is 20; ${2 ^ 3 ^ 2} is 512. ${-2 ^ 2} is -4; use ${(-2) ^ 2} for 4. Parentheses make mixed signs/powers easier to read.
Division by zero and non-finite results report errors rather than producing Infinity or NaN. Remainder is not a guarantee of a nonnegative mathematical modulo for negative inputs.
Text and constants
Section titled “Text and constants”Quoted Strings may use single or double quotes inside an expression:
${'Round ' + public.round}${"Score: " + (private.score + 1)}If either operand of + is a String, it joins text. Otherwise arithmetic requires Numbers. '5' + 2 produces text 52, not Number 7. String escape sequences include \n, \t, and \r; a backslash can escape a quote. Number constants support decimal/scientific notation. true, false, and null are constants, but they do not make a valid non-null Number result by themselves.
Null and unassigned fallback
Section titled “Null and unassigned fallback”${save.bestScore ?? 0}${private.nickname ?? 'Guest'}?? evaluates its fallback only when the primary is null or unassigned. It does not change the primary binding. An undeclared name remains a declaration/type error; declare it first. Division errors, invalid field access, and other failures are not hidden by fallback.
Both branches must have compatible types. Coalescing a nullable Number with 0 can supply a non-null Number. Coalescing it with a String is not a way to silently change its declared type.
Literal expression text
Section titled “Literal expression text”Escape the opening marker in a String:
Write \${private.score} to show the syntax.The displayed text contains ${private.score} instead of evaluating it. Escaping the only marker in a Number does not produce a Number expression.
Supported boundaries
Section titled “Supported boundaries”Expressions support the operators above, names, fields, constants, and grouping. They do not support method calls, Java/JavaScript APIs, arbitrary script execution, collection indexing syntax, comparisons such as >, or Boolean operators such as &&. Use visual If blocks and the operation reference for those tasks.
Current bounds include 32,768 input characters, 32,768 output characters, 64 parser nesting levels, 1,024 expression nodes, and an 8,192-step evaluation allowance. Particular input dialogs can impose smaller limits (the common text form is capped at 8,192 characters). Plot execution budgets also apply. Resource-limit failures cannot be treated as ordinary catchable expression errors.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Check |
|---|---|
| Undeclared expression variable | Create the typed binding; check scope and spelling |
| Variable/field is unassigned | Assign it first or use a compatible fallback |
| Number expression must produce a non-null Number | Remove surrounding text, fix types, coalesce nullable values |
| Unclosed expression | Close } and any quoted String |
| Unexpected syntax | Remove unsupported calls/operators; check parentheses |
| Old value still appears | Compile the draft; check the active build and scope |
See the compact syntax reference, fields, and environment settings.