# Composition and inheritance: the Julian way

**URL:** <https://discourse.julialang.org/t/composition-and-inheritance-the-julian-way/11231>\
**Category:** General Usage\
**Tags:** inheritance, structtypes\
**Created:** [May 29, 2018, 1:06pm UTC](https://discourse.julialang.org/t/composition-and-inheritance-the-julian-way/11231 "2018-05-29T13:06:00Z")\
**Posts on this page:** 1\
**Showing post:** 25

<div class="post-metadata">

**Author:** ![gcalderone](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gcalderone/32/1539_2.png) [@gcalderone](https://discourse.julialang.org/u/gcalderone)\
**Post date:** [May 31, 2018, 2:04pm UTC](https://discourse.julialang.org/t/composition-and-inheritance-the-julian-way/11231/25 "2018-05-31T14:04:17Z")

</div>

Sorry for the absence… I will comment on individual posts below:

> [@Tamas\_Papp](#):
>
> If this is still about `Lazy.@forward` , I suggest you look at the macro and its documentation before further discussion. It is precisely for the composition example we are talking about.

Sorry but I don’t understand why it should be related to be composition example. The `Lazy.@forward` **requires** encapsulation (i.e. approach 1 and 2 in the first post), not composition (approach 3). You will forgive me if _encapsulation_ and _composition_ are not the right words (again, I’m not a CS…), I use them just to refer to the approach discussed in the first post.

> [@DNF](#):
>
> It just seems like the “composition over inheritance” argument would be easier to make if there were a way to efficiently cut all the boilerplate.

Completely agreed. Besides, the boilerplate code may add lots of entries in the dispatch table, without actually adding any _new_ functionality. Moreover, all the boilerplate code, even if automatically generated, must be compiled resulting in further waste of time.

Thank you @Raf for pointing out Mixers.jl, it quickly allows to add further fields to structures without listing again the previous ones. This goes exactly in the direction of aproach 3 in the first post.

> [@Tamas\_Papp](#):
>
> 1. consider simplifying the interface (too many verbs),

You can’t. If you want to add a _twist_ to (e.g.) `Vector`, you simply can’t because you didn’t wrote the interface.

Thank @marius311 for providing a list of rules. Following your example I will provide my proposal, which is actually very similar to yours (except for the `AbstractCitizen` type):

1. define an abstract type as supertype for each struct, e.g. define, `Person <: AbstractPerson`, `Citizen <: AbstractCitizen`, etc. In OOP terminology, the structures will be the data members of a **class** , and the abstract types will be the **interfaces** ;
2. define the hierarchy among structures using abstract types (not concrete types), e.g. `AbstractPerson <: AbstractCitizen`. This will allow us to define hierarchy in the same way as we do it in OOP;
3. define sub structures by repeating the fields of the fields of the parent structure, in the same order and with the same types. This step can be automatized with Mixers.jl by @Raf;
4. all methods working on a structure must accept the corresponding abstract type, not the concrete one. In OOP terminology these are the **methods** associated to a class;
5. the only exception to the rule 4 above are the constructors, and those methods returning a specific structure (either `Person` or `Citizen` in the example above). These methods must accept concrete types, not abstract ones;
6. define a _super_ method like `super(p::Citizen) = Person(p.name, p.age)` (the name is not mandatory…) to be used in all methods of the derived structures to access the corresponding method acting on the parent structure.

I would like to emphasize that the goal here is not to reproduce an OOP practice in Julia, I know it is not possible and will likely lead to troubles. Here we only want to **simply and efficiently** extend/customize/specialize (use the word you prefer…) the behaviour of a Julia object whose methods have been written by someone else.

In my opinion this simple list of rules allows to easily extend the functionality of any object, and use it (quoting @DNF) **exactly like the concrete object, with a twist**. Moreover, even if the object is not supposed to be extended it will not harm its development or performances, and I can’t think of any practical reason to avoid following them. Any counter example here is more than welcome.

> [@DNF](#):
>
> But it’s difficult to apply when the object you want to wrap is pre-existing

Well, if we agree that the above rules are to be followed, the only feasible way is to ask the object developer to adapt its implementation according to the rules… 😉

Two final comments:

- the very fact that we are discussing what is the best way to _wrap_ an object into another to slightly customize its behavour, without adding lot of boilerplate code (either written or generated with macros), implies there is not yet a standardized and commonly accepted way to do it. Or, at least, I am not aware of it (again, any advice here is very welcome);

- many of us, certainly myself, are struggling to understand whether we can use Julia as the main tool for our daily work. Hence, we **need** to know whether Julia has some intrinsic limitation. The impossibility to customize the behaviour of an object is (in my opinion) a strong restriction.

---

_[View the full topic](https://discourse.julialang.org/t/composition-and-inheritance-the-julian-way/11231)._
