In fairness though, I can see how this would be confusing. You should be able to construct a Point{Real}(1.0, 2) but I guess the compiler won’t auto infer parameterized types as abstract types?

What you see is the so-called “diagonal rule” in action.

Implicitly, Julia defines a constructor Point(x::T, y::T) where {T} = Point{T}(x, y). The diagonal rule is that if a type parameter occurs multiple times in a function signature, then those occurences mean the same concrete type.

You can still manually create Point{Any}(1, 2.0) or add more constructors to your liking.

Note that this uses a different constructor from the one with the diagonal rule, which isn’t recursive despite how it looked.

julia> struct Point{T}
x :: T
y :: T
end
julia> Point(1, 1) # parameter inferred from arguments
Point{Int64}(1, 1)
julia> @which Point(1, 1) # diagonal rule method
Point(x::T, y::T) where T in Main at REPL[29]:2
julia> Point{Real}(1, 1.0) # manually specify parameter
Point{Real}(1, 1.0)
julia> @which Point{Real}(1, 1.0) # manual parameter method
Point{T}(x, y) where T in Main at REPL[29]:2