> For the complete documentation index, see [llms.txt](https://docs.endless.link/endless/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.endless.link/endless/devbuild/build/learn-the-move-language/the-move-book/basic-concepts/equality.md).

# Equality

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

```move
0 == 0; // `true`
1u128 == 2u128; // `false`
b"hello" != x"00"; // `true`
```

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

```move
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

```move
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.

```move
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

```move
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

```move
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!

```move
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

```move
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.

```move
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

```move
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.
