# Multiple inheritance carry-over members

**URL:** <https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355>\
**Category:** General Usage\
**Tags:** inheritance, arrays\
**Created:** [April 1, 2021, 11:00am UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355 "2021-04-01T11:00:16Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [April 1, 2021, 11:00am UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/1 "2021-04-01T11:00:16Z")

</div>

Inheritance vs. mulitple dispatch in julia is maybe one of the hard things to grasp. I am still struggling with it and therefore the question. Does julia have a concept of carrying over data members to derived classes? I have read about multiple dispatch being what replaces the need for multiple inheritance and I can see how this may be true for methods, but what about data? To demonstrate, here is an example using @tholy ’ s class `AxisArray`:

```julia
julia> V = AxisArray(rand(3); row='a':'c')
1-dimensional AxisArray{Float64,1,...} with axes:
    :row, 'a':1:'c'
And data, a 3-element Vector{Float64}:
 0.3122957215062174
 0.6611468595604877
 0.6639367902035573
julia> V = AxisArray(rand(3); row='a':'c')
1-dimensional AxisArray{Float64,1,...} with axes:
    :row, 'a':1:'c'
julia> V2 = V .+ 0
And data, a 3-element Vector{Float64}:
 0.3122957215062174
 0.6611468595604877
 0.6639367902035573

```

As it is seen, the addition of `0` already removes the nice axis properties from the array. Even more so, also views of the array burry its nice properties:

```julia
julia> V3 = reshape(V,(1,3))
1×3 reshape(::AxisArray{Float64, 1, Vector{Float64}, Tuple{Axis{:row, StepRange{Char, Int64}}}}, 1, 3) with eltype Float64:
 0.312296 0.661147 0.663937
julia> V3.axes
ERROR: type ReshapedArray has no field axes

```

One may now argue that it is in the responsibility of the package author to write multiple-dispatch methods such that for example such views are also supported. But this is a task which would not be necessary in ordinary inheritance schemes where the data members are essentially just copied and new data members can appended.  
The problem: Am I missing an important julia feature or way of usage in my toolbox, or is this a current limitation of julia or an unavoidable limitation?  
In my mind the usefulness of `AxisArrays` (and all programming which adds data to existing structures) is extremely limited if the user always have to keep track of the axis data. In this case a separate `axis` class is more useful (which may of course exist already), but it just seems wrong, since a set of axes should belong to the array and should be propagated along with what is done to the array.  
I guess the broadcasting mechanism can somehow be carried over to `AxisArrays` but what about the views? How about introducing a julia keyword `persist`, which tells a data member to conceptually automatically reside (or be accessible from) structure of the encapsulating structure?  
This way it would be fairly easy to deal with the views, as the axis would “blubble up” though a series of such encapsulations and still be visible. But then this needs some change to the type structure, as the resulting view type needs to still ideally be recognized a subtype of AxisArrays and not just AbstractArray, I guess.

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 1, 2021, 10:05pm UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/2 "2021-04-01T22:05:22Z")

</div>

> [@RainerHeintzmann](#):
>
> Does julia have a concept of carrying over data members to derived classes?

No. The design of Julia go against this on purpose. The common example is the `Square` class. If I create a `Rectangle` class, then makes sense to have `Square` as a subtype of rectangle, because this replicates the mathematical relationship between them, however, `Rectangle` has two attributes (`length` and `width`, for example) and for `Square` it would be better to inherit nothing and instead just use a single attribute to store the value (saving half the memory).

From your examples, however, I see nothing related to inheritance.

> [@RainerHeintzmann](#):
>
> As it is seen, the addition of `0` already removes the nice axis properties from the array.

The first examples is related to how broadcast was implemented for `AxisArray`. I do not know intimately the broadcast machinery, but I believe materialising `Vector` is the default (i.e., it works even if you do nothing about it), but you can adapt its behaviour, for example, trying to broadcast over `Dict` or `NamedTuple` errors (it would work automatically if it was not reserved by the core team), `(1, 2, 3) .+ 1` returns a `Tuple`. So here you should contact Tim Holy to know if this behavior of broadcast is intended or not.

> [@RainerHeintzmann](#):
>
> Even more so, also views of the array burry its nice properties:

A view of some array is not a subtype of the wrapped array. `ReshapedArray` is a subtype of `AbstractArray` as much as `AxisArray` is a subtype of `AbstractArray`, `ReshapedArray` is not under `AxisArray`, or any other `Array` type it can wrap. This is not common behavior on most languages that I know, because the relationship of a wrapper type is “contain a” not “is a”. I mean, Ruby and its infinite dynamism probably could delegate any method the wrapper does not know to the wrapped object, but it does not stop being a “contains a” relationship and not a “is a” relationship because of that.

> [@RainerHeintzmann](#):
>
> In my mind the usefulness of `AxisArrays` (and all programming which adds data to existing structures) is extremely limited if the user always have to keep track of the axis data.

While we are talking about broadcast, this is probably some behavior Tim just did not implement. Not a limitation of the language.

> [@RainerHeintzmann](#):
>
> I guess the broadcasting mechanism can somehow be carried over to `AxisArrays` but what about the views?

I do not believe generic `view`s can deal with what you are asking here, you can maybe create a specialized type of `view`, because the generic one is made to work with any `AbstractArray`. Luckily, you can create a `view` type that recognizes other methods that may be applied to your type, and overload some `Base` function to use your specific type of view when your specific type of array is passed.

> [@RainerHeintzmann](#):
>
> as the resulting view type needs to still ideally be recognized a subtype of AxisArrays and not just AbstractArray, I guess.

Yes, this kind of dynamic type creation may be possible, but probably indicates you are trying to use Julia as something it is not.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [April 1, 2021, 10:20pm UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/3 "2021-04-01T22:20:30Z")

</div>

> [@Henrique\_Becker](#):
>
> The common example is the `Square` class. If I create a `Rectangle` class, then makes sense to have `Square` as a subtype of rectangle, because this replicates the mathematical relationship between them, however, `Rectangle` has two attributes ( `length` and `width` , for example) and for `Square` it would be better to inherit nothing and instead just use a single attribute to store the value (saving half the memory).

Regardless of the internal layout of a `Square` object, it would be nice if I could count on `Square` instances having a `length` and `width` interface just like `Rectangle` does. Currently `square.length` errors at runtime and `length(square)` (which is equivalent but more verbose) does too.

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 1, 2021, 10:57pm UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/4 "2021-04-01T22:57:17Z")

</div>

You have two solutions there, the first one is that `length` and `width` should be methods implemented by any subtypes of `AbstractRectangle` (or the adequate type). The second is to overload `getproperty` to make `square.length` and `square.width` work even if the internal layout is just a single `side` attribute.

Any of the two ways will need explicit implementation, there is no way to make this work in an entirely generic way, because, as I pointed out, if the internal layout is different, as in the `Square` type case, then you will need to inform the compiler that both `length` and `width` must be obtained from `side`.

> [@jzr](#):
>
> Currently `square.length` errors at runtime and `length(square)` (which is equivalent but more verbose) does too.

I am not sure what you meant by “equivalent but more verbose”, `length(a)` and `a.length` are two completely distinct things, you can make them mean the same, but this is by no way default behaviour.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [April 2, 2021, 2:00am UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/5 "2021-04-02T02:00:38Z")

</div>

The problems with `AxisArray` seem to be orthogonal to inheritance? I mean at least both NamedDims.jl and DimensionalData.jl keep dimension names and behavior after `view` and broadcasting and similar operations - they have what you might call “dominant” wrapper types that try to rewrap during methods like these. But these are just implementation details - wrappers like `AxisArray` can behave pretty much any way you want by writing custom implementations of these base methods.

But… keeping names after `reshape` doesn’t seem like a good idea, the axes really aren’t the same things after that.

Lastly, I once wrote a package to add field inheritance via mixins (Mixers.jl) and I never use it now. Just use composition instead.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [April 2, 2021, 2:53pm UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/6 "2021-04-02T14:53:00Z")

</div>

> [@RainerHeintzmann](#):
>
> Inheritance vs. mulitple dispatch in julia is maybe one of the hard things to grasp.

Julia does not have inheritance.

> [@RainerHeintzmann](#):
>
> Does julia have a concept of carrying over data members to derived classes?

There are no “derived classes” in Julia. The pattern you may be looking for in general is _composition_.

That said, the particular problem you highlight with `AxisArray` may be solved by hooking into the [broadcast interface](https://docs.julialang.org/en/v1.7-dev/manual/interfaces/#man-interfaces-broadcasting) and propagating the extra information. Maybe open an issue for that package, or make a PR.

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [April 2, 2021, 4:33pm UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/7 "2021-04-02T16:33:30Z")

</div>

Thanks for the explanation and for pointing me towards `DimensionalData.jl`. Indeed, it supports the broadcasting scheme, which works well. Yet, my main point was a mechanism that works (be “dominant”) with encapsulating views. I tried `DimensionalData.jl` and it failed to do its job in combination with for example a `PaddedView`. I suspect that this is a fundamental problem. I do understand that PaddedView can add some code to accommodate `DimensionalData` and possibly also the other way round, but the combinatorial effects of everybody having to accommodate everybody else’s additional data are just too large to make sense. Can you maybe explain a bit more about “composition”? Can this mechanism achieve this? Or can broadcast somehow penetrate also the “view” via parent()? If all of this is not possible, there might be at least some generic implementation such as the AbstractArray supporting a dictionary for “additional stuff” to be carried along (and then another encapsulation can retrieve this information), or a best practise such that the looked for information can be found by traversing the parent() tree? But this will probably create a mess in assuring types.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [April 2, 2021, 11:02pm UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/8 "2021-04-02T23:02:47Z")

</div>

> and it failed to do its job

I think you misunderstand the scope of what you want here. It’s job doesn’t really extend into the constructors of ecosystem packages that I don’t know about, I can’t see how this would “just work” in any language. How do we influence the `PaddedView` constructor? and what should happen if you try to wrap it with a NamedDims.jl wrapper? which should “win”?

But it _is_ possible to solve this with very little boilerplate code, and as usual in Julia, it would need some (a lot of) coordination and a shared interface (as you suggest with AbstractArray, but probably actually with traits and shared methods in an interface package like ArrayInterface.jl).

The simple case would be that `PaddedView` has a method that dispatches on `DimArray` and rewraps. But to generalise to AxisArrays,jl and NamdDims.jl and any other wrapper type, we could have a method in ArrayInterface.jl - `rewrap(f, A)`. `PaddedView` and other array packages could call `rewrap` in their constructor. The default `rewrap` would just call `f` and return it. But DimensionalData.jl could add a method to unwrap the internal array, run the constructor `f`, and wrap it with a `DimArray` again.

Someone would have to write this, and packages would have to implement it. Probably a lot wouldn’t, but as ArrayInterface.jl is more widely accepted, things like this may start to work?

Broadcast can handle this a little better - it’s possible to make DD always “win” as the outer wrapper. I’m not sure how well it goes currently with other packages. Probably `NamedDims.jl` wrappers would beat it as @oxinabox understands broadcast better than I do.

Composition is what we are doing by wrapping objects that already have behaviors, instead of inheriting behaviours from a supertype, as we are with `AbstractArray`. But I meant that comment in relation you question about field inheritance, which is actually unrelated to this problem. Regular inheritance doesn’t apply in this context because `PaddedView` does not inherit from or know about `AbstractDimArray`, it inherits from `AbstractArray` - so composition is all we can do.

This is a problem of agreeing on ecosystem wide shared interfaces, and working out what they need to do and agreeing to implement them. Maybe some of them will make it into Base one day. That’s what ArrayInterface.jl is for, but these things are a long way off.

Personally, I just use `DimensionalData.rebuild` for this kind of thing:

```julia
rebuild(some_dimarray, PaddedView(parent(some_dimarray), args...))

```

Which of course will break the index if `PaddedView` changes the array size, another complication to this issue. Doing that generically would need `rewrap(f, A, I...)`

See: [interface for rewrapping Array wrappers · Issue #136 · JuliaArrays/ArrayInterface.jl · GitHub](https://github.com/JuliaArrays/ArrayInterface.jl/issues/136)

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [April 3, 2021, 9:53pm UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/9 "2021-04-03T21:53:16Z")

</div>

> [@RainerHeintzmann](#):
>
> As it is seen, the addition of `0` already removes the nice axis properties from the array. Even more so, also views of the array burry its nice properties:

AxisArrays.jl is a bad example.  
It was never fully updated with the broadcasting changes in Julia 0.6 or 1.0.  
I recommend: AxisKeys.jl, AxisIndicies.jl or DimensionalData.jl as modern replacements.  
We’re planning a BoF at JuliaCon this year to workout a full plan to officially deprecate AxisArrays.jl

> [@Raf](#):
>
> Broadcast can handle this a little better - it’s possible to make DD always “win” as the outer wrapper. I’m not sure how well it goes currently with other packages. Probably `NamedDims.jl` wrappers would beat it as @oxinabox understands broadcast better than I do.

I should write a blog post.  
There is basically one correct way to implement 70% of the broadcasting stuff if you are a wrapper array.  
I suggest copy pasting the code from NamedDims.jl and tweaking that.

> <https://github.com/invenia/NamedDims.jl/blob/master/src/broadcasting.jl>

(Which itself is copied+cleaned from DistributedArrays.jl)

The fact that one does have to do this does seem like our polymorphism isn’t powerful enough.  
Though perhaps we are just missing a bit of our abstraction.  
E.g. a macro could generate that stuff and they wouldn’t require a fundamental change to the language to increase power…  
And more power is not nesc good.  
We have a lot of expressive power as is.  
Some features that increase it would open up to known problems.  
E.g. there is a writeup somewhere that explains why inheriting fields leads to problems. I think it might be the Fragile Base Class problem.  
Another example is being able to define what happens on method error. Lua let’s you do that. But that would result in having to add a bunch of backedges (i.e compilation cache invalidation hooks) to methods that would force recompilation far more often (in particular those hooks were once that were removed in 1.6 because not needed and are part of why Julia 1.6 has much faster package loading).

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [April 4, 2021, 2:12am UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/10 "2021-04-04T02:12:52Z")

</div>

> [@oxinabox](#):
>
> I suggest copy pasting the code from NamedDims.jl and tweaking that.

That was my strategy (youre even thanked in the source), but I think you made some changes since then.

Doing broadcast properly does seem a dark art unfortunately, and since your code works I haven’t justified the time to learn it.

---

<div class="post-metadata">

**Author:** ![haberdashPI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/haberdashpi/32/26337_2.png) [@haberdashPI](https://discourse.julialang.org/u/haberdashPI)\
**Post date:** [April 5, 2021, 1:34pm UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/11 "2021-04-05T13:34:46Z")

</div>

> [@Raf](#):
>
> But it _is_ possible to solve this with very little boilerplate code, and as usual in Julia, it would need some (a lot of) coordination and a shared interface (as you suggest with AbstractArray, but probably actually with traits and shared methods in an interface package like ArrayInterface.jl).

I think this particular problem has been addressed by [Adapt](https://github.com/JuliaGPU/Adapt.jl), that seems like a good general solution that various array libraries could (should?) support.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [April 5, 2021, 1:56pm UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/12 "2021-04-05T13:56:47Z")

</div>

That would work for arrays that need to propagate to the bottom, like `CuArray`.

The `CuArray` constructor could call `adapt(CuArray, A)` instead of `CuArray(A)`, which would work already with `DimArray` already as it supports Adapt.jl:

```julia
julia> adapt(CuArray, DimArray(view(rand(10, 10), 1:5, 1:5), (X, Y)))
DimArray (named ) with dimensions:
 X (NoIndex)
 Y (NoIndex)
and data: 5×5 view(::CuArray{Float64, 2}, 1:5, 1:5) with eltype Float64
 0.774018 0.428549 0.811505 0.676999 0.474822
 0.5862 0.944905 0.0430036 0.750278 0.819485
 0.698396 0.982062 0.646442 0.0306205 0.870356
 0.259098 0.0646769 0.526254 0.850805 0.489501
 0.309116 0.679976 0.346363 0.400562 0.243139

```

But it wont cover a lot of other cases.

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [April 6, 2021, 6:02am UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/13 "2021-04-06T06:02:54Z")

</div>

> [@Raf](#):
>
> I think you misunderstand the scope of what you want here. It’s job doesn’t really extend into the constructors of ecosystem packages that I don’t know about, I can’t see how this would “just work” in any language. How do we influence the `PaddedView` constructor? and what should happen if you try to wrap it with a NamedDims.jl wrapper? which should “win”?

In OOP even ordinary inheritance (with data members) is essentially based on extending structures by additional data and additional methods. In Julia this only concerns methods and data needs to be wrapped by subtyping from AbstractArray and making one data member a final array.

In Python you can make your own array class as a child of the numpy array class (np.ndarray). I have done this and let my class have a different standard display method (like Image in Julia) and also dimension functionality (like DimensionalData). When the base class (np.ndarray) does “its job” it simply does not care and does not need to know that the structure is really longer. It also relies on some standard mechanisms to not loose those extra members. Numpy already has a mechanism in place that can “rewrap” its result back into you derived type. All you need to do is to overwrite this wrapup function and it pretty much works out of the box. The main point I am making here is that np.ndarray is **agnostic** about what other classes may be derived from it and it can still “do its job” (i.e. calculations on arrays) and even return the derived type, if wanted. Some sort of finalize function is called provides you with the necessary information to for example carry over the dimension information (e.g. via “similar” construction). Wrt “who should win” in OOP an object can be both, an instance of its own class as well as being an instance of all parent classes (including their data structure).  
I do understand and appreciate that Julia on purpose does not support this, but then it would be nice to have an easy-to-use generally accepted rewrapping mechanism in place. Maybe “Adapt” does this, but I did not yet have a look at it.

I think from a user perspective there are two possible ways:

1. The ecosystem has a generally agreed way of rewrapping
2. The user has an easy way to define which package should be working with which other package(s).

I do think that this is really a practical problem in Julia as currently this problem of combining features appears to be common. E.g. try to calculate with the Image class. Even if you deprecate AxisArrays.jl, many other subtypes of AbstractArray quickly lose their nice properties when it comes to working with views which limits their practical use. It may well be easier to keep track of dimension information separated from the arrays than to deal with the various propagation problems.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [April 6, 2021, 7:21am UTC](https://discourse.julialang.org/t/multiple-inheritance-carry-over-members/58355/14 "2021-04-06T07:21:31Z")

</div>

But you are extending the type yourself! The key point of misunderstanding here is that `PaddedViews.jl` does not extend `AbstractDimArray` or DimensionalData.jl at all.

If it did, that would also just work. Thats what a `GeoArray` does.

`AbstractDimArray` is entirely agnostic about what classes are derived from it. It was intentionally written as a generalised abstraction, where `AxisArray` isn’t (one of the reasons I wrote a new package). Of course, they need to define the fields again, or define diferent fields with new methods that point to them (it’s a method based interface, fields are never accessed directly). But that’s a minor problem compared to what you are talking about.

You are asking for completely separate objects to be rewrapped, which is an orthogonal problem to inheritance - it’s about having a widely implemented shared interface.

So, just so we’re clear: `PaddedView` is not an instance of `AbstractDimArray`. There is no inheritance involved here.
