Type assertion for parametric constructors behaves strangely

struct A{T<:Real, N}
       a::T
       A{N}(a::T) where {T,N} = new{T,N}(a)
end

For this simple parametric type, A{2}(1.0) fails with a TypeError,

ERROR: TypeError: in A, in T, expected T<:Real, got a value of type Int64

I find this extremely unintuitive. Why is type assertion T<:Real in the definition of the parametric type A applied to a parameter of its constructor? Am I using the parametric constructors incorrectly?

In your type declaration:

… the type parameter T is restricted to subtype Real:

A{2} fails with a TypeError because 2 doesn’t subtype Real. In fact, 2 is not a type at all.

“Constructors” are merely callable objects (objects with methods) that happen to be types: Constructors are just callable objects.

Note the TypeError gets thrown before an attempt to call the constructor could happen. Example:

julia> struct A{T<:Real, N} end

julia> A{2}
ERROR: TypeError: in A, in T, expected T<:Real, got a value of type Int64
4 Likes

In other words, it’s an upper bound on a type, not a type assertion for an instance. typeassert(object, type) and the syntax object::type in some contexts is a type assertion, and it’s not currently supported in where clauses, including the implicit one in struct definitions.

2 Likes

Thanks for your blazingly fast reply!

I thought constructors are just methods that have the same name as the composite type. Being callable objects indeed makes a lot more sense. Thanks again for clearing up my confusion!

2 Likes

I believe OP’s question was more about why the constructor of a parametric (composite) type can’t have a different signature of type parameters.

In other words, can a type A{T<:Real, N1} have a constructor A{N2}(args...) where N2 corresponds to N1 even though it’s in the same position as T?

If my understanding is correct, this is IMO a more relevant issues where I had the similar discussions with core developers a few years ago.

1 Like