On this page:
==
==
===
===
.=
.!=
!=
is_  now
is_  now
is_  same_  number_  or_  object
is_  same_  number_  or_  object
=
Equatable
Equatable.hash
Equatable.identity_  hash
Equatable.hash_  code_  combine
Equatable.hash_  code_  combine_  unordered
8.12

6.45 Equality🔗ℹ

operator

operator ((v1 :: Any) == (v2 :: Any)) :: Boolean

 

map configuration

==

The == operator reports whether v1 and v2 are equal, which includes recursively comparing elements of compound data structures. Two numbers are == only if they are both exact or both inexact. Two mutable values are == only if they the same object (i.e., mutating one has the same effect as mutating the other).

The == map configuration can be used with forms like the Map.by constructor or Map.by annotation constructor to specify the default equality and hashing functions for map keys. The Map.by(==) annotation, for example, matches only maps that use the default equality and hashing functions.

> "apple" == "apple"

#true

> [1, 2, 3] == 1

#false

> [1, "apple", {"alice": 97}] == [1, "apple", {"alice": 97}]

#true

> 1 == 1.0

#false

operator

operator ((v1 :: Any) === (v2 :: Any)) :: Boolean

 

map configuration

===

The === operator reports whether v1 and v2 are the same object. Being the same is weakly defined, but only == values can possibly be the same object, and mutable values are the same only if modifying one has the same effect as modifying the other. Interned values like symbols are === when they are ==.

The === map configuration can be used with forms like the Map.by constructor or Map.by annotation constructor to specify key equality with === and a corresponding hashing function.

> #'apple === #'apple

#true

> #'apple === #'banana

#false

operator

operator ((x :: Number) .= (y :: Number)) :: Boolean

 

operator

operator ((x :: Number) .!= (y :: Number)) :: Boolean

Reports whether x and y are numerically equal or unequal, where inexact numbers are effectively coerced to exact for comparisons to exact numbers. The value #nan is not .= to itself (but #nan is == to itself).

> 1 .= 1

#true

> 1 .= 2

#false

> 1.0 .= 1

#true

> 1 .!= 2

#true

> 1 .!= 1.0

#false

operator

operator ((v1 :: Any) != (v2 :: Any)) :: Boolean

Equvalent to !(v1 == v2).

> "apple" != "apple"

#false

operator

operator ((v1 :: Any) is_now (v2 :: Any)) :: Boolean

 

map configuration

is_now

Reports whether v1 and v2 are equivalent now in the sense that mutable fields of objects have the same values.

Mutable and immutable strings, byte vectors, and arrays are considered the same if they have the same elements, even if one is mutable and the other is immutable. However, a mutable map or set is never considered equivalent to an immutable map or set, even if they have the same content.

The is_now map configuration can be used with forms like the Map.by constructor or Map.by annotation constructor to specify key equality with is_now and a corresponding hashing function. Beware, however, that mutating a key after it is mapped will tend to make the map entry inaccessible.

> #"apple" is_now Bytes.copy(#"apple")

#true

> #"apple" == Bytes.copy(#"apple")

#false

class Posn(mutable x, mutable y)

> Posn(1, 2) is_now Posn(1, 2)

#true

> Posn(1, 2) == Posn(1, 2)

#false

operator

operator ((v1 :: Any) is_same_number_or_object (v2 :: Any)) :: Boolean

 

map configuration

is_same_number_or_object

The is_same_number_or_object operator checks whether two values are either equal via === or are two numbers that are ==. This comparison is primarily intended for comparing numbers, and especially via is_same_number_or_object as a map configuration for equating map keys, where is_same_number_or_object can be slightly more efficient than ==.

expression

=

The = operator is not bound as an expression or binding operator. It is used as a syntactic delimiter by various forms, such as in fun when specifying the default value for an optional argument.

Provided only in the class space, not the annot space.

An interface that a class can implement (publicly or privately) to customize the way its objects are compared and hashed. The interface has two methods:

A class gets a default equality implementation that recurs to compare fields only if the class has no mutable fields, and that matches === when the class has mutable fields. Normally, Equatable should be implemented privately, so that the methods do not have to check what class other instantiates or whether recur is a function.

class Posn(x, y):

  private field cache = #false

  method dist():

    cache || (block:

                def v = math.sqrt(x*x + y*y)

                cache := v

                v)

  // since `cache` is mutable, the default equality

  // comparison would only make `===` objects equal

  private implements Equatable

  private override equals(other :: Posn, recur):

    recur(x, other.x) && recur(y, other.y)

  private override hash_code(recur):

    Equatable.hash_code_combine(recur(x), recur(y))

> Posn(3, 4) == Posn(3, 4)

#true

function

fun Equatable.hash(v :: Any) :: Int

Returns a hash code for v that is consistent with ==.

Returns a hash code for v that is consistent with ===.

function

fun Equatable.hash_code_combine(hc :: Int, ...)

  :: Int

 

function

fun Equatable.hash_code_combine_unordered(hc :: Int, ...)

  :: Int

Combines hash codes to produce a new one. Information is generally lost in the combination, but this combining function mixes integers in a suitable way to produce good results for hashing.

See Equatable for an example.