# Extending functionality of an Abstract Type in a new repo

**URL:** https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192
**Category:** General Usage
**Tags:** package, type
**Created:** [June 11, 2023, 5:01pm UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192 "2023-06-11T17:01:38Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)
#### Post date: [June 11, 2023, 5:01pm UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/1 "2023-06-11T17:01:39Z")

</div>

How can I define a new type in a new package that extends an abstract type in an old package such that functions in the old package work when passed objects of the new type?

I have a type [`AbstractBody`](https://github.com/weymouth/WaterLily.jl/blob/34fe5e3431681561dba6310f7d19761831c9d1ac/src/Body.jl#L13) in WaterLily and I have a routine `measure!` that should work for any subtype as long as they implement a few functions (`sdf` and `measure`). I define [`AutoBody<:AbstractBody`](https://github.com/weymouth/WaterLily.jl/blob/34fe5e3431681561dba6310f7d19761831c9d1ac/src/AutoBody.jl#L13) within the same package, then define `sdf` and `measure` for that type, and everything works fine.

But I want to define other special-purpose types like a [`ParametricBody<:WaterLily.AbstractBody`](https://github.com/weymouth/ParametricBodies.jl/blob/6dc024266256740126730a94de193ecd505dfa1f/src/ParametricBodies.jl#L8) in their own packages. I’ve defined the `sdf` and `measure` functions, but WaterLily still can’t use them. For example:

```julia
using WaterLily,ParametricBodies,StaticArrays
R = 6
surf(θ,t) = R*SA[cos(θ+t),sin(θ+t)]
locate(x::SVector{2},t) = atan(x[2],x[1])-t
body = ParametricBody(surf,locate)
sdf(body,SA[1.,1.],0.) # no problem, returns -4.58
Simulation((8,8),(1,0),R;body) # throws error

```

The `sdf` functions works fine in the REPL, but the `Simulation` doesn’t know how to deal with a `ParametricBody`!

```julia
MethodError: no method matching sdf(::ParametricBody{typeof(surf), typeof(locate), ParametricBodies.var"#12#13", Float64}, ::SVector{2, Float64}, ::Int64)
Closest candidates are: sdf(::AutoBody, ::Any, ::Any) 

```

It must be possible to extend Abstract types like this… What am I doing wrong?

---

<div class="post-metadata">

### Author: ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)
#### Post date: [June 11, 2023, 5:40pm UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/2 "2023-06-11T17:40:46Z")

</div>

I think it’s a problem in the method definition: you need to tell Julia that these functions were named in another package, using an explicit prefix.  
So in your new package ParametricBodies.jl, instead of defining

```julia
function sdf(pb::ParametricBody)

```

you should do

```julia
using WaterLily
function WaterLily.sdf(pb::ParametricBody)

```

or another version which I like less

```julia
import WaterLily: sdf
function sdf(pb::ParametricBody)

```

---

<div class="post-metadata">

### Author: ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)
#### Post date: [June 11, 2023, 9:16pm UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/3 "2023-06-11T21:16:46Z")

</div>

Thanks. That’s changed the error, but it’s still there. Now it seems like the new `measure` function can’t find the new `sdf`. Is there documentation or examples from other repos for this I can look at?

---

<div class="post-metadata">

### Author: ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)
#### Post date: [June 11, 2023, 9:21pm UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/4 "2023-06-11T21:21:43Z")

</div>

Did you do the same with `measure`?

---

<div class="post-metadata">

### Author: ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)
#### Post date: [June 12, 2023, 6:27am UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/5 "2023-06-12T06:27:56Z")

</div>

Yes, I did the same for both - but the compiler says `sdf` is undefined. Perhaps the problem is the way I defined the original `sdf`

```julia
"""
    d = sdf(body::AutoBody,x,t) = body.sdf(x,t)
"""
sdf(body::AutoBody,x,t) = body.sdf(x,t)

```

because when I check in the REPL, the function doesn’t appear.

```julia
> using WaterLily
help?> WaterLily.sdf
  No documentation found.

  Binding WaterLily.sdf does not exist.

```

Could the compiler be inlining the function, so I can’t extend it?

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [June 12, 2023, 6:47am UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/6 "2023-06-12T06:47:16Z")

</div>

Are your modules short enough, or could be made into a short enough MWE that replicates the issue, to post here? gdalle’s suggestions are good so it’s likely there’s some other issue that requires a proper look.

> [@weymouth](#):
>
> Could the compiler be inlining the function, so I can’t extend it?

Inlining is an optimization, those do not interfere with language features.

---

<div class="post-metadata">

### Author: ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)
#### Post date: [June 12, 2023, 7:53am UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/7 "2023-06-12T07:53:12Z")

</div>

WaterLily isn’t short enough for a MWE. However, it _does_ seem like the problem was that `sdf` wasn’t available for being redefined. I just started a new branch `fix_sdf` and made [two changes](https://github.com/weymouth/WaterLily.jl/commit/cc2802af09cee0eae4814d1076494a3dacb0bb21#diff-3951588403571cbac76d5188238d59e33542921791b9983ec055c587d0214b0eR39). I exported `sdf` and I changed the definition of `sdf` to:

```julia
function sdf(body::AutoBody,x,t) body.sdf(x,t) end

```

and now everything is running without throwing errors.

```julia
help?> sdf
search: sdf isdefined @isdefined ComposedFunction symdiff setdiff symdiff! setdiff! searchsortedfirst

  d = sdf(body::AutoBody,x,t) = body.sdf(x,t)

julia> sdf(body,SA[1.,1.],0.) # still working
-4.585786437626905
julia> Simulation((8,8),(1,0),R;body); # no error

```

So it seems like the inline-able version of `sdf` was problem. But maybe not for the reason I think…

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [June 12, 2023, 10:33am UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/8 "2023-06-12T10:33:22Z")

</div>

Not exporting `sdf` would explain it, your import statement wasn’t importing anything by name explicitly so it would only grab what’s in your export statement.

> [@weymouth](#):
>
> I changed the definition of `sdf` to:

That’s not a change at all, it’s alternate syntax for the same function you posted before. `f(x) = x` syntax is a _one-line_ assignment form, it has nothing to do with whether a function call is _inlined_ during compilation. The macros `@inline` and `@noinline` are used to suggest to the compiler whether a method or a call should be inlined or not, but the compiler can choose differently if it’s unfeasible e.g. a dynamically dispatched function call cannot be inlined.

---

<div class="post-metadata">

### Author: ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)
#### Post date: [June 12, 2023, 11:48am UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/9 "2023-06-12T11:48:51Z")

</div>

Got it. Thanks!

So, to summarize: You need to `export func` in the old module, then `import OldMod: func` and define the new version and `export func` in the new module. Correct?

---

<div class="post-metadata">

### Author: ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)
#### Post date: [June 12, 2023, 11:52am UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/10 "2023-06-12T11:52:48Z")

</div>

It’s clearer with `using` in my opinion, cause when you extend a function from the old module you need to prefix it with `OldModule`

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [June 12, 2023, 12:02pm UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/11 "2023-06-12T12:02:19Z")

</div>

`using` is the import statement that works with `export` statements, not `import`. You don’t need to export a function in a module order to extend the function in that module. Exports only specify what names `using` will make available, they do not do anything like passing methods.

---

<div class="post-metadata">

### Author: ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)
#### Post date: [June 12, 2023, 12:17pm UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/12 "2023-06-12T12:17:12Z")

</div>

So the **only** thing I need to do is `import OldMod: AbstractType, func` and then I can define the new type and `func` in the new module and it works.

Personally, the `import` version seems much more direct, since it doesn’t rely on things being exported before they can be extended. (Refer to confusion starting 18h ago.)

---

<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: [June 12, 2023, 12:48pm UTC](https://discourse.julialang.org/t/extending-functionality-of-an-abstract-type-in-a-new-repo/100192/13 "2023-06-12T12:48:44Z")

</div>

In fact, you do not even need to do `import OldMod: AbstractType, func`, you can just do `import OldMod`, the disadvantage is that you need to refer to `AbstractType` and `func` as `OldMod.AbstractType` and `OldMod.func` _in every reference to them in your code_.
