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).