# Passing method arguments: Tuple vs Dict

**URL:** <https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755>\
**Category:** New to Julia\
**Tags:** dictionary, struct\
**Created:** [May 25, 2021, 2:06am UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755 "2021-05-25T02:06:49Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [May 25, 2021, 2:06am UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/1 "2021-05-25T02:06:49Z")

</div>

What am I missing?

```
"""
A struct to hold parameters
""" 
struct P
    a :: Float64
    b :: Vector{Float64}
end

""" 
A method to update the parameters
""" 
function P(; a = 0.0, b = [0.0, 0.0])
    P(a, b)
end 

```

Create an instance of P by passing the parameters directly

```
julia> p0 = P(a = 1.0, b = [2.0, 3.0])
P(1.0, [2.0, 3.0])

```

Create an instance of P by passing the parameters via a dictionary

```
julia> d1 = Dict(:a => 1.0, :b => [2.0, 3.0])
julia> p1 = P(; d1...)
P(1.0, [2.0, 3.0])

```

Isn’t that the same thing? Ahem, no:

```
julia> p1 == p0
false  

```

And yet they have the same type:

```
julia> typeof(p0) == typeof(p1)
true 
julia> fieldnames(typeof(p0)) == fieldnames(typeof(p1))
true 

```

So what’s the difference? Thanks.

---

<div class="post-metadata">

**Author:** ![ettersi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ettersi/32/6829_2.png) [@ettersi](https://discourse.julialang.org/u/ettersi)\
**Post date:** [May 25, 2021, 2:13am UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/2 "2021-05-25T02:13:03Z")

</div>

By default, two structs are considered equal if they are bitwise the same. In your example, this is not the case because the two `Vector`s are _different_ vectors (even though they have the same entries). The following example should make this clear:

```julia
julia> struct Foo
           a::Vector{Int}
       end

julia> Foo([1,2]) == Foo([1,2]) # Different vectors with same entries
false

julia> a = [1,2]; Foo(a) == Foo(a) # Same vector
true

```

If this is not the behaviour that you want, then you must define your own equality comparison:

```julia
julia> Base.:(==)(a::Foo,b::Foo) = a.a == b.a

julia> Foo([1,2]) == Foo([1,2]) 
true # <- I guess this is what you wanted?

```

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [May 25, 2021, 3:28am UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/3 "2021-05-25T03:28:12Z")

</div>

Thanks ettersi. I was just in the process of checking that I could pass the same data as a dictionary. I did not encounter this issue with scalars:

```
struct Foo
    a::Int64
end
julia> Foo(1) == Foo(1)
true

```

Why the difference between scalars and vectors? Thanks!

---

<div class="post-metadata">

**Author:** ![ettersi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ettersi/32/6829_2.png) [@ettersi](https://discourse.julialang.org/u/ettersi)\
**Post date:** [May 25, 2021, 3:40am UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/4 "2021-05-25T03:40:40Z")

</div>

The key difference is mutable vs immutable data structures. Scalars are immutable: if you have two variables `a = b = 1`, then regardless what you do to `a` you will not be able to change the value of `b`. `Vector`s on the other hand are mutable: if you do `a = b = [1]` and `a[1] = 2`, then _both_ `a` and `b` will now point to a vector `[2]`. Given this difference, it makes sense to make the default such that `Foo(1) == Foo(1)`, but `Foo([1]) != Foo([1])`.

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [May 25, 2021, 4:02am UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/5 "2021-05-25T04:02:59Z")

</div>

Makes perfect sense. Great answer, thanks ettersi!

---

<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:** [May 25, 2021, 2:20pm UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/6 "2021-05-25T14:20:53Z")

</div>

> [@ettersi](#):
>
> define your own equality comparison:

And don’t forget your custom `Base.hash` if you use it anywhere as a key (eg `Dict`).

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [May 25, 2021, 9:30pm UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/7 "2021-05-25T21:30:12Z")

</div>

> [@Tamas\_Papp](#):
>
> don’t forget your custom `Base.hash`

Thanks Tamas. Are you suggesting to overload `Base.hash` to assign a hash-key to each key,value pair inside the dictionary and `Base.isequal` to return true if all the hash-keys match? Am I understanding? Do you have a ready-made example of use?

I’ve just noticed this behaviour:

```
struct Foo
    a :: Real
end

julia> Foo(1) == Foo(1)
true

julia> Foo(1) == Foo(1.)
false

```

By contrast,

```
julia> 1 == 1.
true 

```

(but, as expected,

```
    julia> 1 === 1.
    false

```

).

The docs [here](https://docs.julialang.org/en/v1/base/math/#Base.:==) and [here](https://docs.julialang.org/en/v1/base/base/#Base.isequal) are very clear about what `==` does and also the difference with `isequal`. Before reading the docs, I expected either `false` or a `MethodError`.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [May 25, 2021, 9:42pm UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/8 "2021-05-25T21:42:00Z")

</div>

No, the point about `hash` is that if you define equality for your struct, then you should also define the way the struct itself is hashed so that `isequal(x::Foo, y::Foo)` implies `hash(x) == hash(y)`, as specified here: [Essentials · The Julia Language](https://docs.julialang.org/en/v1/base/base/#Base.hash)

In most cases this is extremely simple. Something like:

```julia
function Base.hash(x::Foo, h::UInt)
  hash(x.a, h)
end

```

would work just fine.

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [May 26, 2021, 12:50am UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/9 "2021-05-26T00:50:59Z")

</div>

Thanks rdeits. I’m not familiar with any of this. 😥

I want this to work for any number, so I type with `Number`, right?

```
struct Foo
   a::Vector{Number}
end

```

On the one hand:

```
julia> Base.isequal(x::Foo, y::Foo) = x.a == y.a
julia> Foo([1]) == Foo([1]) 
false 

```

On the other hand:

```
julia> Base.:(==)(x::Foo, y::Foo) = x.a == y.a
julia> Foo([1]) == Foo([1]) 
true

```

So there’s a subtle difference between `==` and `isequal`.

And what is this for?

```
julia> Base.hash(x::Foo, h::UInt) = hash(x.a, h)

julia> hash(Foo([1]))
0x8c5e337b3aca66f1

julia> hash(Foo([1])) == hash(Foo([1]))
false

```

So while now `Foo([1]) == Foo([1]) ` has become `true`, we have `hash(Foo([1])) == hash(Foo([1]))` is `false`. What do I do now?

What I gather from the docs is that if you create your own definition of equality between two things, you would also make sure that the two things are mapped to the same hash. As for what a hash is, I found this definition:

> A hash is a function that converts one value to another. […] hashes are used to index data. Hashing values can be used to map data to individual “buckets” within a hash table. Each bucket has a unique ID that serves as a pointer to the original data. This creates an index that is significantly smaller than the original data, allowing the values to be searched and accessed more efficiently. ([source](https://techterms.com/definition/hash))

The docs are short enough to be quoted in full:

> Base.hash — Function
> 
> ```
> hash(x[, h::UInt])
> 
> Compute an integer hash code such that `isequal(x,y)` implies `hash(x)==hash(y)`. The optional second argument `h` is a hash code to be mixed with the result.
> 
> New types should implement the 2-argument form, typically by calling the 2-argument `hash` method recursively in order to mix hashes of the contents with each other (and with `h`). Typically, any type that implements `hash` should also implement its own `==` (hence `isequal`) to guarantee the property mentioned above. Types supporting subtraction (operator `-`) should also implement [`widen`](@ref), which is required to hash values inside heterogeneous arrays.
> 
> ```

---

<div class="post-metadata">

**Author:** ![ettersi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ettersi/32/6829_2.png) [@ettersi](https://discourse.julialang.org/u/ettersi)\
**Post date:** [May 26, 2021, 4:57am UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/10 "2021-05-26T04:57:18Z")

</div>

> [@ptoche](#):
>
> I want this to work for any number, so I type with `Number`, right?
> 
> ```julia
> struct Foo
> a::Vector{Number}
> end
> 
> ```

I would recommend

```julia
struct Foo{T <: Number}
   a::Vector{T}
end

```

If you don’t understand the relative pros and cons of your proposal and mine, then I would recommend you open another topic since this issue is orthogonal to the main issue of this topic.

* * *

> [@ptoche](#):
>
> So there’s a subtle difference between `==` and `isequal` .

Have a look at the docstrings for `==` and `isequal`. The gist is that you should define only `==` unless you know what you are doing.

* * *

> [@ptoche](#):
>
> And what is this [hashes] for?

Hash functions are a very subtle topic, which is why I did not mention `Base.hash` initially. If you really want to know all the details about this, then I recommend you have a look at a couple of references online until you find one that works for you. If not, just go with what you proposed:

> [@ptoche](#):
>
> ```julia
> julia> Base.hash(x::Foo, h::UInt) = hash(x.a, h)
> 
> ```

After defining this method, I get

```julia
julia> hash(Foo([1])) == hash(Foo([1]))
true

```

so I believe you obtaining

> [@ptoche](#):
>
> ```julia
> julia> hash(Foo([1])) == hash(Foo([1]))
> false
> 
> ```

must be a consequence of some outdated method definitions. Try restarting your Julia REPL and repeating your experiment.

---

<div class="post-metadata">

**Author:** ![ptoche](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ptoche/32/23554_2.png) [@ptoche](https://discourse.julialang.org/u/ptoche)\
**Post date:** [May 26, 2021, 5:53am UTC](https://discourse.julialang.org/t/passing-method-arguments-tuple-vs-dict/61755/11 "2021-05-26T05:53:25Z")

</div>

I have already accepted your answer from all the way up this thread. Thanks! I was initially only interested in understanding the behaviour of `==`, with no plans to change its behaviour. I’m sure there are good reasons it behaves this way, and I have no plan to touch it. (If I’m hit by another unexpected `false`, I won’t care so much and move on)

Having said that, further down the discussion Tamas and Robin mentioned `hash`, which piqued my curiosity, as I’ve seen that come up in code once in a while (and the “don’t forget” made it sound possibly important). I thought perhaps this is the day I finally understand what it is for. But **maybe not**. 🤣

I did have a look at the docs for `==` and `isequal` before posting, but the reason for the different behaviour did not jump out. The main difference stated in the doc is the treatment of floating point numbers and missing values, but there are none here, so I don’t know what’s going on. Here’s a quote from the doc:

> Similar to [`==`](https://docs.julialang.org/en/v1/base/math/#Base.:==), except for the treatment of floating point numbers and of missing values.

As for the last point, you’re absolutely right, I messed up somewhere, it does work as expected: 😳

> Try restarting your Julia REPL and repeating your experiment.

Thanks again. 👍
