# New blog post about Julia parametric types and constructors

**URL:** <https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717>\
**Category:** Teaching & Outreach\
**Tags:** parametric-types, constructors\
**Created:** [September 30, 2024, 11:03am UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717 "2024-09-30T11:03:52Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Maurizio\_Tomasi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maurizio_tomasi/32/384_2.png) [@Maurizio\_Tomasi](https://discourse.julialang.org/u/Maurizio_Tomasi)\
**Post date:** [September 30, 2024, 11:03am UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/1 "2024-09-30T11:03:53Z")

</div>

Hi all,

I have published the first part of a two-part blog post describing how Julia’s parametric constructor works. I wrote this because several of my students use Julia to implement simulation codes, and I have found that this topic is hard for them to grasp. The post is here: [https://ziotom78.github.io/julia/2024/09/30/julia-parametric-types.html](https://ziotom78.github.io/julia/2024/09/30/julia-parametric-types.html).

Since all of my students have a basic knowledge of C++, I inserted a few comments here and there on the similarities and differences between Julia and C++.

I am not an expert on Julia and may have made some mistakes, so I would appreciate it if you could look at this. I will gladly incorporate your suggestions (and give proper credit, of course!).

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [September 30, 2024, 11:20am UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/2 "2024-09-30T11:20:28Z")

</div>

> we enable the definition of several concrete types like `Point{Float64}`, `Point{Int}`, `Point{String}`, etc., and each of them derive from an ancestor type `Point`

I think this is not quite correct as `Point` is not an “ancestor type” as I’d understand it (to me that sounds like an abstract type usually defined with `abstract type`). It’s a `UnionAll` and short for `Point{T} where T`:

```julia
julia> struct Point{T}
           x::T
           y::T
       end

julia> isabstracttype(Point)
false

julia> Point{T} where T
Point

```

---

<div class="post-metadata">

**Author:** ![Maurizio\_Tomasi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maurizio_tomasi/32/384_2.png) [@Maurizio\_Tomasi](https://discourse.julialang.org/u/Maurizio_Tomasi)\
**Post date:** [September 30, 2024, 11:49am UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/3 "2024-09-30T11:49:22Z")

</div>

Hi, @julies; your post prompted me to do some checks. You’re 100% right; things are not as simple as I wrote in the post. See this:

```julia
julia> struct Point{T <: Number}
       x::T
       y::T
       end

julia> supertype(Point{Float64})
Any

julia> Point{Float64} <: Point
true

```

I would have expected `supertype` to return `Point`, because I believed that what Julia was doing is to do the same as the following (invalid) C++ definition:

```cpp
struct Point { };

// This is not C++, but you get the idea: the
// template `Point<T>` derives from the non-template
// class `Point` defined above.
template <typename T>
struct Point : public Point
{
}

```

I believed that the implementation of `<:` used `supertype` internally. Instead, `<:` seems to work using a wider meaning of “derived type”, as it considers both unions and proper type hierarchies:

```julia
julia> Float64 <: Union{Int8, Float64}
true

julia> Float64 <: Real
true

```

Thank you! This was a nice insight, I’ll rework the text and publish a new version soon.

---

<div class="post-metadata">

**Author:** ![Maurizio\_Tomasi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maurizio_tomasi/32/384_2.png) [@Maurizio\_Tomasi](https://discourse.julialang.org/u/Maurizio_Tomasi)\
**Post date:** [October 7, 2024, 11:19am UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/4 "2024-10-07T11:19:42Z")

</div>

The second part of the post is now available: [https://ziotom78.github.io/julia/2024/10/07/julia-parametric-constructors.html](https://ziotom78.github.io/julia/2024/10/07/julia-parametric-constructors.html).

---

<div class="post-metadata">

**Author:** ![PatrickHaecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/patrickhaecker/32/222891_2.png) [@PatrickHaecker](https://discourse.julialang.org/u/PatrickHaecker)\
**Post date:** [October 7, 2024, 12:58pm UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/5 "2024-10-07T12:58:02Z")

</div>

I really like the tutorial.

In part 1, instead of using `sizeof` in

```julia
println("Generic: ", sizeof(Generic(Int8(1), Int8(2))), " bytes")
println("Parametric: ", sizeof(Parametric(Int8(1), Int8(2))), " bytes")

```

I recommend to use `Base.summarysize` and explain that the resulting 18 bytes are 16 + 2 (pointers + UInt8s). Otherwise readers might wonder how the values are stored in `Generic` if the pointers already take 16 bytes.

---

<div class="post-metadata">

**Author:** ![PatrickHaecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/patrickhaecker/32/222891_2.png) [@PatrickHaecker](https://discourse.julialang.org/u/PatrickHaecker)\
**Post date:** [October 7, 2024, 1:24pm UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/6 "2024-10-07T13:24:52Z")

</div>

In preparation to the second tutorial, it probably makes sense to highlight that it is not about (subtype of) abstract field types versus concrete field types for the struct (as you imply with the content at the bottom of the page).  
Rather it is about parametric (possibly subtype of abstract) type parameters versus abstract field types:

```julia
struct ParametricAbstract{T <: Real}
    x::T
    y::T
end

struct Abstract
    x::Real
    y::Real
end

```

```julia
julia> ParametricAbstract(2f0, 2f0) |> Base.summarysize
8

julia> Abstract(2f0, 2f0) |> Base.summarysize
24

```

I think the rule of thumb should be:

- It’s okay and often even encouraged to be (subtype of) abstract in the header (defining the type parameters of a struct or the arguments of a method),
- but you should be specific in the body (using a concrete type or type parameter).

The reason for this rule of thumb is (no surprise here): multiple dispatch (or after thinking a bit more about it) and specialization.

---

<div class="post-metadata">

**Author:** ![PatrickHaecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/patrickhaecker/32/222891_2.png) [@PatrickHaecker](https://discourse.julialang.org/u/PatrickHaecker)\
**Post date:** [October 7, 2024, 1:47pm UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/7 "2024-10-07T13:47:24Z")

</div>

Regarding `Unitful-compatible types` in the second part:  
It’s really great that you highlight the fact that the type should go beyond the machine type.

However, I am deeply convinced, that azimuth and elevation are two totally different types (one defined for 360°, the other for 180°, one defined as the deviation from a plane, the other as a deviation from an axis, one spanning a cylinder when rotating, the other a cone when rotating).

But this is all beyond the point for your example. You could avoid potentially misleading the readers of the tutorial by switching your example to polar coordinates. There, you can focus on the core of the relevant problem.

---

<div class="post-metadata">

**Author:** ![Maurizio\_Tomasi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maurizio_tomasi/32/384_2.png) [@Maurizio\_Tomasi](https://discourse.julialang.org/u/Maurizio_Tomasi)\
**Post date:** [October 7, 2024, 2:54pm UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/8 "2024-10-07T14:54:43Z")

</div>

Thank you, Patrick! I agree that `summarysize` makes the point clearer in the text. You are right about marking subtypes in parametric fields, too. I updated the two posts with your suggestions, as I like them all. Thanks a lot!

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [October 7, 2024, 5:05pm UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/9 "2024-10-07T17:05:38Z")

</div>

> [@Maurizio\_Tomasi](#):
>
> I believed that the implementation of `<:` used `supertype` internally.

`<:` defines Julia’s subtyping. `supertype` is just a (sometimes) convenient helper.

> [@Maurizio\_Tomasi](#):
>
> meaning of “derived type”

Probably don’t want to use that phrasing, “derived type”. It’s highly ambiguous. And it’s not part of the Julia terminology anyway.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [October 7, 2024, 5:16pm UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/10 "2024-10-07T17:16:44Z")

</div>

Looking at [A tutorial about parametric constructors in Julia (1/2) | Maurizio’s blog](https://ziotom78.github.io/julia/2024/09/30/julia-parametric-types.html), there’s an issue with the “Union of parametric types” section, the content, and the title, are misleading/incorrect. E.g.,

> union type `Point`

`Point` isn’t an `Union`, it’s an `UnionAll`. These are very different. Arguably `UnionAll` is, itself, a misleading name, apparently the technical name is “(bounded) existential type” (according to the “Julia subtyping” paper, DOI [10.1145/3276483](https://doi.org/10.1145/3276483)).

REPL example:

```julia
julia> struct Point{T} end

julia> Point isa Union
false

julia> Point isa UnionAll
true

julia> Union{Point{Int}, Point{Float32}}
Union{Point{Float32}, Point{Int64}}

julia> ans isa Union
true

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [October 7, 2024, 5:24pm UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/11 "2024-10-07T17:24:50Z")

</div>

This sentence from the blog post should be corrected, it’s incorrect, or at least highly misleading:

> Parametric types can be **highly** efficient when the type `T` is _concrete_ (i.e., not abstract).

The issue is that “abstract” is ambiguous, in Julia it _sometimes_ refers to any non-concrete type, but it’s AFAIK more proper to use it to refer merely to types declared with `abstract type`. The _latter_ meaning is the one used by `isabstracttype`. Thus `isconcretetype` and `isabstracttype` are _not_ opposites.

EDIT (more than three consecutive replies are not allowed):

A visualization of Julia’s subtyping might also be educational. Given these example Julia types:

```julia
abstract type PointSupertype0 end
abstract type PointSupertype1{T} <: PointSupertype0 end

struct Point{T} <: PointSupertype1{T} end

types = (
    Point, PointSupertype0, PointSupertype1,
    PointSupertype1{Int}, PointSupertype1{<:Int},
    PointSupertype1{Float64}, PointSupertype1{<:Float64},
    Point{Int}, Point{<:Int}, Point{Float64}, Point{<:Float64},
    Point{Union{Int, Float64}}, Point{<:Union{Int, Float64}},
    Union{Point{Int}, Point{Float64}},
    Union{Point{<:Int}, Point{<:Float64}},
)

```

… a Julia script makes a digraph from the subtyping relation, does transitive reduction on it, then produces this GraphViz Dot specification for visualizing:

```sh
digraph='
digraph {
    "Point" -> "PointSupertype1"
    "PointSupertype1" -> "PointSupertype0"
    "PointSupertype1{<:Float64}" -> "PointSupertype1"
    "PointSupertype1{<:Int64}" -> "PointSupertype1"
    "PointSupertype1{Float64}" -> "PointSupertype1{<:Float64}"
    "PointSupertype1{Int64}" -> "PointSupertype1{<:Int64}"
    "Point{<:Float64}" -> "PointSupertype1{<:Float64}"
    "Point{<:Float64}" -> "Union{Point{<:Int64}, Point{<:Float64}}"
    "Point{<:Int64}" -> "PointSupertype1{<:Int64}"
    "Point{<:Int64}" -> "Union{Point{<:Int64}, Point{<:Float64}}"
    "Point{<:Union{Float64, Int64}}" -> "Point"
    "Point{Float64}" -> "PointSupertype1{Float64}"
    "Point{Float64}" -> "Point{<:Float64}"
    "Point{Float64}" -> "Union{Point{Float64}, Point{Int64}}"
    "Point{Int64}" -> "PointSupertype1{Int64}"
    "Point{Int64}" -> "Point{<:Int64}"
    "Point{Int64}" -> "Union{Point{Float64}, Point{Int64}}"
    "Point{Union{Float64, Int64}}" -> "Point{<:Union{Float64, Int64}}"
    "Union{Point{<:Int64}, Point{<:Float64}}" -> "Point{<:Union{Float64, Int64}}"
    "Union{Point{Float64}, Point{Int64}}" -> "Union{Point{<:Int64}, Point{<:Float64}}"
}
'
printf '%s' "$digraph" | dot -Tpng > /tmp/graphviz.png

```

This is the result:

 ![graphviz](https://global.discourse-cdn.com/julialang/original/3X/4/b/4bec158259701cda0823b465e4a127d7b30bae98.png)

---

<div class="post-metadata">

**Author:** ![Maurizio\_Tomasi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maurizio_tomasi/32/384_2.png) [@Maurizio\_Tomasi](https://discourse.julialang.org/u/Maurizio_Tomasi)\
**Post date:** [October 8, 2024, 7:53am UTC](https://discourse.julialang.org/t/new-blog-post-about-julia-parametric-types-and-constructors/120717/12 "2024-10-08T07:53:34Z")

</div>

Thanks, @nsajko , your answer is very insightful! (And the use of `graphviz` to show the hierarchy of the types is awesome.)

I used the term “abstract” because I have found that this is the best way to explain type hierarchies to students with a C++ background. But you are 100% right; the “abstract” term is misleading in the context of Julia. The function `isabstracttype` returns `false` with `Union` types:

```julia
julia> isabstracttype(Union{Int64, Float64})
false

```

However, the chapter of Julia’s manual about [Type unions](https://docs.julialang.org/en/v1/manual/types/#Type-Unions) begins with the statement

> A type union is a special abstract type…

The same wording appears in the paper by Zappa Nardelli et al. you cited (page 113:5):

> A union is an abstract type…

The best thing to do is probably remove the reference to `isabstracttype` from my blog post and reword other parts: avoiding explaining everything is better than making things too complicated for learners.
