but there are two binary operators: "?" and ":"
Let's consider an example:
a = 4; // `a` has type `int` and value 4
b = a < 0 ? -1 : 1; // `b` has type `int` and value 1
Actually, the expression a ? b : c
in this example consists of two nested binary operators. They can be written separately as well:
x = a < 0 ? -1;
b = x : 1;
The type of variable x
will be optional<int>,
or in Argentum syntax: ?int
. Let's delve into the semantics of these two lines more closely:
x = a < 0 ? -1; // `x` will be -1 if `a` < 0 or "nothing" for all other cases.
b = x : 1; // assign the value of `x` to `b`, but if it's "nothing", then assign 1.
It can be said that the operator ?
produces an optional, and :
consumes it. When used together, they function like the old good ternary operator:
b = (a < 0 ? -1) : 1;
When the result of an expression is not needed, the operator ?
works like an if
:
a < 0 ? log("it's negative");
And the pair of operators ?:
works like an if...else
:
a & 1 == 0
? log("it's even")
: log("it's odd");
So, Argentum split the ternary operator into two binary ones. What did this achieve?
- Short conditional expressions without an 'else' part that return values. The language became more orthogonal.
- Nothing got complicated—no new syntactic constructs were added.
- Two constructors for optional values appeared:
- Instead of (C++)
optional<decltype(x)> maybeX{x}
we can writemaybeX = true ? x
- Instead of
optional<decltype(x)> maybeX{nullopt}
we can writemaybeX = false ? x
- Instead of (C++)
- Unpacking with default value also became simpler:
Instead ofauto a = maybeX ? *maybeX : 42
we can writea = maybeX : 42
- In case of data absence, it's not necessary to use a default value; we can call a handler for the problematic situation or trigger panic:
x : terminate()
- It's often, when returning an optional result from a function,
we write:return condition ? result : nullopt
In Argentum, this will be:condition ? result
- We can not only combine the
?
and:
operators but also combine the:
operators among themselves. For example:user = currentUser : getUserFromProfile() : getDefaultUser() : panic("no user");
This short expression attempts to get a user object from multiple places and triggers application exit if nothing succeeds.