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

A corner case that trait call does not seem to fall back to base function #4

Open
eisthf opened this issue Mar 17, 2020 · 1 comment

Comments

@eisthf
Copy link

eisthf commented Mar 17, 2020

I tried the following code and the result is not what I expect.

using Traits

IsGoodTrait(x) = IsGoodTrait(typeof(x))
IsGoodTrait(::Type) = false
IsGoodTrait(::Type{<:AbstractFloat}) = true
IsGoodTrait(::Type{<:AbstractString}) = true

# base function
foo(x) = "not implemented"

@traits function foo(x::T) where {T<:Number, IsGoodTrait(T)}
    println("$T has Good trait")
end

I get the following result. Maybe this is a bug?

julia> foo("s")
"not implemented"

julia> foo(1.2)
Float64 has Good trait

julia> foo(1) # I think this should return "not implemented"
ERROR: MethodError: no method matching '__traits__.Main.foo'(::Type{Tuple{Traits.Syntax._BetweenCurliesAndArgs,T} where T<:Number}, ::Int64, ::Traits.Syntax._BetweenArgsAndTypeVars, ::Type{Int64}, ::Traits.Syntax._BetweenTypeVarsAndTraits, ::Val{false})
Closest candidates are:
  '__traits__.Main.foo'(::Type{Tuple{Traits.Syntax._BetweenCurliesAndArgs,T} where T<:Number}, ::Any, ::Traits.Syntax._BetweenArgsAndTypeVars, ::Any, ::Traits.Syntax._BetweenTypeVarsAndTraits, ::Val{true}) at e:\work\julia\test\test.jl:11
  '__traits__.Main.foo'(::Type{Tuple{Traits.Syntax._BetweenCurliesAndArgs,T} where T<:Number}, ::Type{Traits.Syntax.InnerFuncFixedDocSig{Tuple{Pair{:a1,:x}},Tuple{Pair{:T1,:T}},Tuple{Pair{Symbol("Val{IsGoodTrait(T1)}()"),Symbol("var\"'Val{IsGoodTrait(T1)}()'\"::Val{true}")}}}}) at E:\.julia\packages\Traits\EKIlj\src\Syntax\Syntax.jl:464
Stacktrace:
 [1] #foo#9(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(foo), ::Int64) at e:\work\julia\test\test.jl:10
 [2] foo(::Int64) at e:\work\julia\test\test.jl:10
 [3] top-level scope at REPL[3]:1
@schlichtanders
Copy link
Owner

Thanks for reporting. Just checked your example. First the solution, then the explanation.

You have to add the following clause for it to work

@traits function foo(x::T) where {T<:Number}
    "not implemented"
end

Now the reason: @traits dispatch currently works like it constructs an outer function for normal dispatch (here the T<:Number belongs to normal dispatch). And within this outer function a call to an inner function is made which dispatches on respective extra traits.

Hence if you call foo(1), the outer function for your traits dispatch is called, however the respective inner function is only defined for IsGoodTrait(T) == true. Hence you get the no method found error.
With the added fallback, the respective innerfunction has a proper fallback.

But you are right, I myself see that one would like to have a generic fallback possibility. Lets discuss more about if and how something like that would be possible in Future.

Last remark: You can inspect the current definition of a traits definition via @traits_show_implementation foo
and you will see the outer and inner function respectively

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

No branches or pull requests

2 participants