Using other Integer types as type parameters

I’ve recently been using a lot of Int16s, and found really unexpected behavior when I ended up plugging one of them in as a type parameter. For example:

You can’t use one to define an NTuple

julia> NTuple{2, Nothing}
Tuple{Nothing,Nothing}

julia> NTuple{Int16(2), Nothing}
ERROR: TypeError: in Vararg, in count, expected Int64, got Int16
Stacktrace:
 [1] top-level scope at none:0

Which leads to problems when you have a type that contains an NTuple

julia> struct Foo{N}
           x::NTuple{N,Int}
       end

julia> foo64 = Foo{2}
Foo{2}

julia> foo16 = Foo{Int16(2)}
Foo{2}

julia> fieldtypes(foo64)
(Tuple{Int64,Int64},)

julia> fieldtypes(foo16)
(Union{},)

I think it would be nice if this just worked, but even if it doesn’t I think it should throw an error when I try to make the struct - I spent a bit of time before realizing what I had done, because I only noticed it when I got

julia> @assert isbitstype(foo64)

julia> @assert isbitstype(foo16)
ERROR: AssertionError: isbitstype(foo16)
Stacktrace:
 [1] top-level scope at none:0

I think isbitstype fails for you since foo16 cannot have a valid instance.

Can’t you just use an integer parameter for NTuple?

Yeah, of course. The problem arose because my variable was an Int16 and I didn’t think to convert it before using it as a type parameter. The solution is easy, which is to convert before using it.

The problem is that Julia lets me create a Foo subtype with an Int16 parameter, but changes Tuple field to a Union{}. I should not be able to make a Foo subtype where the field is not a Tuple - either it should throw an error (like NTuple) or automatically convert to an Int

As I said above, I don’t think this the problem here. You are not “creating” a type with that parameter: types have no lifetime (in the sense values do, ie that validation can happen somewhere). For parametric types, you can pretty much do what you like, eg you can just work with

julia> T1 = AbstractArray{:nonsense,-7}
AbstractArray{:nonsense,-7}

julia> eltype(T1)
:nonsense

as a type. But there cannot be a value with that type.

Similarly, there cannot be a value with type foo16. So Union{} is the right anwer for its field type.

1 Like