Expressions & Databinding
Anything between curly braces is an expression: {total * 2}. Quantum evaluates it against the variables in scope and puts the result in place.
Every example on this page runs as shown — tests/docs executes each block and compares it with the Output below it.
A value, or text with values in it
When an attribute is exactly one expression, you get the value with its type. When there is anything else around it, you get text:
<q:component name="Order" xmlns:q="https://quantum.lang/ns">
<q:set name="price" value="9.5" type="number" />
<q:set name="qty" value="3" type="number" />
<q:return value="{price * qty}" />
</q:component>Output: 28.5
<q:component name="Summary" xmlns:q="https://quantum.lang/ns">
<q:set name="price" value="9.5" type="number" />
<q:set name="qty" value="3" type="number" />
<q:return value="{qty} items, total {price * qty}" />
</q:component>Output: "3 items, total 28.5"
Operators
| Kind | Operators |
|---|---|
| Arithmetic | + - * / // (integer division) % ** |
| Comparison | == != < <= > >= in not in |
| Logic | and or not — or && || ! |
| Choice | value if condition else other |
Values that arrive as text — a form field, a query parameter, a tool argument from an LLM — are treated as numbers when they look like numbers, so + adds:
<q:component name="Sum" xmlns:q="https://quantum.lang/ns">
<q:set name="a" value="17" />
<q:set name="b" value="25" />
<q:return value="{a + b}" />
</q:component>Output: 42
<q:component name="Age" xmlns:q="https://quantum.lang/ns">
<q:set name="age" value="20" type="number" />
<q:set name="invited" value="false" type="boolean" />
<q:return value="{'enters' if age >= 18 && !invited else 'waits'}" />
</q:component>Output: "enters"
in compares the way == does, so a value that arrived as text still finds its number in a list:
<q:component name="Member" xmlns:q="https://quantum.lang/ns">
<q:set name="chosen" value="5" />
<q:set name="allowed" value="[1, 5, 10]" type="array" />
<q:return value="{chosen in allowed}" />
</q:component>Output: true
Reading lists and records
<q:component name="Reading" xmlns:q="https://quantum.lang/ns">
<q:set name="user" type="object" value='{"name": "Ana", "tags": ["admin", "dev"]}' />
<q:return value="{user.name} has {user.tags.length} tags, first {user.tags[0]}, last {user.tags[-1]}" />
</q:component>Output: "Ana has 2 tags, first admin, last dev"
true, false and null are literals. Strings use single quotes inside a double-quoted attribute: {status == 'active'}.
Functions
| Function | Example | Result |
|---|---|---|
upper(s), lower(s), trim(s) | upper('ana') | ANA |
replace(s, old, new) | replace('a-b', '-', '+') | a+b |
split(s, sep=',') | split('a,b') | ['a', 'b'] |
contains(s, part) | contains('quantum', 'ant') | true |
len(x), first(x), last(x) | len(items) | number of items |
join(list, sep=', '), sort(list) | join(sort(tags), ' / ') | text |
round(n, digits=0) — halves away from zero | round(2.5) | 3 |
ceil(n), floor(n), abs, min, max | ceil(7 / 3) | 3 |
int(x), float(x), str(x) | int('42') | 42 |
now() | now() | current date and time |
dateAdd(unit, n, start=now) | dateAdd('d', 7) | a week from now |
dateDiff(unit, start, end) | dateDiff('h', a, b) | whole hours |
dateFormat(date, pattern) | dateFormat(now(), '%d/%m/%Y') | 10/09/2026 |
hashPassword(s), verifyPassword(s, hash) | see Authentication | |
random(), random(a, b) | random(1, 6) | a number from 0 up to 1; an integer from a to b |
chance(p), pick(list) | pick(tips) | true with probability p; one element |
Units for the date functions: s, n (minutes), h, d, w. A q:function declared in the component is called the same way: {twice(price)}.
Functions are called by name, never as methods: split(title, ' '), not title.split(' '); ceil(n), not Math.ceil(n). The error for a JavaScript habit names the function to use. .length works on text and lists.
<q:component name="Functions" xmlns:q="https://quantum.lang/ns">
<q:function name="twice">
<q:param name="x" type="number" />
<q:return value="{x * 2}" />
</q:function>
<q:set name="tags" value='["dev", "admin"]' type="array" />
<q:return value="{upper(join(sort(tags), ' / '))} {twice(21)}" />
</q:component>Output: "ADMIN / DEV 42"
Scoped variables
session., application., request., form., query. and cookie. read from their scope. A page often renders before the value exists — before login, say — so reading one that is not set gives empty text:
<q:component name="Hello" xmlns:q="https://quantum.lang/ns">
<q:return value="[{session.name}]" />
</q:component>Output: "[]"
Doing arithmetic with a value that is not set is an error, not an empty result. For a counter, use operation="increment", which starts from zero:
<q:component name="Visits" xmlns:q="https://quantum.lang/ns">
<q:set name="session.visits" operation="increment" />
<q:return value="{session.visits}" />
</q:component>Output: 1
When an expression fails
In a q: attribute, an expression that cannot be evaluated stops the component with an error that names it — nothing is silently replaced:
<q:component name="Broken" xmlns:q="https://quantum.lang/ns">
<q:set name="total" value="3" type="number" />
<q:return value="{totl + 1}" />
</q:component>Error: {totl + 1} could not be evaluated: variable 'totl' is not defined, did you mean 'total'?
The same holds for a failed evaluation ({10 / zero}) and for arithmetic on a scoped value that is not set.
Two places are deliberately more forgiving:
- Conditions test for presence. A name, key or attribute that does not exist makes a
conditionfalse, so<q:if condition="flash">works before there is a flash message. Anything else — a syntax error, a function that does not exist — is still an error. - HTML content keeps the text. An expression in page content that does not resolve is rendered as written and logged once. Page content also holds code samples and stray braces, and those must not break the page.
<q:component name="Presence" xmlns:q="https://quantum.lang/ns">
<q:if condition="flash">
<q:return value="there is one" />
</q:if>
<q:return value="there is none" />
</q:component>Output: "there is none"
Braces that are not expressions
A JSON object and a regular-expression quantifier are left alone:
<q:component name="Literals" xmlns:q="https://quantum.lang/ns">
<q:set name="pattern" value="[0-9]{10,11}" />
<q:set name="rows" value='[{"a": 1}, {"b": 2}]' type="array" />
<q:return value="{pattern} {len(rows)}" />
</q:component>Output: "[0-9]{10,11} 2"
Reference
The rules on this page are EXPR-1 to EXPR-5 in SPEC.md.