Question on manual subsection: Extracting the type parameter from a super-type

I think the manual has a bad example. Before I explain, I think the discussion is getting a little confused; the manual is showing hypothetical source code. If you run it in your own module or REPL, those scopes are accessing your own personal AbstractArray and eltype definitions, not the ones in Base. Avoid the types, and rename functions if you want to try them out, e.g. eltype to eltype_correct.

Back to the point, the manual is trying to make a distinction between Type{<:AbstractArray{T}} and Type{AbstractArray{T}} in the argument annotations. The former specifies arguments being any subtype of AbstractArray, like Array{Int, N} where N, but the latter only specifies AbstractArray itself. T being in the method’s where clause means the inputs must provide a specific type for T.

The supertype-using eltype_wrong method does work on any subtype of AbstractArray, but it does not specify the parameter T we want; instead it tries to recursively supertype its way to AbstractArray so the other eltype_wrong methods can take it. It is indeed correct that if supertype doesn’t work, eltype_wrong doesn’t work.

However, the correct code as is wouldn’t work either because Union{AbstractArray{Int}, AbstractArray{Float64}} does not have a specific type for T, despite being a subtype of AbstractArray. The example has an easy fix, make the types in the Union share a type for T:

eltype_correct(Array{Int,3}) # Int
eltype_correct(Union{Array{Int,1}, Array{Int,3}}) # Int
eltype_wrong(Array{Int,3})   # Int
eltype_wrong(Union{Array{Int,1}, Array{Int,3}})   # errors

Incidentally, this is where it is important to specify parameters belonging to the argument versus the method. A version of the correct code for the number of dimensions would look like

my_ndims(::Type{<:AbstractArray{T,N} where T}) where {N} = N
my_ndims(Union{Array{Int,1}, Array{Bool,1}}) # 1

Base.ndims now behaves like this, but it used to error on unspecific T like this Union or Array{T,1} where T because its method had both parameters {T,N} (issue #40682).

2 Likes