Thanks for your help, Tom. In the end it looks like this is a dup of https://groups.google.com/forum/#!msg/julia-users/Khe1Eh-K6i0/kxvj3day77AJ <https://groups.google.com/forum/#!msg/julia-users/Khe1Eh-K6i0/kxvj3day77AJ>, and in my particular case the cleanest solution was to implement similar() on my subtypes (as recommended by Tim Holy in that thread). Then I could define the single-index indexing on the supertype and the abstractarray and multidimensional code would construct the appropriate subtype for me. This is described in the Interfaces section of the manual, but I didn’t get at first that similar() was the key and was called by the code in Base to construct your type during indexing.
I’ll see if I can expand the docs there to make my oversight less over-seeable. -s > On Sep 17, 2015, at 5:30 PM, Tom Breloff <[email protected]> wrote: > > Try: > > > # this one for any AbstractFoo that is NOT Foo1 > julia> Base.getindex(foo::AbstractFoo, I...) = Foo2(foo.data[I...]) > getindex (generic function with 185 methods) > > julia> Base.getindex(foo::Foo1, I...) = Foo1(foo.data[I...]) > getindex (generic function with 184 methods) > > julia> f1 = Foo1{2,Float64}(rand(2,2)) > Error showing value of type Foo1{2,Float64}: > ERROR: MethodError: `size` has no method matching > size(::Foo1{2,Float64})SYSTEM: show(lasterr) caused an error > > julia> f1.data # notice we actually did create it... the error was just in > trying to show it > 2x2 Array{Float64,2}: > 0.696612 0.337268 > 0.987464 0.719724 > > julia> tmp = f1[1,:] > Error showing value of type Foo1{2,Float64}: > ERROR: MethodError: `size` has no method matching > size(::Foo1{2,Float64})SYSTEM: show(lasterr) caused an error > > julia> tmp.data > 1x2 Array{Float64,2}: > 0.696612 0.337268 > > > > On Thu, Sep 17, 2015 at 4:14 PM, Spencer Russell <[email protected] > <mailto:[email protected]>> wrote: > On Thu, Sep 17, 2015, at 02:31 PM, Tom Breloff wrote: >> f{T<:AbstractInnerType}(x::AbstractOuterType{T}) = <do something with T> > > I don't quite see how to map that onto my problem (forgive me if I'm just > being dense). I have 3 types: > Foo1{N, T} <: AbstractFoo{N, T} <: AbstractArray{T, 2} > > and I want to define a method (in this case getindex) that accepts any > subtype of AbstractFoo{N, T}. If the given instance is a Foo1{N, T} I want to > call the constructor Foo1(someval). If the instance was a Foo2{N, T} then I'd > want to call Foo2(someval). I think the tricky bit is accepting a Foo1{N, T} > and just extracting the Foo1 part of it. I think that my first attempt: > > Base.getindex{BT{N, T} <: AbstractFoo{N, T}}(foo::BT, I...) = > BT(foo.data[I...]) > > Gets across what I'm trying to do, but is not legal. > > Maybe a clearer way to state the underlying problem is: > > given Foo1{N, T} <: AbstractFoo{N, T} > Foo1{1, Int} is a subtype of both Foo1 and AbstractFoo{1, Int} > super(Foo1{1, Int}) returns AbstractFoo{1, Int}, but I want something that > gives me Foo1. > > Thanks for the help, sorry this seems pretty in-the-weeds. > >> However I would be very careful attaching a parameter N to the number of >> columns of an array. Unless you are sure you'll only have a small handful >> of unique values, you risk creating tons and tons of different types, all >> requiring specialized compilation of every function they touch. > > Re: parameterizing on N - > I'm using this for multichannel audio signals, so the vast majority of the > time N will be 1 or 2, sometimes 4 or 8. Even if it's a different number, I > expect usage will be grouped such that there won't be a whole lot of > different channel counts in the same application. > That said, it's part of the design that I'm not 100% sure on, so once I get > further down the line I may go back on it. > > -s > > >> >> >> >> On Thu, Sep 17, 2015 at 2:10 PM, Spencer Russell <[email protected] >> <mailto:[email protected]>> wrote: >> >> I think my question boils down to: "How do I define a method catches any >> subtype of a parametric supertype, but access the unparameterized part of >> the subtype within the function body?" >> >> Say I have this type: >> >> abstract AbstractFoo{N, T} <: AbstractArray{T, 2} >> >> type Foo1{N, T} <: AbstractFoo{N, T} >> data::Array{T, 2} >> end >> >> Foo1{T}(arr::AbstractArray{T, 2}) = Foo1{size(arr, 2), T}(arr) >> >> So the Foo1 outer constructor sets the type parameter N based on the number >> of columns of the contained array. >> >> When indexed by a Range, I want the returned value to be wrapped in a Foo1 >> type, but it might be parameterized with a different value for N, but I >> can't figure out the right type definition. The plan is to catch types that >> are a subtype of Foo, but call the outer constructor to build the result >> value. >> >> I've tried: >> >> Base.getindex{BT{N, T} <: AbstractFoo{N, T}}(foo::BT, I...) = >> BT(foo.data[I...]) >> >> but apparently that has a malformed type parameter list. >> >> I've also tried >> >> Base.getindex{BT <: AbstractFoo}(foo::BT, I::Idx...) = BT(foo.data[I...]) >> >> But that doesn't get called because Foo1{N, T} is not a subtype of >> AbstractFoo. >> >> What does work is defining >> >> Base.getindex(foo::Foo1, I::Idx...) = Foo1(foo.data[I...]) >> >> But then I have to define the getindex method for each concrete subtype of >> AbstractFoo. >> >> Thanks for any help. It's possible that these gymnastics are a sign that I >> just shouldn't parameterize on N and do any necessary checks at runtime, but >> it feels like I'm close on this one. >> >> >> -s >> > >
