mauro3 / Traits.jl

Exploration of traits in Julia
Other
39 stars 6 forks source link

Subtypes in @traitdef #2

Closed mindbound closed 9 years ago

mindbound commented 9 years ago

How would one write correctly e.g. the following,

@traitdef Foo{X} begin
    fnx{Y <: Integer}(X, Y) -> Integer
end

i.e. so that Y can only be a subtype of Integer? I assume it would require a combination of associated types and @constraints but I can't seem to figure out the details from the documentation. TIA.

mauro3 commented 9 years ago

Yes, parameterized functions signatures are not allowed in the trait definition. It's not possible to store them in the naive way I'm doing this at the moment: a Dict Function -> type-tuples. Methods actually use TypeVar for storing their signature. So maybe I should try that too but documentation on TypeVar is a bit sparse. Anyway, this works:

@traitdef Foo{X} begin
    fnx(X, Integer) -> Integer
end
fnx(a::ASCIIString, b::Integer) = 5
@assert istrait(Foo{ASCIIString}, verbose=true)

Note that fnx(a::ASCIIString, b::Int) = ... wouldn't work. Not sure how to do it best with invariant containers like arrays though. Any ideas welcome!

mauro3 commented 9 years ago

I had a go at using TypeVar. But because of https://github.com/JuliaLang/julia/issues/9043 it still does not work. Will revisit once progress on https://github.com/JuliaLang/julia/issues/8974 is made, or if I fancy putting my own method_exits together.

There are tests at https://github.com/mauro3/Traits.jl/blob/master/test/traitdef.jl#L167 which illustrate what works and what doesn't.

mindbound commented 9 years ago

Thank you for the clarification. I'll keep an eye on this.

mauro3 commented 9 years ago

I added an example with a work-around. Maybe something along the lines you were thinking in the original post: https://github.com/mauro3/Traits.jl/blob/master/examples/ex_issue2.jl

mindbound commented 9 years ago

Thank you, I'll take a look at it (though more bulky, perhaps this can do the work until the two issues are fixed and you can update your code).

One question though: Given that # tf89(2., Int[1,2]) # errors, shouldn't the declaration be Foo{Integer} instead of Foo{Int} in https://github.com/mauro3/Traits.jl/blob/master/examples/ex_issue2.jl#L30 and https://github.com/mauro3/Traits.jl/blob/master/examples/ex_issue2.jl#L58, or am I misreading something?

mauro3 commented 9 years ago

tf89(2., Int[1,2]) # errors because Foo{Float64} is only defined to work with Vector{UInt8}, see: https://github.com/mauro3/Traits.jl/blob/master/examples/ex_issue2.jl#L25. Although why I put that there escapes me. Does this answer your question?

Anyway, I did a small update so the impls can have type constraint functions. Have a look at the last traitimpl in the example.

mindbound commented 9 years ago

Yes, now it's clear to me. For now I'll be sticking with this approach, it seems usable enough.

mauro3 commented 9 years ago

Cool. Thanks for giving Traits.jl a try! It's pretty rough, I'm sure there will be more issues...

mindbound commented 9 years ago

That's fine, especially given that much of Julia itself is pretty experimental for the time being.

One related-ish question: how do we stand on subtyping the traitimpls themselves (i.e. @traitimpl Foo{X <: Bar})? I can't seem to find any hints in the source or docs.

mauro3 commented 9 years ago

@traitimpl Foo{X <: Bar} begin ..., yep, I guess this could be nice in some instances. But I'll wait for JuliaLang/julia#8974 to clear.

mauro3 commented 9 years ago

The original example in this issue works, actually for quite a while now, since 92b0b376. So closing.

mindbound commented 9 years ago

Thank you, very glad to see this fixed/implemented.

mauro3 commented 9 years ago

Sorry, I was wrong! Whilst it is no error to define:

@traitdef Foo{X} begin
    fnx{Y <: Integer}(X, Y) -> Integer
end

it doesn't work:

julia> fnx{Y<:Integer}(x::Int, y::Y) = 1
fnx (generic function with 1 method)

julia> istrait(Foo{Int}, verbose=true)
Method fnx with call signature (Int64,Y<:Integer) not defined for Foo{Int64}
false

because method_exists doesn't work with TypeVars: https://github.com/JuliaLang/julia/issues/9043

This is in fact what I wrote above but for some reason I thought it was fixed after all. Sorry, I'm just getting up to speed with this again and was a bit confused...

mauro3 commented 9 years ago

@mindbound, now it is fixed. I replaced all method_exists checks with hand-rolled code.

mindbound commented 9 years ago

Thank you. Traits.jl is a great addition to Julia, especially coming from a Haskell-ish background.

mauro3 commented 9 years ago

Thanks a lot! Let me know if you find other missing bits or have other comments.