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
endThis 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
endNote 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
endThis 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) -> ysReturn an array
yssuch that every element inxswith the same index is mapped withf.The element type of
ysis 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.