Expressions and operators
| Precedence | Operators | Operands | Result |
|---|---|---|---|
| 1 (tightest) | not, unary - |
Bool; a number |
same |
| 2 | *, /, % |
* and % may mix named types; / needs the same named type: Int drops the remainder, Decimal is exact |
Int, or Decimal if either side is Decimal |
| 3 | +, - |
the same named type after widening, or a literal; + also joins two Text values |
as above |
| 4 | <, <=, >, >= |
two numbers or two time values of the same named type; text has no order | Bool |
| 5 | ==, != |
two values of the same type after widening, or a nullable value and none |
Bool |
| 6 | and |
Bool |
Bool |
| 7 (loosest) | or |
Bool |
Bool |
"Widening" is one type standing in for another it is built on (When one type can stand in for another).
Adding two values needs the same type on each side, and multiplying may mix them, because multiplying a price by a quantity means something and adding them doesn't:
var wrong: Stock = Stock(per_pack + packs)var line: Stock = Stock(per_pack * packs)var earlier: Bool = name < other_namevar share: ItemPrice = decimal.divide(total, people, rounding: Rounding.half_even)var boxes: BoxCount = integer.divide(items, box_size, rounding: Rounding.up)
per_pack + packsis an error: it adds aQuantityto aStock.per_pack * packsis fine: it multiplies different units.name < other_nameis an error: text has no order, because the order depends on the language. Sort text withlist.sort_byand a text key.decimal.divideandinteger.dividedivide values of different types, or round another way, with the rounding you name.box_size's type excludes zero. A divisor's type must, so dividing by zero is ruled out while compiling (type.divisor_zero).
In +, - and /, a literal takes the other side's type, exactly as it
does in ==. So price + 3 with a Decimal price is an error, as
price == 3 is: write 3.00. + joins two Text values only when they
are the same named type after widening, or one is a literal, as ==
compares them. * and % still mix.
Operators work on the built-in type a named type is built on, so the
result is a plain Int, Decimal, Text or Bool. To turn it back into
a named type, construct it: Stock(total + holdback)
(Creating values). Brackets
group. and and or stop as soon as the answer is known. a < b < c is
an error, because a < b is a Bool.
Logical operators are words. !, && and || are not Jadpo, and each is
one error whose edit writes the word (syntax.logical_operator). Nor are
=== and !==: == and != already compare values of one type, so each
is one error whose edit writes == or != (syntax.equality_operator).
So are SQL's <>, = and IS NULL
(Habits from other languages).
Operators on standard types, such as price * 20% or distance / 2h,
follow the standard operator table.
Anything in neither that table nor the one above is a compile error naming
the two types. 20% is a Percentage literal. The remainder operator
keeps % with spaces round it, as the formatter writes every binary
operator, and 20%3 is syntax.percent_ambiguous, naming both readings.
Rounding.down rounds toward zero (Numbers).
Markdown for agents: /docs/expressions-and-operators.md.Built from Jadpo main at a707efb.