# Parametric types - type definition in struct name or struct argument?

**URL:** <https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823>\
**Category:** New to Julia\
**Tags:** question, parametric-types\
**Created:** [March 30, 2023, 4:30am UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823 "2023-03-30T04:30:42Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [March 30, 2023, 4:30am UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823/1 "2023-03-30T04:30:42Z")

</div>

Hi. I am new to Julia and have extremely basic computer science knowledge. I am trying to learn about parametric typing. I’ve done a reasonable amount of internet search and read the documents. Here are two cases which confuse me. Case 1: Both struct definitions work, but the constructor in the second case throws an error. Case 2: The second struct definition does not work. Can someone explain what’s going on? I welcome links to documentation, but would also appreciate an explanation.

```julia
# 1
julia> struct S
       a::Type{Real}
       end

julia> S(Real)
S(Real)

julia> struct S{T<:Type{Real}}
       a::T
       end

julia> S(Real)
ERROR: TypeError: in S, in T, expected T<:Type{Real}, got Type{DataType}

# 2
julia> struct SS{T<:Int64}
       a::T
       end

julia> struct SS{T::Int64}
       a::T
       end
ERROR: syntax: invalid variable expression in "where" around REPL[7]:1

```

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [March 30, 2023, 6:57am UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823/2 "2023-03-30T06:57:25Z")

</div>

Case 2 is the easier one to explain:

- the `T1<:T2` syntax means “the type `T1` is a subtype of the type `T2`”
- the `x::T` syntax means “the object `x` is an instance of the type `T`”

In the former, you’re comparing two types, which is what you want when putting constraints on the type parameter. In the latter, you’re comparing an object with a type, which explains why it doesn’t work to specify the type of `a`.

As a side note, `Int64` is what’s called a concrete type, so it has no descendants, nor can it have any. This means your definition is equivalent to:

```julia
struct SS
    a::Int64
end

```

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [March 30, 2023, 7:01am UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823/3 "2023-03-30T07:01:00Z")

</div>

Case 1 is a bit trickier, I suggest you read [the docs on type selectors](https://docs.julialang.org/en/v1/manual/types/#man-typet-type) first. What are you trying to achieve exactly?

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 30, 2023, 7:22am UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823/4 "2023-03-30T07:22:01Z")

</div>

> [@sadish-d](#):
>
> ```julia
> struct S{T<:Type{Real}}
> a::T
> end
> 
> ```

I’m not 100% sure what’s happening here, but maybe you want

```julia
struct S{T<:Real}
    a::Type{T} 
end

```

?

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [March 30, 2023, 8:27am UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823/5 "2023-03-30T08:27:20Z")

</div>

There’s some voodoo around `Type`, it’s special in some ways. I wouldn’t worry about it as a newcomer. If you have a pragmatic question, ask about it, but poking around `Type` hasn’t really enlightened me either.

That said, FWIW, you could instantiate your first struct with

```julia
julia> S{Type{Real}}(Real)
S{Type{Real}}(Real)

```

What happens is that the default constructor probably uses `typeof` to fill in the types, and `typeof(Real)` is `DataType`. To me it really feels like it should be `Type{Real}`, but… (most likely performance-related) voodoo.

You could add a constructor for your type

```julia
julia> struct S{T<:Type{Real}}
       a::T
       S(::Type{T}) where T = new{Type{T}}(T)
       end

julia> S(Real)
S{Type{Real}}(Real)

```

but really, like [Types · The Julia Language](https://docs.julialang.org/en/v1/manual/types/#man-typet-type) says,

> While `Type` is part of Julia’s type hierarchy like any other abstract parametric type, it is not commonly used outside method signatures except in some special cases.

Don’t use it in struct parameters, there’s no reason to.

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [March 30, 2023, 2:49pm UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823/6 "2023-03-30T14:49:06Z")

</div>

@gdalle , thanks for the note on the syntax. My take away is that you have to use the \<: syntax to compare types, even when you’re comparing concrete types (which have no subtypes). Maybe that’s why I was trying the second approach in case 1. And the struct was already getting defined accurately (thanks for your suggestion though @DNF ), it’s just that I wasn’t using the right constructor, as @cstjean pointed out. Thanks to you all. This helped me.

Edit: @DNF pointed out that I misunderstood what @cstjean said, so the rest of this comment is no longer relevant.

@cstjean, I am not sure I can avoid worrying about types if I want to be proficient at multiple dispatch though. Imagine you have a struct called Ball, and there are balls of different colors. I wanted to dispatch a different method for a Ball of different color. Initially, I was taking colors as a field, so I was creating one method that takes a ball and applies different operations based on if/then conditions inside that method. But then, if I can have Ball{Red}, Ball{Blue}, I can create methods specific to them. And, if I someday added a ball of a new color, I could just add a new method instead of mucking with the one giant method and risk breaking things for all Balls.

So I went against your advice and played with parametric types a bit and did this, which works as I expect it to:

```julia
julia> struct S2{T<:Type{<:Real}}
       a::T
       end

julia> S2{Type{Real}}(Real)
S2{Type{Real}}(Real)

julia> S2{Type{Complex}}(Complex)
ERROR: TypeError: in S2, in T, expected T<:(Type{<:Real}), got Type{Type{Complex}}

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 30, 2023, 5:30pm UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823/7 "2023-03-30T17:30:59Z")

</div>

> [@sadish-d](#):
>
> I am not sure I can avoid worrying about types if I want to be proficient at multiple dispatch though.

The idea wasn’t that you should not worry about types, but that you shouldn’t worry about `Type`.

> [@sadish-d](#):
>
> Imagine you have a struct called Ball, and there are balls of different colors. I wanted to dispatch a different method for a Ball of different color.

What about

```julia
abstract type Color end
struct Red <: Color end
struct Ball{T<:Color} end
Ball(::Type{T}) where {T<:Color} = Ball{T}()

```

Or, instead of the last constructor, a popular pattern these days are

```julia
Ball(::T) where {T<:Color} = Ball{T}()

```

With the first constructor, you do

```julia
julia> Ball(Red)
Ball{Red}()

```

while with the second, you do

```julia
julia> Ball(Red())
Ball{Red}()

```

I don’t really see why you need the `Type` as part of the type parameter.

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [March 30, 2023, 6:19pm UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823/8 "2023-03-30T18:19:24Z")

</div>

@DNF, thanks for clarifying. This is enlightening. What you showed is actually what I wanted. I started at it for 20 mins, and I think what you’re trying to tell me is that instead of doing this:

```julia
struct Ball{T<:Type{<:Color}} end

```

I should do this:

```julia
struct Ball{T<:Color} end

```

And then I can define a constructor that takes a type as a parameter if that’s what I want.

This makes a lot of sense.

=====

I am still confused with the `::`, `{}`, and the `where` syntax. This is what I understand:

- Your first constructor takes a type, a subtype of `Color`, as an argument. That’s what I presume `the(::type)` syntax does.
- Your second constructor takes an instance of some `Color`, takes its type `T`, and creates an instance of `Ball{T}`.
- The `where` statement is necessary if we want to use the `T` on the right hand side of the function definition (I think I read this somewhere).

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 30, 2023, 6:32pm UTC](https://discourse.julialang.org/t/parametric-types-type-definition-in-struct-name-or-struct-argument/96823/9 "2023-03-30T18:32:06Z")

</div>

> [@sadish-d](#):
>
> And then I can define a constructor that takes a type as a parameter if that’s what I want.

Exactly. And then you can decide whether to define a constructor for `Ball(Red)` or `Ball(Red())`.

> [@sadish-d](#):
>
> - Your first constructor takes a type, a subtype of `Color`, as an argument. That’s what I presume `the(::type)` syntax does.
> - Your second constructor takes an instance of some `Color`, takes its type `T`, and creates an instance of `Ball{T}`.

Yes to both.

> [@sadish-d](#):
>
> The `where` statement is necessary if we want to use the `T` on the right hand side of the function definition (I think I read this somewhere).

Yes, you use this syntax in order to capture the type in a variable, `T`. But you could also in stead do

```julia
Ball(c::Color) = Ball{typeof(c)}()

```

and then `Ball(Red())`.
