Updated to post-tupocalypse Julia (#10380)
The merge of PR #10380 will necessitate quite some work. Until things have settled a bit, Traits is staying on Julia commit 58cef56f523.
Major overhaul of istrait
function. Now it uses custom-programmed
checks instead of method_exists
. This allows parameterized methods
to be used both in the @traitdef
and in the trait implementation.
This may have pushed Traits.jl into usable terrain. Closes issues #2
and #8.
- Allowing symbols and isbits as associated types.
- added ability to make type constructors part of a trait specification. See test at bottom of test/traitdef.jl.
-
added associated type, see Haskell or Rust. Examples are in src/commontraits.jl.
-
using
@doc
system for documentation -
improved trait dispatch when ambiguous with the following algorithm:
- first dispatch on the normal types
Then dispatch on traits using the following rules, terminating when only one or zero possibilities are left:
- find all matching traits
- discriminate using subtraits, i.e. a subtrait will win over its supertrait
- score all traits according to:
1 point for all single parameter traits,
2 points for all two parameter traits,
etc.
Now pick the highest scoring method. - if still ambiguous throw an error
See also examples/ex_dispatch.jl.
-
better testing of the existence of interface methods. Now uses the
method_exists
function. This leads to some problems with parameterised types, however it should work fine when the parameters are specified:julia> istrait(Indexable{Array}) false julia> istrait(Indexable{Array{Int}}) false julia> istrait(Indexable{Array{Int,1}}) true
However there is Julia bug #8959 which can bite here.
This change also necessitated to introduce a label
All
(just a type) to be used in interface functions declarations whereAny
could be used before, for examplefoo(X, All) -> All
. The reason being that signature type checks withmethod_exists
are contravariant, but forBase.return_types
covariant (or is it the other way around? Always confusing me...). Example, specify thatgetindex
is defined but we don't care about the type of the second argument. To get this pastmethod_exists
:julia> method_exists(getindex, (Array{Int,1}, Any)) false julia> method_exists(getindex, (Array{Int,1}, None)) true
So, in the interface specification, we need to write
getindex(X, None)
. Conversely for return types:julia> Base.return_types(getindex, (Array{Int,1}, None)) 0-element Array{Any,1} julia> Base.return_types(getindex, (Array{Int,1}, Any)) 11-element Array{Any,1}: Any ... Any
So now, in the interface specification, we need to write
getindex(X, Any)
. Thus I introducedAll
which gets replaced byAny
orNone
depending on context.