Best practices for "base" packages to define common function names?

I have a couple of packages that have functions with the same name, but operate on different structs. Users could definitely have both packages loaded at the same time.

I think the best way to prevent issues from conflicting names is to pull the functions into a common “base” package? Are there good examples of this? Any best practices when setting up the base package and starting to extend those versions in the dependent packages?

Extending Base functions for structs you own is not type piracy and there may be good cases for doing it (JuMP.jl does it for empty! for example). However, some people believe that if you do that only to avoid conflicting names, and your function is not an specialization of the same idea as the Base function (but to your struct instead) then you should keep it in your module (i.e, define a brand new function) and maybe do not export it by default. The name given for the pattern of extending a Base function with unrelated methods just to avoid name conflicts is called punning (because you are making a pun by conflating different meanings of a word together), and you probably will find older threads in Discourse talking about it.

2 Likes

Your current setup sounds like how it’s supposed to be: you have different types in each package, and each of them defines methods of some common function for that type.

The reason you might want a *Base package is of you want unrelated packages to be able to use the function, without knowing about any of the types (by pulling in a dependency for one of the more expensive packages).

Example:

#FruitBase.jl
module FruitBase
export Fruit, bite
abstract struct Fruit end
function bite(::Fruit) end
end

#Apples.jl
module Apples
using FruitBase
import FruitBase.bite
export Apple
__init__() = sleep(60) # this package is expensive to include
struct Apple <: Fruit end
bite(::Apple) = "cronch"
end

#Mooses.jl #meese?
module Mooses
using FruitBase # way cheaper than, for instance, Apples
export eat
eat(x::Fruit) = for _ in 1:10; bite(x);end
end