# 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.