I have a simple question: If I export a function like
weights(m::MyType) = m.weights from my package, why do I get things like
WARNING: both MyPackage and StatsBase export "weights"; uses of it in module Main must be qualified
MyType is not a subtype nor supertype of anything that the
weights function in
StatsBase uses (like
AbstractArray). So I don’t see why I need to qualify the usage. This is basically what multiple dispatch should take care of right?
I know there was a thread not too long ago (I can’t find it) that dealt with a similar issue, but I believe in that case there was some commonality in what was supplied so that there actually could have been ambiguities in which version was called.
You can see if you can pun the
weights function by defining it on the
::MyType and then shove it into the
StatsBase.weights instead of your own. If there is no overlap between the tree of types of
MyType, and the things that
StatsBase.weights dispatches on, it is innocuous in my opinion. But people will disagree.
More broadly: a solution to this for better usability might be method merging with
using so that you don’t need to coordiante on a single function to add methods. But that doesn’t exist now, and there are reasonable arguments against that approach.
Relative to other languages: There is no ability for what C++/etc. would call argument dependent lookup (ADL) to take the argument and figure out that it should use
MyPackage.weights rather than
StatsBase.weights. While C++ can handle it with statically dispatching in overloaded functions (i.e. it doesn’t implement multimethods) it would be a much more complicated thing to implement with dynamic multiple dispatch.
But this requires me to depend on StatsBase.jl correct? You mean I should just extend
StatsBase.weights in my package. I get that is a way around it. I’m just wondering why Julia sees this as an issue at all given that there is no ambiguity whatsoever. Is it that Julia can’t do this type of multiple dispatch across packages or something?
Yes, you would need to take on that as a dependency…if it doesn’t fit well with the package, or you think it is too heavy, then it isn’t a good idea. Your best bet is to rename your function and just move on.
The reasons for this behavior are complicated and either obvious or perplexing - depending on what previous languages you come from. Function name conflict: ADL / function merging? gives plenty of background on different worldviews here. This is a nontrivial language design question.
Single dispatch doesn’t have this issue since there is no chance for conflicting concepts. That is
myobj.weights() knows to look in the namespace associated with the type of myobj. C++ does it with overloaded functions and different types, but the rules are crazy and it doesn’t work with dynamic dispatching. Lisp people find the Julia behavior obvious.
But what you are describing is not type piracy (if it is only your type) but rather “punning”. Julia does not have a convenient way to have multiple non-overlwpping concepts active at the same time. While having overlapping concepts for the same function name is obviously a terrible idea, it is more innocuous if there is no overlap in the types involved. You need to coordinate on extending the same function manually, and being careful not to actually engage in any type piracy.
…or just rename your function and move on. Which is what most people do. Those who create packages first get the pick of the litter in nice function names.
Thanks for the detailed response! That linked thread describes it perfectly.
I don’t think StatsBase.jl is necessarily too heavy but moving from 0 dependencies to any feels like too large of an increase I guess I will cave and change the name
BTW, I also wrote a blog post about this very topic recently.