What is a safer way to expand other packages' function?

Hi friends,

I am try to expand the DataFrame function for my data struct, I defined it as:

using DataFrames

DataFrame(Q::mystrust) = begin
# do something 
end

it works well, but when I write above as a file and include it in another session,

using DataFrames
include("my_function.jl")

DataFrame now only have 1 methods, and other function provided by package DataFrames seems be replaced.

>DataFrame
DataFrame (generic function with 1 method)

are there any suggestion for avoid replace other packages function while I expand them?
Thanks for your time!!

You need the namespace: DataFrames.DataFrame(::MyStruct) = ...

2 Likes

Interesting. As a medium-term Julia user, I’m not sure I fully internalized this.

For some PackageA.jl with exported function f, my thought process would have been that using PackageA would bring f into the current namespace, then defining a new f(::MyType) would add a new method for f within the current namespace. It sounds like what you’re suggesting is that defining f(::MyType) instead overwrites the binding for f exported by PackageA with a new function possessing only a single method, essentially: f previously pointed to a methods table populated by PackageA.f but now points to a new methods table containing only to your local f. By comparison, defining it as PackageA.f(::MyType) clarifies that you’re intending to add a method to an existing table vs reassigning the local name.

Does that sound right?

Yes

Yes, and you can also use an explicit import to add methods to the function of other package.

It it wasn’t that way, we would be all the time doing type piracy without knowing it, as every function we define would have to take into account all names exported by every used package, including Base.

1 Like

You could also import the function you want to extend.

import DataFrames: DataFrame

DataFrame(Q::mystrust) = begin
# do something 
end
3 Likes

This is true but I don’t like it.

I for one prefer it. I get why it’s not good to extend exported names; if I remove a name from a module’s export statement, suddenly the remaining extension methods make a new function and the using statement won’t alert me to my slipup. However, I always found it strange that when a name is specified (so I can’t use that name for anything else), I need to qualify it in extension method names but nowhere else, not even the body. There’s the argument that it’s clearer when the global scope is split into separate modules, but exported names and other specified names aren’t qualified either, so I still have to start at the file with the includes and imports to be sure where names come from.

This makes a lot of sense in hindsight. I’ve made a habit of extending existing functions with their global names, e.g. Base.show(::MyType) = ... but I suppose I hadn’t fully processed the why. I think I’d assumed it was something to do with providing method access to other non-locally-scoped code, rather, it’s that show(::MyType) = ... would just hijack the whole of the (non-globally-referenced) show in the local scope.