# Struggling with signatures

**URL:** <https://discourse.julialang.org/t/struggling-with-signatures/52935>\
**Category:** New to Julia\
**Created:** [January 6, 2021, 1:00pm UTC](https://discourse.julialang.org/t/struggling-with-signatures/52935 "2021-01-06T13:00:02Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [January 6, 2021, 1:55pm UTC](https://discourse.julialang.org/t/struggling-with-signatures/52935/2 "2021-01-06T13:55:47Z")

</div>

This is called the [_Diagonal Rule_](https://docs.julialang.org/en/v1/devdocs/types/#Diagonal-types).

In general, if you use a type parameter (e.g., `T`) in your signature, Julia expect all values to match the same type. Moreover, type parameters inside parametrict types (in your case, both uses, as `T` is a parameter for `Dict` and a parameter for `Vector`) are considered **invariant**. This means Julia will not accept a supertype (or subtype) over the specified type, only the exactly specified type.

For example, this will work:

```julia
julia> Container(Dict(S1(1) => [S1(2), S2(3)], S2(4) => [S1(5), S2(6)]))
Container(Dict{S,Array{S,1}}())

```

But only because, the key of the `Dict` is inferred to be `S` (because it has both `S1` and `S2` and `S` is the narrowest type that matches both) and every `Vector` value is also inferred to have elements of type `S`. So both types match exactly. If you let a single vector have only elements of one type the code breaks.

```julia
julia> Container(Dict(S1(1) => [S1(2), S2(3)], S2(4) => [S1(5)]))
ERROR: MethodError: no method matching Container(::Dict{S,Array{T,1} where T})

```

The reason is simple. You already created a `Dict` of the wrong type at this point because you relied on inference, and because one `Vector` was inferred to `Vector{S}` and another to `Vector{S1}` Julia probably tried to use something like `Union{Vector{S},Vector{S1}}` (or `Any`). You can fix it, but it would need to make a copy, what I think it is not what you want. See below.

> [@stefkuypers](#):
>
> I want to avoid having to write the explicit types all the times though so I would like to solve it in the function signature. Is this possible?

I see that you have locked the container to the type `S` (instead of leaving it with a parametric type). I am not sure if this is intended, but I will consider it is intended. The problem boils to the fact you already have structures of the wrong types, `Dict{S1, ...}` is not a `Dict{S, ...}` these are distinct types (this is related to the _invariance_ I mentioned above).

```julia
function Container(source::Dict{T, Vector}) where {T <: Any}
       # and here create a vector of the right type (Vector{Tuple{S, Vector{S}}})
       # to pass to the Dict constructor and have a Dict of the right type
       # Note the inner value vectors need to be converted from
       # whichever type of vector (like `Vector{S1}`) to `Vector{S}`.

```

> [@stefkuypers](#):
>
> When creating a collection with several elements of different types, the type of the collection is set to Any. I wonder whether it would be an idea to use a common type ancestor if possible. That would probably mean an alteration to the language though I guess.

The question is not that the Julia language definition says `Any` will be used but that the compiler is free to infer anything that is valid. In my first sample code above, with Julia 1.5.3, it inferred `S`. The language creators did not specify this on purpose, to have more leeway in the way inference is implemented in the compiler. The inference just need to be valid, not tight.

Final observation: you are aware that your last constructor always create empty containers and throw away the arguments, right?

---

_[View the full topic](https://discourse.julialang.org/t/struggling-with-signatures/52935)._
