# Supertype in Julia

**URL:** <https://discourse.julialang.org/t/supertype-in-julia/88930>\
**Category:** New to Julia\
**Tags:** type\
**Created:** [October 18, 2022, 7:50pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930 "2022-10-18T19:50:22Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Fourier](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fourier/32/38176_2.png) [@Fourier](https://discourse.julialang.org/u/Fourier)\
**Post date:** [October 18, 2022, 7:50pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/1 "2022-10-18T19:50:22Z")

</div>

Imagine someone else has implemented something, say a type and a function:

```julia
struct Foo
    a::Int
end

function bar(x::Foo)
    return x.a
end

```

I would like to build on what he has implemented, I would like to use the function `bar` also for my new type. However I can not create a subtype of `Foo` because it is not abstract and I don’t know how to supertype `Foo` without editing his code.  
What do I do?

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [October 18, 2022, 8:03pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/2 "2022-10-18T20:03:53Z")

</div>

This is not possible. Your only options is to duplicate their code. For this reason, it’s a good idea to write highly generic code, and create abstract types for your custom types, so others can extend them.

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [October 18, 2022, 8:48pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/3 "2022-10-18T20:48:33Z")

</div>

More context to extend @jakobnissen’s answer:

> [@Why is it impossible to subtype a struct?](https://discourse.julialang.org/t/why-is-it-impossible-to-subtype-a-struct/19876/3):
>
> Multiple inheritance is a totally different story and could be allowed. I’ve written about why we don’t allow subtyping of concrete types before if someone wants to dig up one of my earlier posts about it. Edit: here’s a link to an old google groups conversation about it [https://groups.google.com/d/msg/julia-dev/eA4VkFAD-yQ/LNUP\_OT0zy0J](https://groups.google.com/d/msg/julia-dev/eA4VkFAD-yQ/LNUP_OT0zy0J) In particular, this paragraph from the end of my first post on the thread sums up my position fairly well still: While there are a number of practical reaso…

Nevertheless, depending on how you want to build on `Foo`, it might be possible to create other types that, without being subtypes of `Foo`, compose with it, e.g.:

```julia
struct AnotherType
   foo::Foo
   # and other things, maybe
end

bar(x::AnotherType) = bar(x.foo)

```

If there are other methods that you want to extend, you should repeat this for all of them, though, perhaps using metaprogramming to avoid repeating a lot of code.

[Conversion and promotion](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/) can also be used to facilitate using your new type in contexts were `Foo` is used.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [October 18, 2022, 9:36pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/4 "2022-10-18T21:36:25Z")

</div>

I think you could set this up with a bit of a hack even though it’s not formally part of the language itself.

First, note how `deepcopy` is implemented for all types, without even you having to define `deepcopy(x::Foo)`. How is this done? It recursively goes through all fields of types until it finds a type it actually knows how to copy: [julia/deepcopy.jl at 61ccb32b6501a311be84bb86c3a5ffbc993c3be0 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/blob/61ccb32b6501a311be84bb86c3a5ffbc993c3be0/base/deepcopy.jl#L53).

I think you could do the same thing here. You would define a generic version of `bar` that recursively walks through all fields of the input type until it finds a type of `Foo`, then it calls the `bar` function on that.

---

<div class="post-metadata">

**Author:** ![Christopher\_Fisher](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/christopher_fisher/32/26132_2.png) [@Christopher\_Fisher](https://discourse.julialang.org/u/Christopher_Fisher)\
**Post date:** [October 19, 2022, 10:29am UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/5 "2022-10-19T10:29:14Z")

</div>

I realize you want a solution that does not involve editing the original code base, but I think that is the best solution in the case. Adding an abstract type should not introduce a breaking change. Instead it will make the code more extensible.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 19, 2022, 11:23am UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/6 "2022-10-19T11:23:30Z")

</div>

My best advice is as follow : who is this someone else ? If you can go to them, propose that they change their definition of `bar` to

```julia
function bar(x)
    return x.a
end

```

So you can use it. If this someone else is an open source contributor or package manager on GitHub, they might do it gladly (or accept your PR if you do it for them). If this someone else is your boss that manages some code in your organisation, then make your case to them, they might listen too.

---

<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:** [October 19, 2022, 11:49am UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/7 "2022-10-19T11:49:43Z")

</div>

Absolutely, its unlikely a PR adding an abstract type will be rejected, because it’s rarely breaking and can only broaden the user base.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 19, 2022, 11:58am UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/8 "2022-10-19T11:58:11Z")

</div>

Or even without types at all, why bother with a restriction to an abstract type if you do not need it ?

---

<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:** [October 19, 2022, 12:02pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/9 "2022-10-19T12:02:09Z")

</div>

Well, often you want to add an abstract type layer because methods will be defined on a concrete type for e.g. `Base` functions or other functions not owned by the package with the type.

If you add an abstract layer (and move the methods to it), then everyone else can also benefit from your methods on external functions without using your exact concrete object.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 19, 2022, 12:08pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/10 "2022-10-19T12:08:55Z")

</div>

And then what is the issue ? Until someone calls the method, I think that no overhead comes from a definition without abstract type. I don’t see the problem, could you rephrase ?

---

<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:** [October 19, 2022, 12:20pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/11 "2022-10-19T12:20:02Z")

</div>

When you don’t define an abstract type and define all your methods on a concrete type, it is hard for other developers to extend the behavior of your object because they can’t use its methods, they have to wrap the object and forward methods to it. Which is fine, just clunky.

As an example, my package DimensionalData.jl defines a `DimArray <: AbstractDimArray`. Nearly all the methods are on `AbstractDimArray`, so other packages can use all the functionality on their own array types without a layer of indirection - by inheriting from `AbstractDimArray`. They can just drop some of the fields of a `DimArray` if they don’t need them, or add their own. Rasters.jl `Raster` does this, plus a few other packages people have written like [AstroImages.jl](https://github.com/JuliaAstro/AstroImages.jl).

This only needs a few method definitions to work. Most other designs need a lot more method definitions to get `DimArray` functionality. There are like 50 base methods you would have to forward, a lot of them pretty hard to understand like the broadcast machinery.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 19, 2022, 12:24pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/12 "2022-10-19T12:24:43Z")

</div>

> [@heliosdrm](#):
>
> ```julia
> struct AnotherType
> foo::Foo
> 
> ```

You could also just construct instances of `Foo` on the fly. This is cheap if `Foo` is an immutable `struct`. For example:

```julia
bar(x::AnotherType) = bar(Foo(x.somefield))

```

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 19, 2022, 1:06pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/13 "2022-10-19T13:06:45Z")

</div>

> [@Raf](#):
>
> When you don’t define an abstract type and define all your methods on a concrete type, it is hard for other developers to extend the behavior of your object because they can’t use its methods, they have to wrap the object and forward methods to it. Which is fine, just clunky.

I was more thinking about defining the functions **without any type restriction**. So they basically work on every object, without the need to define an abstract type. I get that defining methods on concrete type does not allow code reuse, but what do you have against defining methods without any type restriction ?

---

<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:** [October 19, 2022, 1:53pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/14 "2022-10-19T13:53:35Z")

</div>

Nothing against omitting types! its just that often you can’t do that in practice.

If Base or another package owns a function you implement methods of, you have to use type restriction because you also don’t own `Any` and would be committing type piracy.

Or if you have multiple types of your own that implement the same method differently, same problem, you have to use types in the signature to distinguish them.

---

<div class="post-metadata">

**Author:** ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)\
**Post date:** [October 19, 2022, 2:27pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/15 "2022-10-19T14:27:38Z")

</div>

One common (usability-related) issue I’ve seen from defining methods without any type restriction is bad and inscrutable error messages. When your method doesn’t enforce any type restrictions itself, any type errors are going to come some place deeper in the stack, that the user might not even be aware of. So the error messages appear to make no sense, and it takes quite some experience in Julia to start decoding these error messages and trace them back.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [October 19, 2022, 3:29pm UTC](https://discourse.julialang.org/t/supertype-in-julia/88930/16 "2022-10-19T15:29:34Z")

</div>

Personally, I much prefer duck typing as far as I can get away with it. It may take a little practice, but i find the deep `MethodError`s that result from duck typing much more instructive than one further up the stack in some higher-level function.

For example, with duck typing you may get an error `No method matching one(::Foo)` rather than hitting `No method matching super_complicated_function(::Int64,::String,::Foo,::Vector{Int64})` earlier in the call. The first error message indicates that if I can define `one(::Foo)` then there’s a good chance that `super_complicated_function` will just work – or I’ll hit the next missing method and can fix that too. It’s only if I can’t define the concept of `one(::Foo)` that I have to worry about functions further up the stack. If I hit the error at `super_complicated_function`, I now have to look at and understand the full function and try to write an alternative. If the author of `super_complicated_function` was engaging in recreational overtyping, I probably have to copy-paste the whole body with some trivial modification to make it support `::Foo`. Code duplication is a horror for maintainability.

A major strength of overloading and multiple dispatch is defining generic behaviors where possible and specific behaviors where necessary so that things “just work”.
