Base.return_type(f, T::Type{<:Tuple})
Infer a possible return type of f
with input argument types T
.
!!! warning
Using `Base.return_type` without understanding the API is likely to cause
undefined behavior.
Base.return_type
returns a type R
such that every return value y
of
f(args...)
for any args <: T
satisfies y isa R
. Note that R
is not
guaranteed to be the tightest type with such property.
The API implemented using Base.return_type
MUST return the result
that does not depend on the inferred type R
. That is to say, the
behavior of Base.return_type
must not be observable by the caller of
the API within the gurantee provided by the API.
Following function is an invalid use-case of Base.return_type
.
function invalid_usecase1(f, xs)
R = Base.return_type(f, Tuple{eltype(xs)})
ys = similar(xs, R)
ys .= f.(xs)
return ys
end
This is because the value the caller get by eltype(ys)
depends on exactly
what Base.return_type
returns. It may be fixed by re-computing the element
type before returning the result.
function valid_usecase1(f, xs)
R = Base.return_type(f, Tuple{eltype(xs)})
ys = similar(xs, R)
ys .= f.(xs)
S = mapfoldl(typeof, Base.promote_typejoin, ys; init = Union{})
if S != R
zs = similar(xs, S)
copyto!(zs, ys)
return zs
end
return ys
end
Note that using isconcretetype
is not enough to safely use
Base.return_type
. Following function is another invalid use-case of
Base.return_type
.
function invalid_usecase2(f, xs)
R = Base.return_type(f, Tuple{eltype(xs)})
if isconcretetype(R)
ys = similar(xs, R)
else
ys = similar(xs, Any)
end
ys .= f.(xs)
return ys
end
This is because whether or not the caller gets Any
element type depends
on if Base.return_type
can infer a concrete return type of the given
function. A fix similar to valid_usecase1
can be used.
Another possible fix for invalid_usecase1
and invalid_usecase2
is to
clarify the API guarantee:
another_valid_usecase1(f, xs::AbstractArray) -> ys
Return an array
ys
such that every element inxs
with the same index is mapped withf
.The element type of
ys
is undefined. It must not be used with generic functions whose behavior depend on the element type ofys
.
However, it is discouraged to define such unconventional API guarantee.