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.
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!).
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> struct Point{T}
x::T
y::T
end
julia> isabstracttype(Point)
false
julia> Point{T} where T
Point
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> 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:
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: