# Comparison Operators

OperatorDescription
(`x` operator `y`)
`x`, `y` same type or are numeric`x`, `y` different types
`==``x` is equals to `y`error if not defined`false` if not defined
`!=``x` is not equals to `y`error if not defined`true` if not defined
`>``x` is greater than `y`error if not defined`false` if not defined
`>=``x` is greater than or equals to `y`error if not defined`false` if not defined
`<``x` is less than `y`error if not defined`false` if not defined
`<=``x` is less than or equals to `y`error if not defined`false` if not defined

Comparison operators between most values of the same type are built in for all standard types.

### Floating-point numbers interoperate with integers

Comparing a floating-point number with an integer is also supported.

``````42 == 42.0;         // true

42.0 == 42;         // true

42.0 > 42;          // false

42 >= 42.0;         // true

42.0 < 42;          // false``````

### Decimal numbers interoperate with integers

Comparing a decimal number with an integer is also supported.

``````let d = parse_decimal("42");

42 == d;            // true

d == 42;            // true

d > 42;             // false

42 >= d;            // true

d < 42;             // false``````

### Strings interoperate with characters

Comparing a string with a character is also supported, with the character first turned into a string before performing the comparison.

``````'x' == "x";         // true

"" < 'a';           // true

'x' > "hello";      // false``````

### Comparing different types defaults to `false`

Comparing two values of different data types defaults to `false` unless the appropriate operator functions have been registered.

The exception is `!=` (not equals) which defaults to `true`. This is in line with intuition.

``````42 > "42";          // false: i64 cannot be compared with string

42 <= "42";         // false: i64 cannot be compared with string

let ts = new_ts();  // custom type

ts == 42;           // false: different types cannot be compared

ts != 42;           // true: different types cannot be compared

ts == ts;           // error: '==' not defined for the custom type``````

### Safety valve: Comparing different numeric types has no default

Beware that the above default does NOT apply to numeric values of different types (e.g. comparison between `i64` and `u16`, `i32` and `f64`) – when multiple numeric types are used it is too easy to mess up and for subtle errors to creep in.

``````// Assume variable 'x' = 42_u16, 'y' = 42_u16 (both types of u16)

x == y;             // true: '==' operator for u16 is built-in

x == "hello";       // false: different non-numeric operand types default to false

x == 42;            // error: ==(u16, i64) not defined, no default for numeric types

42 == y;            // error: ==(i64, u16) not defined, no default for numeric types``````

# Boolean Operators

Note

All boolean operators are built in for the `bool` data type.

OperatorDescriptionArityShort-circuits?
`!` (prefix)NOTunaryno
`&&`ANDbinaryyes
`&`ANDbinaryno
`||`ORbinaryyes
`|`ORbinaryno

Double boolean operators `&&` and `||` short-circuit – meaning that the second operand will not be evaluated if the first one already proves the condition wrong.

Single boolean operators `&` and `|` always evaluate both operands.

``````a() || b();         // b() is not evaluated if a() is true

a() && b();         // b() is not evaluated if a() is false

a() | b();          // both a() and b() are evaluated

a() & b();          // both a() and b() are evaluated``````

# Null-Coalescing Operator

OperatorDescriptionArityShort-circuits?
`??`Null-coalescebinaryyes

The null-coalescing operator (`??`) returns the first operand if it is not `()`, or the second operand if the first operand is `()`.

This operator short-circuits – meaning that the second operand will not be evaluated if the first operand is not `()`.

``````a ?? b              // returns 'a' if it is not (), otherwise 'b'

a() ?? b();         // b() is only evaluated if a() is ()``````

Tip: Default value for object map property

Use the null-coalescing operator to implement default values for non-existent object map properties.

``````let map = #{ foo: 42 };

// Regular property access
let x = map.foo;            // x == 42

// Non-existent property
let x = map.bar;            // x == ()

// Default value for property
let x = map.bar ?? 42;      // x == 42``````

# In Operator

Trivia

The `in` operator is simply syntactic sugar for a call to the `contains` function.

Similarly, `!in` is a call to `!contains`.

The `in` operator is used to check for containment – i.e. whether a particular collection data type contains a particular item.

Similarly, `!in` is used to check for non-existence – i.e. it is `true` if a particular collection data type does not contain a particular item.

``````42 in array;

array.contains(42);     // <- the above is equivalent to this

123 !in array;

!array.contains(123);   // <- the above is equivalent to this``````

### Built-in support for standard data types

Data typeCheck for
Numeric rangeinteger number
Arraycontained item
Object mapproperty name
Stringsub-string or character

### Examples

``````let array = [1, "abc", 42, ()];

42 in array == true;                // check array for item

let map = #{
foo: 42,
bar: true,
baz: "hello"
};

"foo" in map == true;               // check object map for property name

'w' in "hello, world!" == true;     // check string for character

'w' !in "hello, world!" == false;

"wor" in "hello, world" == true;    // check string for sub-string

42 in -100..100 == true;            // check range for number``````