Skip to content

Commit

Permalink
Fixed failing test
Browse files Browse the repository at this point in the history
I'm a bit stomped by this test failure as it didn't show up in the CI of PR:
#34

Furthermore, the same issue existed as far back as
#25

I tried to see whether this was introduced in one of the minor
versions of Julia 0.5.  But running the test now locally fails for all
0.5.0, 0.5.1 and 0.5.2.

So, not sure what changed.
  • Loading branch information
mauro3 committed Aug 10, 2017
1 parent b3e5395 commit 17797aa
Show file tree
Hide file tree
Showing 8 changed files with 295 additions and 1 deletion.
67 changes: 67 additions & 0 deletions example/hand-coding-trait.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Tried to use @pure instead of generated functions but no success.
using SimpleTraits

# isimmutable trait with generated function
@traitdef IsImmutable_gen{X}
@generated SimpleTraits.trait{X}(::Type{IsImmutable_gen{X}}) =
X.mutable ? :(Not{IsImmutable_gen{X}}) : :(IsImmutable_gen{X})

# isimmutable trait with pure function
@traitdef IsImmutable_pure{X}
Base.@pure SimpleTraits.trait{X}(x::Type{IsImmutable_pure{X}}) =
x.mutable ? Not{IsImmutable_pure{x}} : IsImmutable_pure{x}


# isimmutable trait with normal function
@traitdef IsImmutable_fn{X}
SimpleTraits.trait{X}(::Type{IsImmutable_fn{X}}) =
X.mutable ? Not{IsImmutable_fn{X}} : IsImmutable_fn{X}

@traitfn f_gen{X; IsImmutable_gen{X}}(x::X) = true
@traitfn f_gen{X; !IsImmutable_gen{X}}(x::X) = false

@traitfn f_pure{X; IsImmutable_pure{X}}(x::X) = true
@traitfn f_pure{X; !IsImmutable_pure{X}}(x::X) = false

@traitfn f_fn{X; IsImmutable_fn{X}}(x::X) = true
@traitfn f_fn{X; !IsImmutable_fn{X}}(x::X) = false

immutable A end
type B end

@code_warntype f_gen(A())
@code_warntype f_pure(A())
@code_warntype f_fn(A())


# isimmutable trait with generated function
@traitdef IsBits_gen{X}
@generated SimpleTraits.trait{X}(::Type{IsBits_gen{X}}) =
!isbits(X) ? :(Not{IsBits_gen{X}}) : :(IsBits_gen{X})

# isimmutable trait with pure function
@traitdef IsBits_pure{X}
Base.@pure SimpleTraits.trait{X}(x::Type{IsBits_pure{X}}) =
!isbits(X) ? Not{IsBits_pure{x}} : IsBits_pure{x}


# isimmutable trait with normal function
@traitdef IsBits_fn{X}
SimpleTraits.trait{X}(::Type{IsBits_fn{X}}) =
!isbits(X) ? Not{IsBits_fn{X}} : IsBits_fn{X}

@traitfn g_gen{X; IsBits_gen{X}}(x::X) = true
@traitfn g_gen{X; !IsBits_gen{X}}(x::X) = false

@traitfn g_pure{X; IsBits_pure{X}}(x::X) = true
@traitfn g_pure{X; !IsBits_pure{X}}(x::X) = false

@traitfn g_fn{X; IsBits_fn{X}}(x::X) = true
@traitfn g_fn{X; !IsBits_fn{X}}(x::X) = false

immutable A end
type B end

@code_warntype g_gen(A())
@code_warntype g_pure(A())
@code_warntype g_fn(A())
94 changes: 94 additions & 0 deletions example/readme.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# The example in the README.md
using SimpleTraits
import Compat.String

# Traits are defined with `@traitdef`:
@traitdef IsNice{X}
@traitdef BelongTogether{X,Y} # traits can have several parameters

# All traits have one or more (type-)parameters to specify the type to
# which the trait is applied. For instance `IsNice{Int}` signifies that
# `Int` is a member of `IsNice` (although whether that is true needs to be
# checked with the `istrait` function). Most traits will be
# one-parameter traits, however, several parameters are useful when
# there is a "contract" between several types.


# Add types to a trait-group with `@traitimpl`:

@traitimpl IsNice{Int}
@traitimpl BelongTogether{Int,String}


# It can be checked whether a type belongs to a trait with `istrait`:
using Base.Test
@test istrait(IsNice{Int})
@test !istrait(BelongTogether{Int,Int}) # only BelongTogether{Int,String} was added above

# Functions which dispatch on traits are constructed like:
@traitfn f{X; IsNice{X}}(x::X) = "Very nice!"
@traitfn f{X; !IsNice{X}}(x::X) = "Not so nice!"

# This means that a type `X` which is part of the trait `IsNice` will
# dispatch to the method returning `"Very nice!"`, otherwise to the one
# returning `"Not so nice!"`:
@test f(5)=="Very nice!"
@test f(5.)=="Not so nice!"


# Similarly for `BelongTogether` which has two parameters:
@traitfn f{X,Y; BelongTogether{X,Y}}(x::X,y::Y) = "$x and $y forever!"
@test f(5, "b")=="5 and b forever!"
@test_throws MethodError f(5, 5)

@traitfn f{X,Y; !BelongTogether{X,Y}}(x::X,y::Y) = "$x and $y cannot stand each other!"
@test f(5, 5)=="5 and 5 cannot stand each other!"

# Note that for a particular generic function, dispatch on traits can only work
# on one trait for a given signature. Continuing above example, this
# *does not work* as one may expect:

@traitdef IsCool{X}
@traitfn f{X; IsCool{X}}(x::X) = "Groovy!"


# @traitdef IsNice{X}
# @traitdef BelongTogether{X,Y} # traits can have several parameters
# # ```
# # All traits have one or more (type-)parameters to specify the type to
# # which the trait is applied. For instance `IsNice{Int}` signifies that
# # `Int` is a member of `IsNice` (although whether that is true needs to be
# # checked with the `istrait` function). Most traits will be
# # one-parameter traits, however, several parameters are useful when
# # there is a "contract" between several types.


# # Add types to a trait-group with `@traitimpl`:
# @traitimpl IsNice{Int}
# @traitimpl BelongTogether{Int,String}


# # It can be checked whether a type belongs to a trait with `istrait`:
# using Base.Test
# @test istrait(IsNice{Int})
# @test !istrait(BelongTogether{Int,Int}) # only BelongTogether{Int,String} was added above

# # Functions which dispatch on traits are constructed like:

# @traitfn f{X; IsNice{X}}(x::X) = 1
# @traitfn f{X; !IsNice{X}}(x::X) = 2

# # This means that a type `X` which is part of the trait `IsNice` will
# # dispatch to the method returning `1`, otherwise to the one returning `2`:

# @test f(5)==1
# @test f(5.)==2

# #Similarly for `BelongTogether` which has two parameters:

# @traitfn f{X,Y; BelongTogether{X,Y}}(x::X,y::Y,z) = 1
# @test f(5, "b", "a")==1
# @test_throws MethodError f(5, 5, "a")==2

# @traitfn f{X,Y; !BelongTogether{X,Y}}(x::X,y::Y,z) = 2
# @test f(5, 5, "a")==2
15 changes: 15 additions & 0 deletions notes.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
* TODO
- [X] add Base-traits
- [X] Not{Not{}}
- [ ] merge with Traits.jl
- in Traits.jl a
- [ ] think about type hierarchies using subtyping and how that would
mesh with Traits.jl

* Examples
- [ ] hash trait: [[mu4e:msgid:CAH%2BJbz%2B%3DwU5gVYb0C-b3%3DjNeK2%3Ds5ms3wmqWdu2LAhaBD%2BiiBw@mail.gmail.com][Re: {julia-users} The unique function and iterables of custom composite types]]

* add to base
- include it in sysimg.jl
- figure out where in the boot-strap it goes to

4 changes: 4 additions & 0 deletions src/SimpleTraits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,14 @@ macro traitimpl(tr)
$fnhead = $trname{$(paras...)}
VERSION < v"0.6-" && ($isfnhead = true) # Add the istrait definition as otherwise
# method-caching can be an issue.
nothing
end
else
return quote
$fnhead = Not{$trname{$(paras...)}}
VERSION < v"0.6-" && ($isfnhead = false) # Add the istrait definition as otherwise
# method-caching can be an issue.
nothing
end
end
elseif tr.head==:call
Expand All @@ -177,12 +179,14 @@ macro traitimpl(tr)
P1 = $P1
return $fn($(P2...)) ? :($Tr{$(P1...)}) : :(Not{$Tr{$(P1...)}})
end
nothing
end)
else
return esc(quote
function SimpleTraits.trait{$(P1...)}(::Type{$Tr{$(P1...)}})
return $fn($(P2...)) ? $Tr{$(P1...)} : Not{$Tr{$(P1...)}}
end
nothing
end)
end
else
Expand Down
2 changes: 1 addition & 1 deletion test/base-traits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ type T9867 end
@test istrait(IsCallable{T9867})

@test istrait(IsIterator{Array})
@test !istrait(IsIterator{Cmd})
@test !istrait(IsIterator{Symbol})
@test istrait(IsIterator{Base.UnitRange{Int}})
@test istrait(IsIterator{Base.UnitRange})
23 changes: 23 additions & 0 deletions test/coverage-test.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# julia --code-coverage coverage-test.jl
using SimpleTraits, Base.Test
@traitdef Tr{X}
@traitimpl Tr{Int}

foo() = 1
@traitfn foo(x::::Tr) = 2
@traitfn function foo(x::::(!Tr))
println("here")
println("here")
println("here")
if x>0
return 3
else
return -3
end
end


@test foo()==1
@test foo(1)==2
@test foo(1.0)==3
@test foo(-1.0)==-3
42 changes: 42 additions & 0 deletions test/issue30.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using SimpleTraits

abstract AbFoo

@traitdef IsFoo{X} #<:AbFoo}

type Bar<:AbFoo
y::Float64
end

type Foo<:AbFoo
x::Int
end

isfoo(::Type{Foo}) = true
isfoo(x) = false

@show isfoo(Foo(3))

@show isfoo(Bar(3))

@generated function tmp{X}(::Type{IsFoo{X}})
Tr = IsFoo # /home/mauro/.julia/v0.5/SimpleTraits/src/SimpleTraits.jl, line 185:
P1 = Any[:X] # /home/mauro/.julia/v0.5/SimpleTraits/src/SimpleTraits.jl, line 186:
println(isfoo(X))
return if isfoo(X)
:($Tr{$(P1...)})
else
:(SimpleTraits.Not{$Tr{$(P1...)}})
end
end

@show tmp(IsFoo{Foo})


@traitimpl IsFoo{X} <- isfoo(X)

@show istrait(IsFoo{Foo})

@traitfn f{X; IsFoo{X}}(x::X) = "Is Foo"

f(Foo(3))
49 changes: 49 additions & 0 deletions test/tmp.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using SimpleTraits
using SimpleTraits.BaseTraits

_get_type{T}(::Type{T}) = T.name, T.parameters

function check_traitdispatch{Tr}(::Type{Tr}, Args; nlines=5)
@show @macroexpand @traitfn fn_test(x::::Tr) = 1
# @traitfn fn_test(x::::Tr) = 1
# @traitfn fn_test(x::::(!Tr)) = 2
# @assert llvm_lines(fn_test, Args) == nlines

#f(::Tr{Arg}) = 1

#
# @traitfn fn_test(x::::(!Tr)) = 2
# @assert llvm_lines(fn_test, Args) == nlines

#SimpleTraits.traitfn(:(fn_test(x::::Tr) = 1))
#@traitfn fn_test(x::::Tr) = 1

# # @inline fn_test{TT}(x::TT) = fn_test(trait(Tr{TT}), x)
# # fn_test{TT}(::Type{Tr{TT}}, x::TT; ) = 1
# # fn_test{TT}(::Type{Not{Tr{TT}}}, x::TT; ) = 1

# @assert llvm_lines(fn_test, Args) == nlines
end

check_traitdispatch(IsBits, (Int,))


f{T}(::Type{T}) = gg(::T) = T
f(Int)(5)

ff{T}(::Type{T}) = gg(::Type{T}) = T
ff(Int)(Int)

fff{T,TT}(::Type{T}, ::Type{TT}) = gg(::T{TT}) = T
fff(Vector,Int)([1])



g{T}(::Type{T}) = (E = eltype(T); gg(::T) = (T,E) )
g(Vector{Int})([1])

macro mm(Tr, Args=(Int,), nlines=5)
esc( quote
@traitfn test_fn(x::::$Tr) = 1
end)
end

0 comments on commit 17797aa

Please sign in to comment.