Comparison#
You can perform various comparisons, such as comparing numbers or strings, or checking whether a specific element is contained in an array.
Binding of Comparison Operators#
The binding between comparison operators works in a special way, following these steps:
- For all comparison operators, perform the comparison between their left and right operands
- Take the logical AND of all those results
For example, 3 <= x <= 5 first evaluates 3 <= x, then evaluates x <= 5, and finally takes their logical AND: 3 <= x && x <= 5.
This allows you to write comparison chains concisely.
$ xa '3 <= 4 <= 5'
# TRUE
$ xa '3 <= 10 <= 5'
# FALSE
The following operators follow this specification:
><>=<===!=@!@?=
Comparison Operators#
The comparison operators are as follows:
| Operator | Meaning |
|---|---|
left > right |
Returns whether left is greater than right |
left < right |
Returns whether left is less than right |
left >= right |
Returns whether left is greater than or equal to right |
left <= right |
Returns whether left is less than or equal to right |
$ xa '[1 > 2, 2 > 2, 3 > 2]'
# [FALSE;FALSE;TRUE]
$ xa '[1 < 2, 2 < 2, 3 < 2]'
# [TRUE;FALSE;FALSE]
$ xa '[1 >= 2, 2 >= 2, 3 >= 2]'
# [FALSE;TRUE;TRUE]
$ xa '[1 <= 2, 2 <= 2, 3 <= 2]'
# [TRUE;TRUE;FALSE]
Overriding Comparison Operators#
Comparison operators actually determine their behavior based on the result of the spaceship operator.
When the spaceship operator is overridden, the behavior of the various comparison operators changes accordingly.
Equality Operators#
Equality Operator#
The equality operator left == right returns whether the values on both sides are equal.
$ xa '[1 == 2, 2 == 2, 3 == 2]'
# [FALSE;TRUE;FALSE]
Currently, it is only defined for some types such as numbers and strings.
Inequality Operator#
The inequality operator left != right returns whether the values on both sides are not equal.
This is the negation of the equality operator.
$ xa '[1 != 2, 2 != 2, 3 != 2]'
# [TRUE;FALSE;TRUE]
Containment Operators#
Containment Operator#
The containment operator left @ right returns whether left is contained in right.
The behavior for each right-hand type is as follows:
| Right Type | Return Value |
|---|---|
| String | Whether the left string is contained in the right string |
| Array | Whether the left element is contained in the right array |
| Object | Whether the left key is contained in the right object |
$ xa '"bcd" @ "abcde"'
# TRUE
$ xa '"123" @ "abcde"'
# FALSE
$ xa '1 @ [1, 2, 3]'
# TRUE
$ xa '4 @ [1, 2, 3]'
# FALSE
$ xa '"a" @ {a: 1; b: 2; c: 3}'
# TRUE
$ xa '"d" @ {a: 1; b: 2; c: 3}'
# FALSE
The behavior of the containment operator is inconsistent: strings are substrings, arrays are elements, and objects are keys.
Negative Containment Operator#
The negative containment operator left !@ right returns whether left is not contained in right.
It behaves equivalently to the expression !(left @ right) using the containment operator.
$ xa '"bcd" !@ "abcde"'
# FALSE
$ xa '"123" !@ "abcde"'
# TRUE
Overriding the Containment Operator#
The containment operator is actually an operator that calls the _@_ method of the right-hand value and returns its boolean conversion.
$ xa -q '
Basket := {
`_@_`: this, item -> item @ this.items
}
basket := Basket{items: ["apple", "orange", "banana"]}
OUT << "Basket: $basket"
"apple" @ basket && (OUT << "apple is in basket")
"cherry" @ basket && (OUT << "cherry is in basket")
'
# Basket: {items:[apple;orange;banana]}
# apple is in basket
InstanceOf Operator#
The instanceOf operator left ?= right returns whether left is an instance of right.
More precisely, it determines whether object left is the same instance as right, or whether right exists somewhere in left’s inheritance chain.
$ xa -q '
Animal := {}
Human := Animal {}
socrates := Human{}
pythagoras := Human{}
Animal ?= Animal && (OUT << "Animal is Animal")
Human ?= Human && (OUT << "Human is Human")
socrates ?= socrates && (OUT << "Socrates is Socrates")
pythagoras ?= pythagoras && (OUT << "Pythagoras is Pythagoras")
Human ?= Animal && (OUT << "Human is Animal")
Animal ?= Human && (OUT << "Animal is Human")
socrates ?= Human && (OUT << "Socrates is Human")
Human ?= socrates && (OUT << "Human is Socrates")
socrates ?= Animal && (OUT << "Socrates is Animal")
Animal ?= socrates && (OUT << "Animal is Socrates")
socrates ?= pythagoras && (OUT << "Socrates is Pythagoras")
pythagoras ?= socrates && (OUT << "Pythagoras is Socrates")
'
# Animal is Animal
# Human is Human
# Socrates is Socrates
# Pythagoras is Pythagoras
# Human is Animal
# Socrates is Human
# Socrates is Animal
Spaceship Operator#
The spaceship operator <=> is an operator that returns the magnitude relationship between the left and right sides.
The relationship between the left-right magnitude relationship and the return value of the spaceship operator is as follows:
| Condition | Return Value |
|---|---|
| Left < Right | -1 |
| Left = Right | 0 |
| Left > Right | 1 |
$ xa '1 <=> 2'
# -1
$ xa '2 <=> 2'
# 0
$ xa '3 <=> 2'
# 1
When comparing strings, they are determined in lexicographic order.
$ xa ' "a" <=> "b" '
# -1
$ xa ' "aa" <=> "a" '
# 1
Overriding the Spaceship Operator#
The spaceship operator is actually an operator that calls the _<=>_ method of the left-hand value and returns its return value.
$ xa '
Person := {
`_<=>_`: this, other -> this.age <=> other.age
}
alice := Person{age: 30}
bob := Person{age: 20}
alice <=> bob
'
# 1
Use in SORT Function and Others#
The spaceship operator can be used as a comparison function in functions like SORT.
The following example sorts by string length.
$ xa '
(
"apple",
"banana",
"cherry",
"durian",
"elderberry",
"fig",
"grape",
) >> SORT[a, b -> $#a <=> $#b]
'
# fig
# apple
# grape
# banana
# cherry
# durian
# elderberry