# Difference of type covariant in between struct and function

**URL:** <https://discourse.julialang.org/t/difference-of-type-covariant-in-between-struct-and-function/13453>\
**Category:** General Usage\
**Tags:** question\
**Created:** [August 14, 2018, 5:36pm UTC](https://discourse.julialang.org/t/difference-of-type-covariant-in-between-struct-and-function/13453 "2018-08-14T17:36:20Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![shipengcheng1230](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shipengcheng1230/32/4089_2.png) [@shipengcheng1230](https://discourse.julialang.org/u/shipengcheng1230)\
**Post date:** [August 14, 2018, 5:36pm UTC](https://discourse.julialang.org/t/difference-of-type-covariant-in-between-struct-and-function/13453/1 "2018-08-14T17:36:20Z")

</div>

Hello, let’s define a few type hierarchy (on Julia v0.7):

```julia
julia> abstract type T end

julia> abstract type T1 <: T end

julia> abstract type T2 <: T end

```

For the function, it works:

```julia
julia> foo2(x::X) where {X<:Type{<:T}} = "ok"
foo2 (generic function with 1 method)

julia> foo2(T1)
"ok"

julia> foo2(T)
"ok"

```

However, if I construct a `struct` it won’t works,

```julia
julia> struct Foo{X<:Type{<:T}}
       x::X
       end

julia> Foo(T1)
ERROR: TypeError: in Foo, in X, expected X<:(Type{#s12} where #s12<:T), got Type{DataType}
Stacktrace:
 [1] Foo(::Type{T1}) at ./REPL[5]:2
 [2] top-level scope at none:0

```

Then I use the inner constructor which is nearly the same as the function and still doesn’t work:

```julia
julia> struct Foo2{X<:Type{<:T}}
       x::X
       function Foo2(x::X) where {X<:Type{<:T}}
              s = new{x}()
              s.x = x
       end
       end

julia> Foo2(T1)
ERROR: TypeError: in Foo2, in X, expected X<:(Type{#s13} where #s13<:T), got Type{T1}
Stacktrace:
 [1] Foo2(::Type{T1}) at ./REPL[17]:4
 [2] top-level scope at none:0

```

Why wouldn’t my `T1` be passed into `Foo` or `Foo2`? One reason I would do this is trying to dispatch specifically on `T1` and `T2` but also need some generality on `T` somehow.

Thank you!

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 14, 2018, 5:48pm UTC](https://discourse.julialang.org/t/difference-of-type-covariant-in-between-struct-and-function/13453/2 "2018-08-14T17:48:42Z")

</div>

There’s no difference between the acceptable type parameters, the only difference is in type parameter binding in method dispatch. The default constructor is `Foo(x::X) where X` and in this case `X` will only be `typeof(X)` unless it is written as `Foo(x::Type{...}) ...`. `Foo{Type{T1}}(T1)` works.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 14, 2018, 5:53pm UTC](https://discourse.julialang.org/t/difference-of-type-covariant-in-between-struct-and-function/13453/3 "2018-08-14T17:53:06Z")

</div>

> [@shipengcheng1230](#):
>
> ```julia
> function Foo2(x::X) where {X<:Type{<:T}}
> s = new{x}()
> s.x = x
> end
> 
> ```

Firstly, it should be `new{X}`. Secondly, the constraint on `X` does not change what `X` binds to, it still binds to `DataType`. You need to change it to sth like `Foo2(x::Type{X}) where X <: T`. Lastly, `Foo2` is immutable, you cannot assign to a field after consturction.

```julia
julia> abstract type T end

julia> abstract type T1 <: T end

julia> abstract type T2 <: T end

julia> struct Foo3{X<:Type{<:T}}
       x::X
       function Foo3(x::Type{X}) where {X<:T}
              s = new{Type{X}}(x)
       end
       end

julia> Foo3(T1)
Foo3{Type{T1}}(T1)

```

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [August 14, 2018, 5:56pm UTC](https://discourse.julialang.org/t/difference-of-type-covariant-in-between-struct-and-function/13453/4 "2018-08-14T17:56:04Z")

</div>

And finally, you can figure out these all by yourself even without knowing much about the dispatch rule by just checking the value of `x` and `X` in the constructor. It should be more clear at that point what went wrong…
