[This is a continuation/update on a previous question, but with new problem... click
this link to see the original post.]
To briefly review, I have an abstract matrix class that is derived from Base.AbstractArray{Scalar{T},N}, where Scalar{T<:Number} is an object of my own design. The array is truly abstract: it is not a contiguous/dense array of Scalars. In fact, the storage format resembles a compressed sparse matrix, except that each column represents a Scalar. Because of this compressed storage format, the default implementations of cat/vcat/hcat are quite suboptimal, so I need to override them.
Now, this is not a problem, if I define methods that take only my arrays. Unfortunately, I need to be able to accept arbitrary mixtures of my arrays and standard numeric AbstractArrays. What I need is a way to override, say, vcat in such a way that my methods are called when at least one of the arguments is mine. With the help of Miles Lubin, I've been experimenting with invoke; for instance:
# vcat{T}(V::AbstractVector{T}...) (abstractarray.jl:541)
vcat{T}( X::Union(Base.AbstractVector{T},CVX.AbstractVector{T})... ) =
any(iscvx,X) ? cat_cvxa( 1, X ) :
invoke( vcat, (Base.AbstractVector{T}...), X... )
The any(iscvx,X) test returns true if at least one of the arguments is an object of mine, and false otherwise. In this way, the standard Base.AbstractVector version of the method can be called if none of my objects are present.
Astute readers already know the problem. In theory, Union(Base.AbstractVector{T},CVX.AbstractVector{T}) is actually just the same as Base.AbstractVector{T}, since my arrays are derived from the base abstract array. So there's an ambiguity here; a potential for a stack overflow, too.
The funny thing is: sometimes this works exactly the way I want it to! That is, if I feed vcat a mix of array types, this is the function that is called. But then, I've rearranged my code a bit more, and now it never calls this modified form of the function. What has never happened, at least not yet, is a infinite loop/stack overflow. But nor has there ever been a warning about the potential ambiguity.
What I'm really looking for, I suppose, is a way to override the previous definition of this method, but somehow be able to invoke the overridden version if my test demands it.
Honestly, I think part of the problem is that Base.AbstractArray is not taking its status as an abstract class seriously. Many of the implementations of vcat, hcat, cat, and other functions assume a storage format and proceed as if they know best how every possible subclass would want to handle heterogenous sets of arrays. Honestly, I think that most of the implementations in abstractarray.jl ought to be relegated to the Array class; let ever concrete class determine for itself how to efficiently navigate its storage when concatenating matrices. Alas, I think that attempting to do that would run into some of the very problems I'm facing here.
Any suggestions would be welcome! The one thing I am considering that I know would work is to remove Base.AbstractArray as as subclass of mine. Then the Union above would no longer be trivial, and there would be no ambiguities to deal with. Unfortunately, that would mean I'd have to reimplement a lot of the convenience functions that do work well in abstractarray.jl and elsewhere; including, for instance, showarray.
Thanks for listening
Michael