# Help me understand the \`unique\` semantic for a vector of mutable struct

**URL:** <https://discourse.julialang.org/t/help-me-understand-the-unique-semantic-for-a-vector-of-mutable-struct/110887>\
**Category:** General Usage\
**Tags:** question, mutable-structure\
**Created:** [February 28, 2024, 10:57am UTC](https://discourse.julialang.org/t/help-me-understand-the-unique-semantic-for-a-vector-of-mutable-struct/110887 "2024-02-28T10:57:30Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [February 28, 2024, 10:57am UTC](https://discourse.julialang.org/t/help-me-understand-the-unique-semantic-for-a-vector-of-mutable-struct/110887/1 "2024-02-28T10:57:30Z")

</div>

The `unique` documentation mentions that it is based on the `isequal` function.  
Hence I cannot understand the result of the following MWE:

```julia
Base.@kwdef mutable struct AStruct
    toto::String = "toto"
    tuti::Int = 2
end      

function Base.:(==)(a::AStruct, b::AStruct)
    for field ∈ fieldnames(AStruct)
        getproperty(a, field) != getproperty(b, field) && return false
    end
    return true
end

function unique_experiment()
    a = [(AStruct("titi",3),"aa"),(AStruct("tutu",3),"aa"),(AStruct("titi",3),"aa"),(AStruct("tete",3),"bb")]
    println("lenght(a) = $(length(a))")
    @show a[1]
    @show a[3]
    @show a[1] == a[3]
    ua = unique(a)
    println("lenght(ua) = $(length(ua))")
end

```

The output is:

```julia
lenght(a) = 4
a[1] = (PathViz.AStruct("titi", 3), "aa")
a[3] = (PathViz.AStruct("titi", 3), "aa")
a[1] == a[3] = true
lenght(ua) = 4

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 28, 2024, 11:18am UTC](https://discourse.julialang.org/t/help-me-understand-the-unique-semantic-for-a-vector-of-mutable-struct/110887/2 "2024-02-28T11:18:44Z")

</div>

The `==` implementation for `AStruct` and default `isequal` did not fulfill this documented requirement: “`isequal` is the comparison function used by hash tables (`Dict` ). `isequal(x,y)` must imply that `hash(x) == hash(y)` .” As a consequence, `unique` is unable to put them in the same slot of a `Set`.

Behavior you’d like:

```julia
julia> isequal([1], [1])
true

julia> unique([[1], [1]])
1-element Vector{Vector{Int64}}:
 [1]

julia> hash.([[1], [1]])
2-element Vector{UInt64}:
 0xc7253bdde85cb9f5
 0xc7253bdde85cb9f5

```

What happens now:

```julia
julia> isequal((AStruct("titi",3),"aa"), (AStruct("titi",3),"aa"))
true

julia> unique([(AStruct("titi",3),"aa"), (AStruct("titi",3),"aa")])
2-element Vector{Tuple{AStruct, String}}:
 (AStruct("titi", 3), "aa")
 (AStruct("titi", 3), "aa")

julia> hash.([(AStruct("titi",3),"aa"), (AStruct("titi",3),"aa")])
2-element Vector{UInt64}:
 0xd5f0f1ab22ccc31c
 0xbec08e442b331e69

```

Same discrepancy occurs for the `AStruct` instances alone rather than Tuples containing them.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [February 28, 2024, 11:31am UTC](https://discourse.julialang.org/t/help-me-understand-the-unique-semantic-for-a-vector-of-mutable-struct/110887/3 "2024-02-28T11:31:53Z")

</div>

Thank you very much for this detailed explanation !

I wonder if some tooling could help developers by forcing them to implement a `hash` method for each custom `isequal` method (I have spent some energy trying to figure out the problem before this discourse post).

Thank you again !

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 28, 2024, 11:36am UTC](https://discourse.julialang.org/t/help-me-understand-the-unique-semantic-for-a-vector-of-mutable-struct/110887/4 "2024-02-28T11:36:20Z")

</div>

The docstrings do say that custom `isequal`/`==` and `hash` implementations come in pairs. I wish I knew how hashing works to give any suggestions.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [February 28, 2024, 11:41am UTC](https://discourse.julialang.org/t/help-me-understand-the-unique-semantic-for-a-vector-of-mutable-struct/110887/5 "2024-02-28T11:41:57Z")

</div>

You are right, but one has to guess that he may not understand what is the semantic of `isequal` in order to look at the corresponding docstring.

The docstring of `unique` does not make any reference to the `hash` function:

```julia
help?> unique
search: unique unique! allunique

  unique(itr)

  Return an array containing only the unique elements of collection itr, as
  determined by isequal, in the order that the first of each set of equivalent
  elements originally appears. The element type of the input is preserved.

  See also: unique!, allunique, allequal.

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 28, 2024, 11:54am UTC](https://discourse.julialang.org/t/help-me-understand-the-unique-semantic-for-a-vector-of-mutable-struct/110887/6 "2024-02-28T11:54:40Z")

</div>

Right, I meant the `==`/`isequal`/`hash` docstrings. It does seem strange to me that `unique` mentions `isequal` in particular when hash table types must use `hash` then `isequal` to do key equality properly.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [February 28, 2024, 12:01pm UTC](https://discourse.julialang.org/t/help-me-understand-the-unique-semantic-for-a-vector-of-mutable-struct/110887/7 "2024-02-28T12:01:51Z")

</div>

Note that I think that I would have I consider the `hash` function if I was dealing with `Dict`. But since I was only using regular `Array`s, I have (wrongly) assumed that `unique` implementation only implied a bunch of call to `isequal`.

Maybe the `unique` docstring could be improved, mentioning the `hash` function.
