This repository has been archived by the owner on Feb 7, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
traitdispatch.jl
260 lines (210 loc) · 5.67 KB
/
traitdispatch.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# ###############
# # recreate manual-traitdispatch.jl: f2
# @traitfn ttf2{X,Y<:Integer; D1{Y}, D4{X,Y}}(x::X,y::Y) = x + sin(y)
# @traitfn ttf2{S,T<:Integer; D1{S}, D1{T} }(s::S,t::T) = sin(s) - sin(t)
# @traitfn ttf2{X,Y<:FloatingPoint; D1{X}, D1{Y} }(x::X,y::Y) = cos(x) - cos(y)
# @test ttf2(4,5)==(4 + sin(5))
# @test ttf2(4,5.) == cos(4)-cos(5.)
# @test ttf2(MTT1(5),4) == sin(5)-sin(4)
# @test ttf2(MTT2(5),3) == sin(3)+5
# @test length(methods(f2))==length(methods(ttf2))
# note that some of below functions are also tested in perf/perf.jl.
# So a update here might need an update there.
################
@traitfn ft1{X,Y; Eq{X,Y}}(x::X,y::Y) = x==y
ff1(x,y) = x==y
@test ff1(4,5)==ft1(4,5)
#################
@traitfn function ft2{X,Y; Arith{X,Y}}(x::X,y::Y)
out = zero(promote(x,y)[1])
for xe in 1:round(Int,x)
out += xe + y
end
out
end
function ff2{X,Y}(x::X,y::Y)
out = zero(promote(x,y)[1])
for xe in 1:round(Int,x)
out += xe + y
end
out
end
@test ff2(7.3,5.)==ft2(7.3,5.)
##################
@traitfn ft3{X1,X2; IsIterable{X1}}(x::X1,y::X2) = (out=X2[]; for i in x; push!(out,i+y) end; out)
ff3{Y}(x,y::Y) = Y[i+y for i in x]
@test ff3([1:10;],5)==ft3([1:10;],5)
@test ff3(BigFloat[1:10;],BigInt(5))==ft3(BigFloat[1:10;],BigInt(5))
###############
@traitdef MyTr{X,Y} begin
foobar(X,Y) -> Bool
end
type A
a::Int
end
foobar(a::A, b::A) = a.a==b.a
@test istrait(MyTr{A,A}) # true
@test istrait(MyTr{Int,Int})==false
# make a function which dispatches on traits:
@traitfn ft111{X,Y; Cmp{X,Y}}(x::X,y::Y) = x>y ? 5 : 6
@traitfn ft111{X,Y; MyTr{X,Y}}(x::X,y::Y) = foobar(x,y) ? -99 : -999
@test ft111(4,5)==6
@test ft111(A(5), A(6))==-999
@test_throws TraitException ft111("asdf", 5)
foobar(a::String, b::Int) = length(a)==b
@test ft111("asdf", 4)==-99
## dispatch using subtraits
@traitdef MyTr2{X,Y} <: MyTr{X,Y} begin
bar(X,Y) -> Bool
end
@traitfn gt1{X,Y; MyTr2{X,Y}}(x::X,y::Y) = "MyTr2"
@traitfn gt1{X,Y; MyTr{X,Y}}(x::X,y::Y) = "MyTr"
type B1
a::Int
end
foobar(a::B1, b::B1) = a.a==b.a
type B2
a::Int
end
foobar(a::B2, b::B2) = a.a==b.a
bar(a::B2, b::B2) = a.a==b.a
@test istrait(MyTr{B1,B1}) # true
@test istrait(MyTr2{B1,B1})==false
@test istrait(MyTr2{B2,B2})
@test gt1(B1(1), B1(1))=="MyTr"
@test gt1(B2(1), B2(1))=="MyTr2"
##########
## adding trait methods to existing functions:
@traitdef MyTr7{X} begin
bobo(X) -> String
end
abstract AMTyp7
type MTyp71 <: AMTyp7
end
type MTyp72 <: AMTyp7
end
# add to above trait
@traitimpl MyTr7{MTyp71} begin
bobo(X::MTyp71) = "Yeah"
end
import Base.sin
@traitfn sin{X; MyTr7{X}}(x::X) = bobo(x)
@test sin(MTyp71())=="Yeah"
@test_throws TraitException sin(MTyp72())
@traitfn Base.cos{X; MyTr7{X}}(x::X) = bobo(x)
@test cos(MTyp71())=="Yeah"
@test_throws TraitException cos(MTyp72())
######
# Ambiguities
######
@traitdef TrTr1{X} begin
len1(X)
end
@traitfn tf7465{X<:Integer,Y; TrTr1{X}}(x::X,y::Y) = x-y
@traitfn tf7465{X<:Integer,Y; TrTr1{Y}}(x::X,y::Y) = x+y
@traitimpl TrTr1{Int} begin
len1(x::Int) = 5
end
# now ambiguous:
@test_throws Traits.TraitException tf7465(5,6)
# resolve
@traitfn tf7465{X<:Integer,Y; TrTr1{X}, TrTr1{Y}}(x::X,y::Y) = x*y
@test tf7465(5,6)==5*6
@traitdef TrTr22{X,Y} <: TrTr1{X}, TrTr1{Y} begin
# empty
end
@traitfn tf7465{X<:Integer,Y; TrTr22{X,Y}}(x::X,y::Y) = x*y*1000
# errors again because ambigours again
@test_throws Traits.TraitException tf7465(5,6)
## single argument ambiguities
####
@traitdef TrTr2{X} begin
len2(X)
end
@traitfn tttf{X; TrTr1{X}}(x::X) = len1(x)
@traitfn tttf{X; TrTr2{X}}(x::X) = len2(x)
@test tttf(5)==len1(5) # works as TrTr2{Int} is not a trait
@traitimpl TrTr1{Float64} begin
len1(x::Float64) = 5
end
@traitimpl TrTr2{Float64} begin
len2(x::Float64) = 55
end
@test_throws Traits.TraitException tttf(5.) # errors
@traitfn tttf{X; TrTr1{X}, TrTr2{X}}(x::X) = len2(x) # pick len2 over len1
@test tttf(5.)==len2(5.)
# # this can also be resolved by using a sub-trait, essentially equivalent:
# @traitdef STrTr{X} <: TrTr1{X}, TrTr2{X} begin
# # empty
# end
# # no need to implement it for Float64: it's already a member:
# @test istrait(STrTr{Float64})
## test resolution of single argument ambiguities with subtraits
####
# came up here: https://github.com/mauro3/Traits.jl/pull/4#issuecomment-69742371
@traitdef U1{X} begin
u1(X)
end
@traitdef U2{X} <: U1{X} begin
u2(X)
end
@traitdef UU1{X} <: U1{X} begin
uu1(X)
end
@traitdef UU2{X} <: U2{X} begin
uu2(X)
end
@traitimpl U1{Int} begin
u1(x::Int) = 1
end
@traitimpl U2{Int} begin
u2(x::Int) = 2
end
@traitimpl UU1{Int} begin
uu1(x::Int) = 11
end
@traitimpl UU2{Int} begin
uu2(x::Int) = 12
end
@traitfn tttf238{X; UU1{X}}(x::X) = "this should loose"
@traitfn tttf238{X; UU2{X}}(x::X) = "this should win"
# This test in traitdispatch.jl should probably pass:
if dispatch_bug1
@test_throws Traits.TraitException tttf238(5)=="this should win"
else
@test tttf238(5)=="this should win"
end
# however if U2 were a subtrait of something else but U1 then dispatch should be ambiguous:
@traitdef V1{X} begin
v1(X)
end
@traitdef Other1{X} begin
other1(X)
end
@traitdef V2{X} <: Other1{X} begin
v2(X)
end
@traitdef VV1{X} <: V1{X} begin
vv1(X)
end
@traitdef VV2{X} <: V2{X} begin
vv2(X)
end
@traitimpl V1{Int} begin
v1(x::Int) = 1
end
@traitimpl Other1{Int} begin
other1(x::Int) = -1
end
@traitimpl V2{Int} begin
v2(x::Int) = 2
end
@traitimpl VV1{Int} begin
vv1(x::Int) = 11
end
@traitimpl VV2{Int} begin
vv2(x::Int) = 12
end
@traitfn tttf240{X; VV1{X}}(x::X) = "neither should win 1"
@traitfn tttf240{X; VV2{X}}(x::X) = "neither should win 2"
@test_throws Traits.TraitException tttf240(5)