# Best practice for user-customizable methods

**URL:** <https://discourse.julialang.org/t/best-practice-for-user-customizable-methods/75552>\
**Category:** General Usage\
**Tags:** question, type-piracy\
**Created:** [January 31, 2022, 10:49pm UTC](https://discourse.julialang.org/t/best-practice-for-user-customizable-methods/75552 "2022-01-31T22:49:58Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [January 31, 2022, 10:49pm UTC](https://discourse.julialang.org/t/best-practice-for-user-customizable-methods/75552/1 "2022-01-31T22:49:58Z")

</div>

Suppose there is a function in some package for which I want to implement a custom method in my own package `MyPackage`. However, I also want _users_ of `MyPackage` to customize/overwrite that method further if they want. I’m wondering what is the best practice for allowing this.

As a specific example, let’s take [DrWatson](https://juliadynamics.github.io/DrWatson.jl/v2.7/)’s [`default_prefix`](https://juliadynamics.github.io/DrWatson.jl/dev/name/#DrWatson.default_prefix) function. As discussed in the documentation of that function, let’s say I want to customize it for a `MyType` in `MyPackage`.

### Option 1

One possibility is to define the following in `MyPackage`:

```julia-auto
import DrWatson
default_prefix_mytype(c) = "lala" # no type annotation!
DrWatson.default_prefix(c::MyType) = default_prefix_mytype(c)

```

I can then tell users of my package that if they want to overwrite the `default_prefix` for `MyType`, they should define their own

```julia-auto
import MyPackage
MyPackage.default_prefix_mytype(c::MyPackage.MyType) = "user_lala"

```

Since that’s more specific than the `default_prefix_mytype` without any type annotation, it will essentially overwrite the method in `MyPackage`.

### Option 2

The other possible solution would be to directly set

```julia-auto
import DrWatson
DrWatson.default_prefix(c::MyType) = "lala"

```

in `MyPackage` and to tell my users that if they don’t like that, they should just define their own

```julia-auto
import DrWatson
using MyPackage: MyType
DrWatson.default_prefix(c::MyType) = "user_lala"

```

This would exactly overwrite the existing method.

The first method seems cleaner, but more convoluted to communicate in the documentation. The second method is easier to communicate, but it raises the question of how exactly Julia handles overwriting methods. Which method definition wins? I assume the last `using` wins, right? If a user does `using MyPackage` in their script, then overwrites the method, and then calls `using MyPackage` again (directly or indirectly), the second `using` is ignored, right? (Or does it revert the method definition?).

What is the recommended best practice in a situation like that? Is there some more elegant third option?

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [January 31, 2022, 11:14pm UTC](https://discourse.julialang.org/t/best-practice-for-user-customizable-methods/75552/2 "2022-01-31T23:14:41Z")

</div>

Both of these are [type piracy](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-type-piracy) which is recommended against because it makes the behavior of code harder to understand. In both cases, the behavior of `default_prefix(::MyType)` _changes_ based on whether the user’s code was loaded, even though neither `default_prefix` nor `MyType` comes from the user code.

Given that they both have the same type piracy issue, I can’t see any reason to pick Option 1–it has the same drawbacks just with a whole extra layer of complexity that you have to explain to your users.

> The second method is easier to communicate, but it raises the question of how exactly Julia handles overwriting methods. Which method definition wins? I assume the last `using` wins, right?

Actually both options raise this question, since a user might have two pieces of code (perhaps from yet another package which uses `MyPackage`) that both try to overwrite `default_prefix_mytype`. And yes, the last method definition wins, which is why both designs are inherently fragile.

So if this is really the behavior you want, where a user is encouraged to _change_ the behavior of `MyPackage` (not adding new behaviors for new types, but changing the behavior of existing types), then Option 2 is better than Option 1. But it’s worth considering whether this is actually what you want, since this is essentially a way of mutating global state, which is an endless source of confusion.

Is there another way to express the kind of thing you actually want to achieve?

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [February 1, 2022, 3:31am UTC](https://discourse.julialang.org/t/best-practice-for-user-customizable-methods/75552/3 "2022-02-01T03:31:07Z")

</div>

What I have in mind is not a package author building on top of `MyPackage`, but an “end-user”. In that context, I feel like type piracy may be a bit more appropriate.

What I actually want to achieve is in fact specifically customizing (and letting the “user” customize) how the [`DrWatson`](https://juliadynamics.github.io/DrWatson.jl/v2.7/save/) package chooses filenames: In my own package `QuantumControl` (or `QuantumControlBase`) – which is the real `MyPackage` – I have an [`OptimizationConfig`](https://github.com/JuliaQuantumControl/QuantumControlBase.jl/blob/89701e9c3a1303fc29d51d136ce47e6e5ba4f761/src/saving.jl#L8-L12) struct. This struct encodes an optimization problem, and the result of that optimization is written to a file by `DrWatson`’s [writing tools](https://juliadynamics.github.io/DrWatson.jl/v2.7/save/) like [`@produce_or_load`](https://juliadynamics.github.io/DrWatson.jl/v2.7/save/#DrWatson.@produce_or_load), where the automatic filename is determined by the methods `DrWatson.default_prefix(c::OptimizationConfig)`, `DrWatson.allaccess(c::OptimizationConfig)`, `DrWatson.allignore(c::OptimizationConfig)`, `DrWatson.access(c::OptimizationConfig, key)` and `DrWatson.default_allowed(c::OptimizationConfig)`.

Within `QuantumControlBase`, I try to provide these methods to result in reasonable default filenames. [Right now](https://github.com/JuliaQuantumControl/QuantumControlBase.jl/blob/302d701ed8ebf1ef5480b676d778ecb57e3112fa/src/saving.jl), these are done with “Option 1”.

The “user” is someone using the `QuantumControl` package in a `DrWatson`-based project, that is, basically a collection of scripts doing various optimizations, and storing the result to disk. I think it would be at least somewhat common for that user to want to customize the automatic filenames for the stored results, for that particular project. I don’t see any reasonable way for them to do that without _some_ type piracy.

It seemed like the more “blatant” piracy of “Option 2” was maybe going to behave a bit more unpredictably. The potentially tricky situation would be a script file in the project that starts like this:

```julia
using DrWatson
using ProjectSrc # uses QuantumControl/QuantumControlBase, overwrite methods
using QuantumControl # uses QuantumControlBase

```

The `ProjectSrc` here is their project specific code (the `src` folder of the `DrWatson` project), which includes custom methods overriding the originals in `QuantumControlBase`. Now, would the third line reset the overwritten method from line 2? With “Option 1”, definitely not, but with “Option 2” I’m actually not sure what happens.

Maybe I’m just worrying too much, and in practice users will manage just fine with “Option 2” (If lines 2 and 3 in the above example are switched and `using ProjectSrc` is last, there is never a problem). I’m definitely _not_ worried about a bunch of third-party packages implementing conflicting methods for ` OptimizationConfig`, which is a situation where type piracy would completely blow up.

---

<div class="post-metadata">

**Author:** ![gustaphe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gustaphe/32/18174_2.png) [@gustaphe](https://discourse.julialang.org/u/gustaphe)\
**Post date:** [February 1, 2022, 5:27am UTC](https://discourse.julialang.org/t/best-practice-for-user-customizable-methods/75552/4 "2022-02-01T05:27:52Z")

</div>

Do you need the user to have complete control of the function? One way that packages like `Plots` and `Latexify` deal with customization is to have a global (_gasp_) `Dict` of defaults, which you edit with a user-facing setter.

For your usecase, that could be

```julia
export set_mytype_prefix
global mytype_prefix = Ref{String}("lala")
function set_mytype_prefix(new)
    mytype_prefix[] = new
end
Watson.default_prefix(c::MyType) = mytype_prefix[]

```
