# Equality

Move supports two equality operations `==`

and `!=`

## Operations

Syntax | Operation | Description |
---|---|---|

`==` | equal | Returns `true` if the two operands have the same value, `false` otherwise |

`!=` | not equal | Returns `true` if the two operands have different values, `false` otherwise |

### Typing

Both the equal (`==`

) and not-equal (`!=`

) operations only work if both operands are the same type

`0 == 0; // `true``

1u128 == 2u128; // `false`

b"hello" != x"00"; // `true`

Equality and non-equality also work over user defined types!

`address 0x42 {`

module example {

struct S has copy, drop { f: u64, s: vector<u8> }

fun always_true(): bool {

let s = S { f: 0, s: b"" };

// parens are not needed but added for clarity in this example

(copy s) == s

}

fun always_false(): bool {

let s = S { f: 0, s: b"" };

// parens are not needed but added for clarity in this example

(copy s) != s

}

}

}

If the operands have different types, there is a type checking error

`1u8 == 1u128; // ERROR!`

// ^^^^^ expected an argument of type 'u8'

b"" != 0; // ERROR!

// ^ expected an argument of type 'vector<u8>'

### Typing with references

When comparing references, the type of the reference (immutable or mutable) does
not matter. This means that you can compare an immutable `&`

reference with a mutable one `&mut`

of
the same underlying type.

`let i = &0;`

let m = &mut 1;

i == m; // `false`

m == i; // `false`

m == m; // `true`

i == i; // `true`

The above is equivalent to applying an explicit freeze to each mutable reference where needed

`let i = &0;`

let m = &mut 1;

i == freeze(m); // `false`

freeze(m) == i; // `false`

m == m; // `true`

i == i; // `true`

But again, the underlying type must be the same type

`let i = &0;`

let s = &b"";

i == s; // ERROR!

// ^ expected an argument of type '&u64'

## Restrictions

Both `==`

and `!=`

consume the value when comparing them. As a result, the type system enforces that
the type must have `drop`

. Recall that without the
`drop`

ability, ownership must be transferred by the end of the function, and such
values can only be explicitly destroyed within their declaring module. If these were used directly
with either equality `==`

or non-equality `!=`

, the value would be destroyed which would break
`drop`

ability safety guarantees!

`address 0x42 {`

module example {

struct Coin has store { value: u64 }

fun invalid(c1: Coin, c2: Coin) {

c1 == c2 // ERROR!

// ^^ ^^ These resources would be destroyed!

}

}

}

But, a programmer can *always* borrow the value first instead of directly comparing the value, and
reference types have the `drop`

ability. For example

`address 0x42 {`

module example {

struct Coin as store { value: u64 }

fun swap_if_equal(c1: Coin, c2: Coin): (Coin, Coin) {

let are_equal = &c1 == &c2; // valid

if (are_equal) (c2, c1) else (c1, c2)

}

}

}

## Avoid Extra Copies

While a programmer *can* compare any value whose type has `drop`

, a programmer
should often compare by reference to avoid expensive copies.

`let v1: vector<u8> = function_that_returns_vector();`

let v2: vector<u8> = function_that_returns_vector();

assert!(copy v1 == copy v2, 42);

// ^^^^ ^^^^

use_two_vectors(v1, v2);

let s1: Foo = function_that_returns_large_struct();

let s2: Foo = function_that_returns_large_struct();

assert!(copy s1 == copy s2, 42);

// ^^^^ ^^^^

use_two_foos(s1, s2);

This code is perfectly acceptable (assuming `Foo`

has `drop`

), just not efficient.
The highlighted copies can be removed and replaced with borrows

`let v1: vector<u8> = function_that_returns_vector();`

let v2: vector<u8> = function_that_returns_vector();

assert!(&v1 == &v2, 42);

// ^ ^

use_two_vectors(v1, v2);

let s1: Foo = function_that_returns_large_struct();

let s2: Foo = function_that_returns_large_struct();

assert!(&s1 == &s2, 42);

// ^ ^

use_two_foos(s1, s2);

The efficiency of the `==`

itself remains the same, but the `copy`

s are removed and thus the program
is more efficient.