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
>>  
>  
> 

Reply via email to