Janet 1.42.0-dev-7fd75f3 Documentation
(Other Versions:
1.42.0
1.41.2
1.41.1
1.40.1
1.40.0
1.39.1
1.38.0
1.37.1
1.36.0
1.35.0
1.34.0
1.31.0
1.29.1
1.28.0
1.27.0
1.26.0
1.25.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.0
1.19.0
1.18.1
1.17.1
1.16.1
1.15.0
1.13.1
1.12.2
1.11.1
1.10.1
1.9.1
1.8.1
1.7.0
1.6.0
1.5.1
1.5.0
1.4.0
1.3.1
)
Comparison Operators
Comparison operators are used for comparing values in Janet, in order to establish equality or ordering. Janet has two types of comparison operators, which we refer to as "primitive" comparison operators, and "polymorphic" comparison operators, respectively.
Primitive Comparison Operators
The primitive comparison operators are =, <, <=, >,
>=. In the simple case, each operator can be used to compare two values
as follows: (< a b) will return true if a < b, and false otherwise.
Similarly (= a b) will be true only if a == b.
(= 3 3) # -> true
(< 1 3) # -> true
(>= :a :a) # -> true
# strings compare lexicographically
(> "bar" "foo") # -> false
# keywords compare lexicographically by keyword name
(<= :bar :foo) # -> true
# nil always equals itself and only itself
(= nil nil) # -> trueMore generally, each of these operators can take any number of arguments
(from 0) and will return true if the arguments do not violate the ordering
implied by the operator. So (< 1 2 3) returns true but
(> 3 2 4) returns false. As an extreme, (<) returns true
since its (nonexistent) arguments do not violate the ordering.
(= 1 1 1) # -> true
(< 1 3 5) # -> true
(>= 3 1 7) # -> false
(> 1) # -> trueThe primitive comparison operators provide a total ordering for all Janet types, but importantly, these operators compare values of different types in a way that the user might find surprising in at least two ways.
First, if two arguments of a primitive comparison are of different types, they will be ordered by Janet's internal type number. This is not necessarily what the user needs, for example, when comparing Janet int/s64 types to Janet numbers.
# evaluates to false
(= (int/s64 1) (int/u64 1)) # -> false
# evaluates to true but this is due to the Janet internal type number
# for int/u64 types being greater than the internal type number for
# numbers!
(< 3 (int/u64 2)) # -> trueIf you require comparison between types to be ordered by something other than type number (e.g. "numeric value") then, use the polymorphic comparison operators, described below.
Secondly, = does not compare the contents of buffers, arrays,
tables, fibers, and some abstract types. Instead, it checks if the
two values are the same object.
# even though these have the same content they are NOT considered =
(= @"abc" @"abc") # -> false
(= @{:a 1} @{:a 1}) # -> false
(= @[:a :b] @[:a :b]) # -> false
# = returns true for the same value
(def x @{:a 1})
(= x x) # -> true
# = works as expected on immutable values
(= nil nil) # -> true
(= true true) # -> true
(= 1 1) # -> true
(= 'sym 'sym) # -> true
(= :kwd :kwd) # -> true
(= "abc" "abc") # -> true
(= [:a :b] [:a :b]) # -> true
(= {:a 1} {:a 1}) # -> truePolymorphic Comparison Operators
The polymorphic comparison operators are used for comparing different types in some manner rather than just by internal Janet type number. The semantics are determined by the types involved. The purpose of these operators is to allow comparison to work in some "less surprising" way (relative to the primitive comparison operators) when two types have a natural ordering between them.
The polymorphic comparison operators are compare=, compare<,
compare<=, compare>, compare>=. In general, they work
similarly to the primitive operators:
(compare< 1 3) # -> true
# strings compare lexicographically
(compare> "bar" "foo") # -> false
# keywords compare lexicographically by keyword name
(compare<= :bar :foo) # -> true
# nil always equals itself and only itself
(compare= nil nil) # -> true
# just like <
(compare< 1 2 3) # -> trueHowever, when comparing between int/s64, int/u64, and number types, these operators will "do the right thing".
# they are "semantically" equal
(compare= (int/s64 1) (int/u64 1)) # -> true
# semantically 3 is not < 2
(compare< 3 (int/u64 2)) # -> falseIn general the polymorphic operators are slower than the primitive ones, so use the primitive ones unless you need the extra polymorphic features.
Implementing Polymorphic Comparison
If you just want to use the polymorphic comparison for the built-in types, you can skip this section, which is about how to implement polymorphic comparison for your own types.
The polymorphic comparison operators all use a function called compare
to establish an ordering between janet values. The compare function
compares two values (here called a and b), and returns -1, 0, or
1 for a < b, a = b, a > b respectively. This result is
used by the comparison operator, like compare<, to return false or true.
(The comparison operators are extended to work for multiple arguments using
multiple calls to compare). The algorithm for the compare
function is as follows:
- if
aimplements:compareand(:compare a b)is not nil, then return(:compare a b) - if
bimplements:compareand(:compare b a)is not nil, then return(- (:compare b a)) - else return
(cond (< a b) -1 (= a b) 0 1)
Since compare defers to the primitive operators as a last
resort, the polymorphic comparison operators produce a total ordering
of Janet types.
The compare method on an abstract type can be implemented in C, and the compare method for a table-based "object" can be implemented in Janet. For more information on the latter see the object oriented programming section and the prototypes section for more information on developing object oriented methods on tables.
Deep Equality Operator
To compare the contents of mutable values, use the deep=
function. This function compares buffers like strings, and
recursively compares arrays and tables.
(deep= [:a :b] [:a :b]) # -> true
(deep= {:a 1} {:a 1}) # -> true
(deep= "abc" "abc") # -> true
(deep= @{:x @[@{:a 1} 3 @"hi"] :y 2}
@{:x @[@{:a 1} 3 @"hi"] :y 2}) # -> true
# deep= uses = for immutable values
(deep= @{:x (int/s64 1)}
@{:x (int/u64 1)}) # -> false