How to wrap a concrete type in a user-defined type?

Julia does not allow inherit concrete types. So how should I implement my type using existing concrete type? For example, I want to implement MyArray with AxisArrays. AxisArray, they share the same methods, the only difference is that MyArray has some constraints on its constructor, so it is easier for the users to write their code.

For example, I can wrap AxisArray in MyArray,

using AxisArrays

struct MyArray
       a::AxisArray
       function MyArray(A)
           size(A) > (3, 4) && error()
           new(A)
       end
end

and forward every method of AxisArray to MyArray (using @forward in MacroTools.jl). This is the composition way.

On the other hand, I could just make an alias to AxisArray:

function MyArray(a...)
       size(a[1]) > (3, 4) && error()
       AxisArray(a...)
end

julia> MyArray(rand(2,3), (Axis{:a}([1,2]), Axis{:b}([1,2,3])))
2×3 AxisArray{Float64,2,Array{Float64,2},Tuple{Axis{:a,Array{Int64,1}},Axis{:b,Array{Int64,1}}}}:
 0.233249  0.549376  0.399034
 0.208456  0.2461    0.240907

But want it returns is an AxisArray. How to change it to be shown as MyArray also? Just modify AxisArray’s show method?

Which way is recommended in the above 2?

Modifying show is ultimately unhelpful as you will want to dispatch using your type’s typename (sooner or later).

@forward whatever you should and that way you are open to future

2 Likes

I think option 2 is good, but why do you want it to display as MyArray? Will you dispatch on this type? If not, I would just call the method that does the size checking something like create_array or verify_array and not pretend that it was its own type.

If you need your own type, then you can either forward the methods, or alternatively, just refer to the field myarray.a directly.

It depends on what your goal is. If you want to dispatch on the specialized type, then you need to make it a separate type, if all you want is to check a parameter on construction, then your second option might be better.

This looks like type piracy, although harmless.

You can forward all the calls from MyArray to AxisArrays with ReusePatterns, and define your own show method as follows:

julia> using ReusePatterns, AxisArrays

julia> struct MyArray
              a::AxisArray
              function MyArray(A)
                  size(A) > (3, 4) && error()
                  new(A)
              end
       end

julia> @forward (MyArray, :a) AxisArray

julia> Base.show(a::MyArray) = "This is MyArray!"