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.
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.
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.