Open eschnett opened 9 years ago
This should work:
@traitfn eltype{V; AbstractVS{V}}(dummy::Type{V}) = veltype(V)
It is an error in the parsing which should be fixed...
Also, I think your first constraint doesn't work. Constraints need to evaluate to a Bool. I think what you want is an associated type:
@traitdef AbstractVS{V} begin
S = veltype{V}
veltype(Type{V}) -> Type{S}
vnewtype(Type{V}, Type{R}) -> Type{W}
vdim(V) -> Int
vnull(Type{V}) -> V
vscale(S, V) -> V
vadd(V, V) -> V
@constraints begin
istrait(AbstractScalar{S})
end
end
The Rust documentation is quite good: https://doc.rust-lang.org/book/associated-types.html
Thanks for the interest in Traits!
Thanks for the pointer to associated types; I know them as "fundeps" in Haskell. I was confused by the syntax (tried to put the S = ...
into the @constraints
sections) which didn't work.
Apart from eltype
, everything is working fine for me now.
Yes, functional dependencies and type families. I looked at those a little but couldn't say that I understand them.
Good to hear that some works. About eltype, did my suggestion above using dummy
not work?
I didn't realize that adding dummy
should help. It does indeed, in the sense that this makes the parse error go away. However, this version of eltype
is then not called.
eltype
is already defined in Base
, and I import this definition and am trying to extend it. Based on what I see from macroexpand(@traitfn ...)
and methods(eltype)
, I don't think this is going to work.
I think it should work. This is what I get (using a drop-in trait Tr
):
julia> using Traits
This warning is ok:
WARNING: Method definition func_for_method(Method, Any, Any) in module Inference at inference.jl:606 overwritten in module Traits at /home/mauro/.julia/v0.4/Traits/src/base_fixes.jl:8.
WARNING: Method definition eltype(Type{Base.Associative{#K<:Any, #V<:Any}}) in module Base at dict.jl:240 overwritten in module Traits at /home/mauro/.julia/v0.4/Traits/src/base_fixes.jl:20.
endof ok-warnings.
julia> @traitdef Tr{X} begin
end
julia> import Base: eltype
julia> @traitfn eltype{V; Tr{V}}(dummy::Type{V}) = veltype(V)
eltype (generic function with 50 methods)
so the Base eltype
function is extended. But I guess you're referring to:
julia> eltype(Int)
Int64
julia> @which eltype(Int)
eltype{T<:Number}(::Type{T<:Number}) at number.jl:9
even though istrait(Tr{Int})
is true. This is expected: first normal type dispatch is done. If type dispatch selects a traitfn-method only then does trait-dispatch come into play. I can see how this is a problem here and potentially in other cases too. I'm not sure though how/whether this can be solved, I'll need to ponder it for a bit.
When I extended eltype
and looked at methods(eltype)
, I think I saw at least generic versions that should match everything. (Why -- shouldn't this have been caught as an error by Julia, or shouldn't the second definition have overridden the first?) In particular, Base defines
eltype(::Type{Any})
as a fallback.
The Traits-generated version looked like
eltype{S}(dummy::Type{S})
which then dispatched on the type of S
. This looked to me as if @traitfn
assumed that it provided the only definition of a function, and didn't interact well with previous definitions.
Looking into this a bit further (without using any Traits):
julia> @which eltype(Vector{Int})
eltype(t::DataType) at operators.jl:184
julia> methods(eltype, (Type{Vector{Int}},))
1-element Array{Any,1}:
eltype(t::DataType) at operators.jl:184
julia> f(t::DataType) = 1
f (generic function with 1 method)
julia> f{X}(::Type{X}) = 2
f (generic function with 2 methods)
julia> f(Int)
1
julia> methods(f, (Type{Int},))
1-element Array{Any,1}:
f(t::DataType) at none:1
julia> g{X}(::Type{X}) = 2
g (generic function with 1 method)
julia> g(Int)
2
julia> methods(g, (Type{Int},))
1-element Array{Any,1}:
g{X}(::Type{X}) at none:1
So it looks like the parameterized method is completely shadowed by the DataType
method. Maybe or maybe not a bug in Julia? Generally dispatch using Type
and DataType
has not been quite ironed out: https://github.com/JuliaLang/julia/issues?utf8=%E2%9C%93&q=DataType+is%3Aissue+author%3Amauro3
Hmm, this doesn't help, does it?
I want to define
eltype
via@traitfn
.eltype
takes a type as argument, not a value. Could you give some advice?For clarity, I start by defining an
AbstractVS
trait, an abstract vector space over a scalar field:veltype
should return the type of the scalar field of the vector space, and takes a type as argument. For example,veltype(Array{Int}) = Int
. This seems to work fine.I then want to implement
eltype
as trait function. The naive version looks like this:This leads to an error since Traits.jl wants to convert
Type{V}
to a symbol. I tried a few other approaches, including this:but this also leads to an error (somewhere in
translate_head
smake_trans
).So now I'm trying to define this trait function manually. I'm not worried about a nice syntax at the moment -- this can be added later. Could you give me a hint?