On Friday, August 22, 2014 01:17:53 PM Jameson Nash wrote:
> Instead of eltype as written, use the following format:
> eltype{T<:...}(::Type{T}) = eltype(super(T))

With this definition:
Base.eltype{T<:MyAbstractType}(::Type{T}) = eltype(super(T))

eltype(MyType{Float32}) yields "Any".


And for the second:
julia> f{M<:MyAbstractType}(::Type{M}) = (M.name){Float32}
f (generic function with 1 method)                                              
                                                      

julia> f(MyType{Float64})
ERROR: type: instantiate_type: expected TypeConstructor, got TypeName
 in f at none:1

It was a good suggestion, it's just that I had already tried it.

--Tim

> 
> This should help with the type inference issue too.
> 
> I think M.name is already the type, so you don't need to use eval (which
> doesn't return the right thing anyways, in the general case)
> 
> Sorry I can't type more clearly on a phone, but I'm hoping this will be
> enough to get you going in the right direction.
> 
> On Friday, August 22, 2014, Tim Holy <tim.h...@gmail.com> wrote:
> > Hi all,
> > 
> > I've come up against a couple of surprising type-manipulation issues and
> > I'm
> > wondering if I'm just missing something. Hoping someone out there knows a
> > better way of doing these manipulations.
> > 
> > The issues arise when I try writing generic algorithms on abstract
> > parametric
> > types that need to make decisions based on both the concrete parameters
> > and
> > the concrete type. Let's start with a simple example:
> > 
> > abstract MyAbstractType{T}
> > 
> > immutable MyType{T} <: MyAbstractType{T}
> > 
> >     a::T
> >     b::T
> > 
> > end
> > 
> > Now let's write a generic "eltype" method:
> > 
> > Base.eltype{M<:MyAbstractType}(::Type{M}) = M.parameters[1]
> > 
> > It's a little ugly to have to use M.parameters[1] here. While I'm curious
> > to
> > know whether I'm missing a simple alternative, I can live with this.
> > 
> > Now let's define some arithmetic operations:
> > 
> > (*)(x::Number, m::MyType) = MyType(x*m.a, x*m.b)
> > (.*)(x::Number, m::MyType) = MyType(x*m.a, x*m.b)
> > 
> > And then try it out:
> > julia> y = MyType(3,12)
> > 
> > julia> 2y
> > MyType{Int64}(6,24)
> > 
> > julia> 2.1y
> > MyType{Float64}(6.300000000000001,25.200000000000003)
> > 
> > 
> > So far, so good. Now let's try something a little more sophisticated:
> > 
> > julia> A = [MyType(3,12), MyType(4,7)]
> > 
> > 2-element Array{MyType{Int64},1}:
> >  MyType{Int64}(3,12)
> >  MyType{Int64}(4,7)
> > 
> > julia> 2A
> > 
> > 2-element Array{Any,1}:
> >  MyType{Int64}(6,24)
> >  MyType{Int64}(8,14)
> > 
> > The problem here is we're getting an Array{Any,1} back. No problem you
> > say,
> > let's try to help type inference out, by specifying that a
> > 
> > ::MyType{Int}*::Float64 is a MyType{Float64}. If we were willing to write
> > 
> > this
> > using concrete types, it would be easy:
> > 
> > Base.promote_array_type{T<:Real, S}(::Type{T}, ::Type{MyType{S}}) =
> > MyType{promote_type(T, S)}
> > 
> > But if we want to just use the abstract type, then I've been unsuccessful
> > in
> > avoiding this construction:
> > 
> > Base.promote_array_type{T<:Real, M<:MyAbstractType}(::Type{T}, ::Type{M})
> > =
> > eval(M.name.name){promote_type(eltype(M), T)}
> > 
> > Ouch! Do we really have to use eval there? This seems likely to be a
> > runtime
> > bottleneck, which seems confirmed by
> > 
> > code_llvm(Base.promote_array_type, (Type{Float64}, Type{eltype(A)}))
> > 
> > Compare it against the version generated when I instead use the concrete
> > type,
> > and you'll see what I mean.
> > 
> > Of course these issues would be easily solved by triangular dispatch or
> > staged
> > functions, but I'm hoping there's another good way that exists today.
> > 
> > --Tim

Reply via email to