@@ -43,9 +43,9 @@ it with Not{}, e.g. Not{Tr1{X,Y}}
43
43
Not
44
44
45
45
# Helper to strip an even number of Not{}s off: Not{Not{T}}->T
46
- stripNot {T<:Trait} (:: Type{T} ) = T
47
- stripNot {T<:Trait} (:: Type{Not{T}} ) = Not{T}
48
- stripNot {T<:Trait} (:: Type{Not{Not{T}}} ) = stripNot (T)
46
+ stripNot (:: Type{T} ) where {T <: Trait } = T
47
+ stripNot (:: Type{Not{T}} ) where {T <: Trait } = Not{T}
48
+ stripNot (:: Type{Not{Not{T}}} ) where {T <: Trait } = stripNot (T)
49
49
50
50
"""
51
51
A trait is defined as full-filled if this function is the identity
@@ -63,14 +63,14 @@ Usually this function is defined when using the `@traitimpl` macro.
63
63
However, instead of using `@traitimpl` one can define a method for
64
64
`trait` to implement a trait, see the README.
65
65
"""
66
- trait {T<:Trait} (:: Type{T} ) = Not{T}
67
- trait {T<:Trait} (:: Type{Not{T}} ) = trait (T)
66
+ trait (:: Type{T} ) where {T <: Trait } = Not{T}
67
+ trait (:: Type{Not{T}} ) where {T <: Trait } = trait (T)
68
68
69
69
# # Under the hood, a trait is then implemented for specific types by
70
70
# # defining:
71
71
# trait(::Type{Tr1{Int,Float64}}) = Tr1{Int,Float64}
72
72
# or
73
- # trait{I<:Integer,F<:FloatingPoint} (::Type{Tr1{I,F}}) = Tr1{I,F}
73
+ # trait(::Type{Tr1{I,F}}) where {I<:Integer,F<:FloatingPoint} = Tr1{I,F}
74
74
#
75
75
# Note due to invariance, this does probably not the right thing:
76
76
# trait(::Type{Tr1{Integer,FloatingPoint}}) = Tr1{Integer, FloatingPoint}
@@ -83,7 +83,7 @@ istrait(Tr1{Int,Float64}) => return true or false
83
83
```
84
84
"""
85
85
istrait (:: Any ) = error (" Argument is not a Trait." )
86
- istrait {T<:Trait} (tr:: Type{T} ) = trait (tr)== stripNot (tr) ? true : false # Problem, this can run into issue #265
86
+ istrait (tr:: Type{T} ) where {T <: Trait } = trait (tr)== stripNot (tr) ? true : false # Problem, this can run into issue #265
87
87
# thus is redefine when traits are defined
88
88
"""
89
89
@@ -148,8 +148,8 @@ macro traitimpl(tr)
148
148
push! (paras, esc (v))
149
149
end
150
150
arg = :(:: Type{$trname{$(paras...)}} )
151
- fnhead = :($ curmod. trait {$(curly...)} ( $ arg) )
152
- isfnhead = :($ curmod. istrait {$(curly...)} ( $ arg) )
151
+ fnhead = :($ curmod. trait ( $ arg) where {$ (curly... )})
152
+ isfnhead = :($ curmod. istrait ( $ arg) where {$ (curly... )})
153
153
if ! negated
154
154
return quote
155
155
$ fnhead = $ trname{$ (paras... )}
@@ -171,8 +171,8 @@ macro traitimpl(tr)
171
171
fn = Expr (:call , GlobalRef (SimpleTraits, :! ), fn)
172
172
end
173
173
return esc (quote
174
- function SimpleTraits. trait {$(P1...)} ( :: Type{$Tr{$(P1...)}} )
175
- return $ fn ($ (P2... )) ? $ Tr{$ (P1... )} : Not{$ Tr{$ (P1... )}}
174
+ function SimpleTraits. trait ( :: Type{$Tr{$(P1...)}} ) where { $ (P1 ... )}
175
+ return $ fn ($ (P2... )) ? $ Tr{$ (P1... )} : Not{$ Tr{$ (P1... )}}
176
176
end
177
177
nothing
178
178
end )
@@ -182,16 +182,16 @@ macro traitimpl(tr)
182
182
end
183
183
184
184
# Defining a function dispatching on the trait (or not)
185
- # @traitfn f{X,Y; Tr1{X,Y}}(x::X,y::Y) = ...
186
- # @traitfn f{X,Y; !Tr1{X,Y}}(x::X,y::Y) = ... # which is just sugar for:
187
- # @traitfn f{X,Y; Not{Tr1{X,Y}}}(x::X,y::Y) = ...
185
+ # @traitfn f(x::X,y::Y) where {X,Y; Tr1{X,Y}} = ...
186
+ # @traitfn f(x::X,y::Y) where {X,Y; !Tr1{X,Y}} = ... # which is just sugar for:
187
+ # @traitfn f(x::X,y::Y) where {X,Y; Not{Tr1{X,Y}}} = ...
188
188
189
189
dispatch_cache = Dict () # to ensure that the trait-dispatch function is defined only once per pair
190
190
let
191
191
global traitfn
192
192
function traitfn (tfn, cur_module)
193
193
# Need
194
- # f{X,Y} (x::X,Y::Y) = f(trait(Tr1{X,Y}), x, y)
194
+ # f(x::X,Y::Y) where {X,Y} = f(trait(Tr1{X,Y}), x, y)
195
195
# f(::False, x, y)= ...
196
196
if tfn. head== :macrocall
197
197
hasmac = true
@@ -213,27 +213,53 @@ let
213
213
# trait: expression of the trait
214
214
# trait0: expression of the trait without any gensym'ed symbols
215
215
#
216
+ # oldfn_syntax: set to true if the old parametric syntax is used
217
+ #
216
218
# (The variables without gensym'ed symbols are mostly used for the key of the dispatch cache)
217
219
218
220
fhead = tfn. args[1 ]
219
221
fbody = tfn. args[2 ]
220
222
221
- fname, paras, args0, kwargs = @match fhead begin
222
- f_ {paras__} (args0__;kwargs__) => (f,paras,args0,kwargs)
223
- f_ (args0__; kwargs__) => (f,[],args0,kwargs)
224
- f_ {paras__} (args0__) => (f,paras,args0,[])
225
- f_ (args0__) => (f,[],args0,[])
223
+ # TODO 1.0: remove
224
+ out = @match fhead begin
225
+ f_ {paras__} (args0__;kwargs__) => (f,paras,args0,kwargs,true )
226
+ f_ (args0__; kwargs__) => (f,[],args0,kwargs,false )
227
+ f_ {paras__} (args0__) => (f,paras,args0,[],true )
228
+ f_ (args0__) => (f,[],args0,[],false )
229
+ f_ (args0__; kwargs__) where paras__ => (f,paras,args0,kwargs,false )
230
+ f_ (args0__) where paras__ => (f,paras,args0,[],false )
231
+ end
232
+ if out== nothing
233
+ error (" Could not parse function-head: $fhead . Note that several `where` are not supported." )
226
234
end
235
+ fname, paras, args0, kwargs, oldfn_syntax = out
227
236
haskwargs = length (kwargs)> 0
228
- if length (paras)> 0 && isa (paras[1 ],Expr) && paras[1 ]. head== :parameters
229
- # this is a Traits.jl style function
230
- trait = paras[1 ]. args[1 ]
237
+ # extract parameters and traits from paras and/or args0
238
+
239
+ if length (paras)== 0
240
+ maybe_traitor = true
241
+ else
242
+ if paras[1 ] isa Expr && paras[1 ]. head== :parameters
243
+ maybe_traitor = false
244
+ length (paras)< 2 && error (" Cannot parse function parameters: $para " )
245
+ typs = paras[2 : end ]
246
+ trait = paras[1 ]. args[1 ]
247
+ elseif paras[1 ] isa Expr && paras[1 ]. head== :bracescat
248
+ maybe_traitor = false
249
+ length (paras)!= 1 && error (" Cannot parse function parameters: $para " )
250
+ typs = paras[1 ]. args[1 : 1 ]
251
+ trait = paras[1 ]. args[2 ]
252
+ else
253
+ maybe_traitor = true
254
+ # the processing happens below
255
+ end
256
+ end
257
+ if ! maybe_traitor
231
258
trait0 = trait # without gensym'ed types, here identical
232
- typs = paras[2 : end ]
233
259
typs0 = typs # without gensym'ed types, here identical
234
260
args1 = insertdummy (args0)
235
- else
236
- # This is a Traitor.jl style function. Change it into a Traits.jl function.
261
+ else # This is a Traitor.jl style function (or invalid).
262
+ # Change paras & args0 into a Traits.jl function.
237
263
# Find the traitor:
238
264
typs0 = deepcopy (paras) # without gensym'ed types
239
265
typs = paras
@@ -293,34 +319,64 @@ let
293
319
else
294
320
pushloc = poploc = nothing
295
321
end
296
- # create the function containing the logic
322
+ # create the function containing the logic. Do it separately if old-school parametric functions
323
+ # (TODO : delete the oldfn_syntax branches in Julia 1.0 (or 0.7 already?))
297
324
retsym = gensym ()
298
325
if hasmac
299
- fn = :(@dummy $ fname {$(typs...)} ($ val, $ (strip_kw (args1). .. ); $ (kwargs... )) = ($ pushloc; $ retsym = $ fbody; $ poploc; $ retsym))
326
+ fn = if oldfn_syntax
327
+ :(@dummy $ fname {$(typs...)} ($ val, $ (strip_kw (args1). .. ); $ (kwargs... )) = ($ pushloc; $ retsym = $ fbody; $ poploc; $ retsym))
328
+ else
329
+ :(@dummy $ fname ($ val, $ (strip_kw (args1). .. ); $ (kwargs... )) where {$ (typs... )} = ($ pushloc; $ retsym = $ fbody; $ poploc; $ retsym))
330
+ end
300
331
fn. args[1 ] = mac # replace @dummy
301
332
else
302
- fn = :($ fname {$(typs...)} ($ val, $ (strip_kw (args1). .. ); $ (kwargs... )) = ($ pushloc; $ retsym = $ fbody; $ poploc; $ retsym))
333
+ fn = if oldfn_syntax
334
+ :($ fname {$(typs...)} ($ val, $ (strip_kw (args1). .. ); $ (kwargs... )) = ($ pushloc; $ retsym = $ fbody; $ poploc; $ retsym))
335
+ else
336
+ :($ fname ($ val, $ (strip_kw (args1). .. ); $ (kwargs... )) where {$ (typs... )} = ($ pushloc; $ retsym = $ fbody; $ poploc; $ retsym))
337
+ end
303
338
end
304
339
# Create the trait dispatch function
305
340
ex = fn
306
341
key = (cur_module, fname, typs0, strip_kw (args0), trait0_opposite)
307
342
if ! (key ∈ keys (dispatch_cache)) # define trait dispatch function
308
343
if ! haskwargs
309
- ex = quote
310
- $ fname {$(typs...)} ($ (args1... )) = (Base. @_inline_meta (); $ fname ($ curmod. trait ($ trait),
311
- $ (strip_tpara (strip_kw (args1))... )
312
- )
313
- )
314
- $ ex
344
+ ex = if oldfn_syntax
345
+ quote
346
+ $ fname {$(typs...)} ($ (args1... )) = (Base. @_inline_meta (); $ fname ($ curmod. trait ($ trait),
347
+ $ (strip_tpara (strip_kw (args1))... )
348
+ )
349
+ )
350
+ $ ex
351
+ end
352
+ else
353
+ quote
354
+ $ fname ($ (args1... )) where {$ (typs... )} = (Base. @_inline_meta (); $ fname ($ curmod. trait ($ trait),
355
+ $ (strip_tpara (strip_kw (args1))... )
356
+ )
357
+ )
358
+ $ ex
359
+ end
315
360
end
316
361
else
317
- ex = quote
318
- $ fname {$(typs...)} ($ (args1... );kwargs... ) = (Base. @_inline_meta (); $ fname ($ curmod. trait ($ trait),
319
- $ (strip_tpara (strip_kw (args1))... );
320
- kwargs...
321
- )
322
- )
323
- $ ex
362
+ ex = if oldfn_syntax
363
+ quote
364
+ $ fname {$(typs...)} ($ (args1... );kwargs... ) = (Base. @_inline_meta (); $ fname ($ curmod. trait ($ trait),
365
+ $ (strip_tpara (strip_kw (args1))... );
366
+ kwargs...
367
+ )
368
+ )
369
+ $ ex
370
+ end
371
+ else
372
+ quote
373
+ $ fname ($ (args1... );kwargs... ) where {$ (typs... )} = (Base. @_inline_meta (); $ fname ($ curmod. trait ($ trait),
374
+ $ (strip_tpara (strip_kw (args1))... );
375
+ kwargs...
376
+ )
377
+ )
378
+ $ ex
379
+ end
324
380
end
325
381
end
326
382
dispatch_cache[key] = (haskwargs, args0)
@@ -347,14 +403,14 @@ end
347
403
Defines a function dispatching on a trait. Examples:
348
404
349
405
```julia
350
- @traitfn f{X; Tr1{X}}(x::X,y) = ...
351
- @traitfn f{X; !Tr1{X}}(x::X,y) = ...
406
+ @traitfn f(x::X,y) where {X; Tr1{X}} = ...
407
+ @traitfn f(x::X,y) where {X; !Tr1{X}} = ...
352
408
353
- @traitfn f{X,Y; Tr2{X,Y}}(x::X,y::Y) = ...
354
- @traitfn f{X,Y; !Tr2{X,Y}}(x::X,y::Y) = ...
409
+ @traitfn f(x::X,y::Y) where {X,Y; Tr2{X,Y}} = ...
410
+ @traitfn f(x::X,y::Y) where {X,Y; !Tr2{X,Y}} = ...
355
411
```
356
412
357
- Note that the second example is just syntax sugar for `@traitfn f{X,Y; Not{Tr1{X,Y}}}(x::X,y::Y) = ...`.
413
+ Note that the second example is just syntax sugar for `@traitfn f(x::X,y::Y) where {X,Y; Not{Tr1{X,Y}}} = ...`.
358
414
"""
359
415
macro traitfn (tfn)
360
416
@static if isdefined (Base, Symbol (" @__MODULE__" ))
0 commit comments