Define a parametric type with parameters S
and T
(S
is intended to be an integer, and T is intended to be a floating-point number):
struct FooBar{S,T}
x::S
y::T
FooBar{S,T}(x,y) where {S,T} = new(x,y)
end
Define an external constructor with only the second parameter T
:
FooBar{T}(y) where {T} = FooBar{Int,T}(0,y)
The external constructor works:
julia> FooBar{Float64}(1.0)
FooBar{Int64, Float64}(0, 1.0)
Now, define the same parametric type and external constructor, except that S
and T
are limited with their supertypes as S<:Integer
and T<:AbstractFloat
:
struct Foo{S<:Integer,T<:AbstractFloat}
x::S
y::T
Foo{S,T}(x,y) where {S,T} = new(x,y)
end
Foo{T}(y) where {T} = Foo{Int,T}(0,y)
The external constructor generates an error:
julia> Foo{Float64}(1.0)
ERROR: TypeError: in Foo, in S, expected S<:Integer, got Type{Float64}
Stacktrace:
[1] top-level scope
@ REPL[14]:1
Here, the parameter T
is the first (and only) parameter used in the signature of the external constructor. Somehow Julia seems to think that it should also be the first parameter of the type definition and therefore it has to be <:Integer
.
To verify this hypothesis, define another parametric type and external constructor, but use the first parameter S
of the type definition in the signature of the external constructor:
struct Bar{S<:Integer,T<:AbstractFloat}
x::S
y::T
Bar{S,T}(x,y) where {S,T} = new(x,y)
end
Bar{S}(x) where {S} = Bar{S,Float64}(x,1.0)
Now the external constructor does not generate an error:
julia> Bar{Int}(0)
Bar{Int64, Float64}(0, 1.0)
Is this a bug in Julia? Here is the version info:
julia> VERSION
v"1.9.2"