# In Operator not working as expected for struct

**URL:** <https://discourse.julialang.org/t/in-operator-not-working-as-expected-for-struct/117874>\
**Category:** New to Julia\
**Tags:** question, struct\
**Created:** [August 6, 2024, 8:23am UTC](https://discourse.julialang.org/t/in-operator-not-working-as-expected-for-struct/117874 "2024-08-06T08:23:17Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![sven](https://avatars.discourse-cdn.com/v4/letter/s/e47c2d/32.png) [@sven](https://discourse.julialang.org/u/sven)\
**Post date:** [August 6, 2024, 8:23am UTC](https://discourse.julialang.org/t/in-operator-not-working-as-expected-for-struct/117874/1 "2024-08-06T08:23:17Z")

</div>

Hello.

I have a struct “parts” and a different struct (“collection”) which contains a Set of parts. I want to check if a part is contained in the Set of parts. I tried to overload the `isequal` function. Because in the [Documentation](https://docs.julialang.org/en/v1/base/collections/) (under Iterable Collections/ Base.in) it says _[…] For example, Sets check whether the item `isequal` to one of the elements […]_. In the example below i want `x_prime in X.parts` to evaluate to true.

I’m running Julia 1.10.4 in a jupyter notebook on linux. Below is a (hopefully) minimal working example. Any help would be greatly appreciated.

Thanks in advance  
Sven

**Input:**

```julia
struct part
    x::Array{BigInt}
end

Base.:isequal(part1::part,part2::part) = isequal(part1.x,part2.x)

struct collection
    num_of_parts::BigInt
    parts::Set{part}
end

x = part([1,2,3])
y = part([2,3,4])
z = part([3,4,5])

X = collection(3,Set{part}([x,y,z]))

x_prime = deepcopy(x)
println("x' is equal to x: ",isequal(x_prime,x))
println("x is a part of X.parts: ",x in X.parts)
println("But x' isn't: ", x_prime in X.parts)

```

**Output:**

```julia
x' is equal to x: true
x is a part of X.parts: true
But x' isn't: false

```

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [August 6, 2024, 9:45am UTC](https://discourse.julialang.org/t/in-operator-not-working-as-expected-for-struct/117874/2 "2024-08-06T09:45:47Z")

</div>

Hi sven,

Welcome to the Julia community!

The short answer is that you should also implement `hash` for your `part` struct. Citing [`isequal`’s documentation](https://docs.julialang.org/en/v1/base/base/#Base.isequal):

> This typically means that types for which a custom == or isequal method exists must implement a corresponding hash method (and vice versa).

If you add `Base.hash(p::part) = hash(p.x)`, then `x_prime in X.parts` now indeed evaluates to `true`.

If you want some more context, Julia’s `Set`s are basically `Dict`s with `Nothing` values. In turn `Dict`s rely on hash tables. When you are then using `in(x, X.parts)`, you’re checking that `x` is a key in `X.parts.dict`. To do this, you

1. Compute the hash index of `x` in the `Dict`’s hash table.
2. Check that this slot is not empty.
3. If a value in this slot indeed exists, compare it to `x` using `isequal`.

In your example the slot for `x_prime` not the same as that of `x` due to differing hashes. In fact, the spot is empty, so `in` will immediately return `false`, without ever calling `isequal`. So even if you had written ` Base.:isequal(part1::part,part2::part) = true` (and did not overwrite the default `hash`), you would find that `x_prime in X.parts` evaluates to `false`. Now, the [documentation of `in`](https://docs.julialang.org/en/v1/base/collections/#Base.in) does state that

> Sets check whether the item `isequal` to one of the elements;

which is then actually a bit too simplistic, so the confusion is certainly understandable.

---

<div class="post-metadata">

**Author:** ![sven](https://avatars.discourse-cdn.com/v4/letter/s/e47c2d/32.png) [@sven](https://discourse.julialang.org/u/sven)\
**Post date:** [August 6, 2024, 9:53am UTC](https://discourse.julialang.org/t/in-operator-not-working-as-expected-for-struct/117874/3 "2024-08-06T09:53:41Z")

</div>

Many thanks for the clear explanation!

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 6, 2024, 11:19am UTC](https://discourse.julialang.org/t/in-operator-not-working-as-expected-for-struct/117874/4 "2024-08-06T11:19:33Z")

</div>

(Note also that, as explained in the `isequal` docs, you should normally define `==`, via `Base.:(==)`, rather than `Base.isequal`.)

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 6, 2024, 12:13pm UTC](https://discourse.julialang.org/t/in-operator-not-working-as-expected-for-struct/117874/5 "2024-08-06T12:13:54Z")

</div>

I have a couple of comments:

Firstly, it is conventional to use Capitalized names for types, i.e. `Part` and `Collection`.

Secondly, `Array{BigInt}` is an abstract type, which makes your code type unstable, and could hurt performance. If you use `Array{BigInt, 1}` or its alias `Vector{BigInt}`, it should help.

Thirdly, `BigInt`s are slow. If you need them, they are fine, otherwise you can consider using native (and fast) `Int`.

Fourthly, in your `collection` type, you have a separate field, `num_of_parts`. Normally, you would not store that, since the number of parts is actually stored inside the `parts` field, you can find it by doing `length(X.parts)`, also, unless you are planning to store 10 billion billion arrays of `BigInt`s, it probably not necessary to make `num_of_parts` a `BigInt` 😉

---

<div class="post-metadata">

**Author:** ![sven](https://avatars.discourse-cdn.com/v4/letter/s/e47c2d/32.png) [@sven](https://discourse.julialang.org/u/sven)\
**Post date:** [August 6, 2024, 12:26pm UTC](https://discourse.julialang.org/t/in-operator-not-working-as-expected-for-struct/117874/6 "2024-08-06T12:26:03Z")

</div>

@stevengj @DNF Thank you for your comments. They are very welcome!
