# Dict equality with composite type value

**URL:** https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357
**Category:** New to Julia
**Tags:** question
**Created:** [October 27, 2019, 7:54am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357 "2019-10-27T07:54:50Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![johannmartinet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johannmartinet/32/11003_2.png) [@johannmartinet](https://discourse.julialang.org/u/johannmartinet)
#### Post date: [October 27, 2019, 7:54am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/1 "2019-10-27T07:54:50Z")

</div>

Still new to Julia and trying to test one of my methods which return a `Dict`. I know what should be included in this `Dict` and I try to compare it with what is returned by my method. However I have difficulties to test equality between two Dicts.

Here is a minimal working example of my problem :

**Module.jl**

```julia
module Module
import Base

export Struct
export Simple

struct Struct
        id::Int
        x::Vector{Float64}
end

struct Simple
        id::Int
end
end

```

**runtests.jl**

```julia
import Base
using Module
using Test

@testset "simple" begin
        expected = Dict{Int, Module.Simple}()
        expected[1] = Module.Simple(1)
        actual = Dict{Int, Module.Simple}()
        actual[1] = Module.Simple(1)
        @test actual == expected
end

@testset "struct" begin
        expected = Dict{Int, Module.Struct}()
        expected[1] = Module.Struct(1, [1.0])
        actual = Dict{Int, Module.Struct}()
        actual[1] = Module.Struct(1, [1.0])
        @test actual == expected
end

```

For the `Simple` struct, test passed without any problem.  
For the `Struct` struct, test failed with the following error :

```julia
(Module) pkg> test
   Testing Module
 Resolving package versions...
Test Summary: | Pass Total
simple | 1 1
struct: Test Failed at /home/xxxxxxx/sandbox/Module/test/runtests.jl:18
  Expression: actual == expected
   Evaluated: Dict(1 => Struct(1, [1.0])) == Dict(1 => Struct(1, [1.0]))
Stacktrace:
 [1] top-level scope at /home/xxxxxxxxx/sandbox/Module/test/runtests.jl:18
 [2] top-level scope at /build/julia/src/julia-1.2.0/usr/share/julia/stdlib/v1.2/Test/src/Test.jl:1113
 [3] top-level scope at /home/xxxxxxxx/sandbox/Module/test/runtests.jl:14
Test Summary: | Fail Total
struct | 1 1

```

First, I have strictly no idea why this error occurs. Is it related to the fact that `Simple` is strictly immutable and `Struct` is not (Vector is an array and arrays are mutable in julia if i get it right) ?

I try to find an answer in julia documentation and discourse and I thought :

- I should create following methods : `Base.isequal(struct::Struct)` and `Base.hash(struct::Struct)`
- I should replace `Struct` variables by strictly immutable types

So I have the following questions :

- Why this error occurs ?
- Should I create a specific `Base.isequal/hash` for each new struct I create ?
- Is there any way to rely on default `Dict` implementation to test equality between two dicts with custom composite types ?

Thank you!

---

<div class="post-metadata">

### Author: ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)
#### Post date: [October 27, 2019, 8:11am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/2 "2019-10-27T08:11:56Z")

</div>

What you are running into is that `==` for custom immutable structs just ends up falling back to `===`, and because your two arrays you pass to `Struct` don’t have the same location in memory, this returns false. There is already an open issue for this [here](https://github.com/JuliaLang/julia/issues/4648). The solution in your case would be to overload `Base.:(==)` or `Base.isequal` for `Struct`. You might not even need to overload `hash`, but I would test that again first.

---

<div class="post-metadata">

### Author: ![johannmartinet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johannmartinet/32/11003_2.png) [@johannmartinet](https://discourse.julialang.org/u/johannmartinet)
#### Post date: [October 27, 2019, 8:34am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/3 "2019-10-27T08:34:58Z")

</div>

Thanks for your answer and the link to the issue.  
I understand now why for `Struct` it does not work and throw an error.  
Just have a follow up question for the `Simple` case :

```julia
@testset "identity/equals" begin
        a = 1
        b = 1
        @test 1 === 1 # pass => OK
        @test [1.0] === [1.0] # fail => OK
        @test [1.0] == [1.0] # pass => OK
        @test a === b # pass => Why ?
end

```

In this test `a` and `b` should not have the same location in memory and the identity comparison still return true. Is there a special case for primitive types ?

---

<div class="post-metadata">

### Author: ![dmolina](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmolina/32/5246_2.png) [@dmolina](https://discourse.julialang.org/u/dmolina)
#### Post date: [October 27, 2019, 8:41am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/4 "2019-10-27T08:41:54Z")

</div>

There is no special case for primitive types, in julia, the variables use the memory used to store its value, each variable does not have its own memory. So a and b have the same location, and it is normal that pass the identity comparison. When you say var1 = var2, var1 and var2 are alias, each variable has not its own memory, the memory is the same, the memory needed to store the value.

```julia
b = [1.0]
a = b
@test a === b # true

```

Actually, when the variable value is scalar, its behavior is similar to have its own memory.

```julia
a = 4
b = a # Both are the same value and memory position
a === b # true
a = 5 # Now a make reference to constant 5, stored in a different memory position
a === b # false
println(b) # Print 4
println(a) # Print 5 

```

---

<div class="post-metadata">

### Author: ![dmolina](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmolina/32/5246_2.png) [@dmolina](https://discourse.julialang.org/u/dmolina)
#### Post date: [October 27, 2019, 8:46am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/5 "2019-10-27T08:46:22Z")

</div>

By the way, as @simeonschaub said, your code will pass the tests doing:

```julia
import Base: ==

function ==(val1::Module.Struct, val2::Module.Struct)
    return val1.id == val2.id && val1.x == val2.x
end

```

---

<div class="post-metadata">

### Author: ![johannmartinet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johannmartinet/32/11003_2.png) [@johannmartinet](https://discourse.julialang.org/u/johannmartinet)
#### Post date: [October 27, 2019, 9:00am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/6 "2019-10-27T09:00:22Z")

</div>

Thank you for your answer.  
I need more insight :

I quote :

> So a and b have the same location, and it is normal that pass the identity comparison

```julia
a = 1
b = 1
a === b # true

```

why in this case `a` and `b` refers to the same memory location ?

Thank you !

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [October 27, 2019, 9:04am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/7 "2019-10-27T09:04:47Z")

</div>

It doesn’t. Forget about memory locations, they are very misleading in understanding `===`.

The best definition is in its docstring:

> Determine whether `x` and `y` are identical, in the sense that no program could distinguish them.

Also, if you end up defining an `==` method for something, it is usually advantageous to define `Base.hash` too right away. It is very easy to end up with your values in a `Dict` or something similar, and then chase a silly bug for hours just because `hash` does not match `==`.

---

<div class="post-metadata">

### Author: ![johannmartinet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johannmartinet/32/11003_2.png) [@johannmartinet](https://discourse.julialang.org/u/johannmartinet)
#### Post date: [October 27, 2019, 9:11am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/8 "2019-10-27T09:11:05Z")

</div>

Thank you for your answer.

Ok I had to focus more on `===` documentation.  
Indeed integer literals `1` could not be distinguished.  
Then, how julia distinguish arrays (first guess : allocated on the heap at different location? )

```julia
a = [1.0] 
b = [1.0]
a === b # false

```

I agree with you both `==` and `hash` should be overloaded right away.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [October 27, 2019, 9:18am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/9 "2019-10-27T09:18:55Z")

</div>

> [@johannmartinet](#):
>
> Then, how julia distinguish (first guess : allocated on the heap ? )

One key ingredient about the efficiency is Julia is that the “how” is left unspecified, so it leaves considerable room for the compiler to do clever things. So unless you want to understand internals (in which case dig into the source and follow the devdocs), don’t be concerned about this.

What is clear that one could devise a conforming program could distinguish them (eg change some values and check if they change in the other one), so they are not equal. Whereas eg

```julia
using StaticArrays
a = SVector(1, 2)
b = SVector(1, 2)
a === b # true

```

---

<div class="post-metadata">

### Author: ![johannmartinet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johannmartinet/32/11003_2.png) [@johannmartinet](https://discourse.julialang.org/u/johannmartinet)
#### Post date: [October 27, 2019, 9:23am UTC](https://discourse.julialang.org/t/dict-equality-with-composite-type-value/30357/10 "2019-10-27T09:23:06Z")

</div>

Thanks ! All clear now !
