Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support return type assertions #8

Open
Seelengrab opened this issue Jul 31, 2023 · 3 comments
Open

Support return type assertions #8

Seelengrab opened this issue Jul 31, 2023 · 3 comments
Labels
feature New feature

Comments

@Seelengrab
Copy link
Owner

Seelengrab commented Jul 31, 2023

@timholy brought up a good point in JuliaLang/julia#49973 (comment), namely that sometimes return type assertions are useful. This would (optionally) be checked as well when checking for interface conformity. The syntax to use this would be (in the example of AbstractArrays):

@required AbstractArray begin
    size(::AbstractArray{T,N})::NTuple{N, Int}
    getindex(::AbstractArray{T}, ::Int)::T
end

where the T in getindex would be forced to match. This could potentially be implemented with Base.return_type. Though I do admit not liking relying on inference, there's no way around it in this case.

@stelmo
Copy link

stelmo commented Sep 15, 2023

Hi there, thanks for writing this package, it is really great! We are currently using it to streamline a bigger project we have, and I think it would be nice to be able to check that an implemented type both takes the right kind of arguments and returns something expected. Do you think you will incorporate return type assertions into this package?

@Seelengrab
Copy link
Owner Author

Seelengrab commented Sep 16, 2023

I still want to support this, yes, but the checking part for this is, in general, a bit tricky. Consider this type for example:

struct MyVector{T} <: AbstractVector{T}
    arr::Vector{T}
end
Base.getindex(mv::MyVector{T}, idx::Int) where T = mv.arr[idx]
Base.size(mv::MyVector) = size(mv.arr)

Evidently, this type implements the AbstractVector interface correctly. However, just checking the return types of getindex gives a (maybe surprising) result:

julia> Base.return_types(getindex, (MyVector, Int))
1-element Vector{Any}:
 Any

The return type is Any, because we didn't specify what kinds of elements MyVector holds when querying the return types. This is the correct result - we don't know the element type, so anything can be returned. It does work if we give it some form of concrete type:

julia> Base.return_types(getindex, (MyVector{Union{Int,Float64}}, Int))
1-element Vector{Any}:
 Union{Float64, Int64}

but then you run into the issue of figuring out that relationship in the first place; really, what the interface requires is not that getindex(av::AbstractVector{T}, i::Int)::T holds, but that getindex(av::AbstractVector{T}, i::Int)::eltype(av) holds, because there is no clear/established API for the semantics of a type parameter (& how to extract them). They are usually ad-hoc constructions - and in this case, points to eltype being a requirement of the interface as well (which by default takes the first type parameter of AbstractVector and claims that as the element type).


To be clear, I still want to have the implicit return type assertion work - it's just a bit more tricky and definitely requires "breaking apart" types given when checking an interface into constituent parts, potentially picking Any and getting Any back out (which is not really helpful, I'd imagine). Not at all impossible to do, but requires a bit of care.

@stelmo
Copy link

stelmo commented Sep 16, 2023

That makes sense. I appreciate the detailed answer, it shows you are thinking it through carefully :) Still, even the ability to specify the interface like your package already allows is really very cool, and definitely a step in the right direction for the Julia ecosystem!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature
Projects
None yet
Development

No branches or pull requests

2 participants