Getting Started with EK9 · Appendix A

The Operator Reference

The Using Operators chapter grouped EK9's operators by the job they do. This appendix lists the whole set in one place, for looking things up.

The Default? column says whether the compiler can write the operator for you. A $\checkmark$ means you may ask for it by name with default operator <symbol>, or get it along with all the others from the blanket default operator. Everything else is yours to write, because it carries a decision the compiler cannot guess. The defaultable set is small, and deliberately so: comparing, checking, converting, hashing and copying are mechanical; adding, merging and promoting are not.

Comparing is special. A type decides its sameness once: <=> if it can be ordered, or == if it can only be told equal or not. The compiler then generates the rest of the family from it — from <=> it writes ==, <>, <, <=, > and >=; from == it writes <>. Those are marked generated below: you never write them and never ask for them (E07181), so they can never disagree with the <=>. And a defaulted <=> needs the fields to support it — a record whose fields cannot themselves be ordered gets == compared field by field, and no <.

Comparing

Symbol Name What it does Default?
<=> comparator Negative, zero or positive: sorts before, same, after. $\checkmark$
< less than Is the left smaller? generated
<= less than or equal Smaller, or the same? generated
> greater than Is the left larger? generated
>= greater than or equal Larger, or the same? generated
== equal Are the two the same? $\checkmark$ (or generated)
<> not equal Are the two different? generated
<~> fuzzy compare How similar — a closeness score.

The comparator <=> — often called the "spaceship" — is the root of the family: every other comparison is generated from it. == is marked both ways: it is generated from a <=>, but a type that can only be told equal (a point on a map has no "smaller") declares == as its sameness instead.

Note. You may write != in an expression as a C-style alias for <> (a != b means a <> b). But you never define the not-equal operator at all: <> is generated from the type's sameness, and writing operator != is a compile error (E07640, "use <> for the not equal operator"). So: use either symbol in an expression; define neither.

Arithmetic

Symbol Name What it does Default?
+ add Add, or join together.
- subtract Take away.
* multiply Multiply.
/ divide Divide.
^ power Raise to a power.
mod modulus The modulus (always positive).
rem remainder The remainder after division.
++ increment Move on by one.
-- decrement Move back by one.
! factorial The factorial.
abs absolute The size, ignoring sign.
sqrt square root The square root.

Note. ++ and -- differ from the rest of this table. They change the value in place and return nothing, so each is a statement on its own line, count++; + and - produce a new value instead. Because they change the value in place, on a constrained type ++ and -- keep the value's own type and check its rule again (Constrained Types). To flip a number's sign, write a unary minus: -count.

Arithmetic that assigns

These do the sum and store the answer back, so they change the value they are used on.

Symbol Name What it does Default?
+= add and assign Add to, and keep the result.
-= subtract and assign Take away from, and keep the result.
*= multiply and assign Multiply by, and keep the result.
/= divide and assign Divide by, and keep the result.

Converting

Symbol Name What it does Default?
$ to text The human-readable form. $\checkmark$
$$ to JSON The JSON form, for crossing a boundary. $\checkmark$
#? hashcode A number standing for the value. $\checkmark$
#^ promote Become another type automatically. One step only.

Asking about state

Symbol Name What it does Default?
? is set Does this hold a meaningful value? $\checkmark$
empty is empty Is there nothing in it?
length length How long, or how many.
contains contains Is that inside this?
matches matches Does it match this pattern?

Every type that holds fields must answer ? — it is the set/unset check the whole language rests on.

Copying and merging

Symbol Name What it does Default?
:=: copy Copy the other's contents into this one. $\checkmark$
:^: replace Replace this one's contents with the other's.
:~: merge Merge the other into this one, filling gaps.

For your own type the default :=: is a shallow copy: the copy's fields refer to the same objects as the original's.

Logic and bits

Symbol Name What it does Default?
~ not Flip a true/false value. The not keyword reads the same in an expression.
and and True when both are true.
or or True when either is true.
xor exclusive or True when exactly one is true.
<< shift left Shift the bits left.
>> shift right Shift the bits right.

The rest

Symbol Name What it does Default?
#< prefix The leading part of the value.
#> suffix The trailing part of the value.
close close Release whatever the value is holding — a file, a connection. $\checkmark$

You never call close yourself — writing x.close() is a compile error (E81060). It is called for you: a try closes the values it opened when it ends, and a type's default operator close closes the closeable fields it holds.

The stream pipe, |, also counts as an operator; it joins the stages of a pipeline together (Streams and Pipelines).

That is the complete list of operators you can give to a type of your own. You cannot add to it or invent a new symbol, and each entry has a settled meaning you are expected to keep. In return, an operator you meet in anyone's code is one you already understand.

Operators you use, but never define

A last handful belong to the language rather than to any one type. You cannot write your own version of these, because they are built on the set/unset idea that every EK9 value already has. You met them in Guards and Safe Code.

Symbol Name What it does
?: Coalesce (Elvis) a ?: b — use a if it is set, else b.
<? comparison coalescing (lesser) The smaller of the two.
>? comparison coalescing (greater) The larger of the two.
:=? assign-if-unset Assign only if the variable is unset.

?: checks that a value is genuinely set, and it is the one to use. (EK9 has no ?? operator, as in JavaScript, C# or Swift: EK9 is designed so that a value is never absent, though it may be unset, so there would be nothing for ?? to test. Writing ?? is not allowed - it is a compile error, E01096 - and ?: is what you want.)

The two comparison-coalescing operators (<? and >?) share one rule: a set value is always preferred to an unset one, and only when both are set does the comparison actually happen. That is what makes them safe on values which may not have arrived yet — exactly where a plain < would hand you a meaningless answer. When the two values are equal, both give back the left one; swap the two sides if you want the right one.