What values can hold optional<T>
? It's either the value T
itself or a special value "nothing" that doesn't match any values of T
. Now let's try a trick: what is optional<void>
? It's a single-bit value that distinguishes between "nothing" and "void". It's a complete synonym for the bool
data type. Thus, since Argentum has the types "void" and "?T", there is no need in a separate "bool" type.
All logical operations, like comparison operations return ?T
. And ?
operator accepts any variations of ?T
as its left operand:
Type of ?
operator: (?T) ? (T->X) -> (?X)
- On the left side, it's not just "bool" (which is actually "?void") but it can be any
?T
. - On the right side, it's an expression with a result
X
(or transformationT
intoX
). - The result of the "
?
" operator itself will be?X
.
This is how the the "?
" operator works:
- First it evaluates/executes its left operand, and analyzes its result of type
?T
:- If "nothing," the result of the entire "
?
" operator becomes "nothing" of type?X
. - Otherwise,
- It creates a special temporary variable "_", having type
T
, and value extracted from?T
. - It executes its right operand, which using the "
_
" variable produces the value of typeX
. - Then "
?
" operator it wraps thisX
into?X
and makes it the result of the entire operation.
- It creates a special temporary variable "_", having type
- If "nothing," the result of the entire "
This "?" operator semantics allows checking conditions while simultaneously extracting the wrapped optional value and passing results down the chain of operations, method calls, and field accesses in a safe and controlled manner:
currentOrderId ? orders.findOrder(_) ? _.getPrice() ? processPrice(_);
In this example:
- If
currentOrderId
exists, find anorder
based on it. - If an
order
is found, retrieve theprice
from it. - If a
price
exists,process
it.
If a language lacks such syntax, this simple expression turns into a multi-line hard-to-maintain cascade of "if" statements and temporary variables.
Speaking of syntax-level safety, both C++ and Java allow accessing the value inside an optional without checking for its existence:
// C++
optional<int> x;
cout << *x;
// Java
var x = Optional<Integer>.empty();
System.out.println(x.get());
In Argentum, however, the "?
" operator provides access to the internal value only when it exists, and the ":
" operator requires you to provide code that will supply a value in place of absence. There are no other operators for accessing optionals. This is an impenetrable defense against accessing nonexistent values at the syntax level of the language during compilation.
// We cannot access the inner integer of `x` without prior checking
fn printOpt(x ?int) {
// Prints only if exists
x ? log(toString(_));
// Another way to access is by providing a default value
log(toString(x : -1));
// Yet another option - conditional conversion of `?int` to `?String`
// with a default value if ?String is nullopt
log(x ? toString(_) : "none");
}
Because of significance of optional types, Argentum has a simplified syntax for creating optional values:
- Value wrapped in optional:
+value_expression
. - "Nothing" of type ?T:
?T
(for example?int
). - "Nothing" of the same type as expression result:
?expression
.
BTW, despite non-existing bool, Argentum has keywords for it:
- "
bool
" declares the type "?void
" - "
true
" creates value+void
. - "
false
" creates value?void
.