Thanks Tim, > As you feared, using .types this way messes up inference. The better > approach > is > > SparseArray{K,V,N}(data::Associative{K,V}, dims::NTuple{N,Int}) = > SparseArray{V, N, typeof(data)}(data, dims) >
So the general thing happening here is: type A{B,C} c::C end function A{B,C}(c::C{B}) return A{B,C}(c) end I can't add the constraint that B and C must be "consistent" to the type definitions. However, the constructor can use that constraint in the type annotation on its arguments. In that case there is nothing to stop you from making an "inconsistent" instance of type A{B,C}, but anything that comes out of the outer constructor will be consistent. What is the PL name for this notion of consistency? > Your 1D constructor could just dispatch to this with SparseArray(data, > (dims,)) > > If you add @inline in front of the getindex/setindex! functions, you may be > able to eliminate the splatting penalty, and you won't need the 1D > specializations. > Why does @inline eliminate the splatting penalty specifically? Does inlining allow some later (LLVM?) pass to remove the operations to gather the indices into a tuple and the splat them back out again (replacing them with a no-op?)? In that case is it important that the other methods of getindex are also defined with @inline? This is interesting, I don't usually pay this much attention to the types I use. Thanks, James