I think you're probably being overly optimistic about how infrequently there will be dispatch ambiguities between unrelated functions that happen to have the same name. I would guess that if you try to merge two unrelated generic functions, ambiguities will exist more often than not. If you were to automatically merge generic functions from different modules, there are two sane ways you could handle ambiguities:
- warn about ambiguities when merging happens; - raise an error when ambiguous calls actually occur. Warning when the ambiguity is caused is how we currently deal with ambiguities in individual generic functions. This seems like a good idea, but it turns out to be extremely annoying. In practice, there are fairly legitimate cases where you can have ambiguous intersections between very generic definitions and you just don't care because the ambiguous case makes no sense. This is especially true when loosely related modules extend shared generic functions. As a result, #6190 <https://github.com/JuliaLang/julia/issues/6190> has gained a lot of support. If warning about ambiguities in a single generic function is annoying, warning about ambiguities when merging different generic functions that happen share a name would be a nightmare. Imagine popular packages A and B both export a function `foo`. Initially there are no ambiguities, so things are fine. Then B adds some methods to its `foo` that introduce ambiguities with A's `foo`. In isolation A and B are both fine – so neither package author sees any warnings or problems. But suddenly every package in the ecosystem that uses both A and B – which is a lot since they're both very popular – is spewing warnings upon loading. Who is responsible? Package A didn't even change anything. Package B just added some methods to its own function and has no issues in isolation. How would someone using both A and B avoid getting these warnings? They would have to stop writing `using A` or `using B` and instead explicitly import all the names they need from either A or B. To avoid inflicting this on their users, A and B would have to carefully coordinate to avoid any ambiguities between all of their generic functions. Except that it's not just A and B – it's all packages. At that point, why have namespaces with exports at all? What if we only raise an error when *making calls* to `foo` that are ambiguous between `A.foo` and `B.foo`? This eliminates the warning annoyance, which is nice. But it makes code that uses A and B that calls `foo` brittle in dangerous ways. Suppose, for example, you call `foo(x,y)` somewhere and initially this can only mean `A.foo` so things are fine. But then you upgrade B, which adds a method to `B.foo` that also matches the call to `foo(x,y)`. Now your code that used to work will fail *at run time* – and only when invoked with ambiguous arguments. This case may be possible but rare and not covered by your tests. It's a ticking time bomb introduced into your code just by upgrading dependencies. The way this issue has actually been resolved, if you were using A and B and call `foo`, initially only is exported by A, as soon as package B starts exporting `foo`, you'll get an error and be forced to explicitly disambiguate `foo`. This is a bit annoying, but after you've done that, your code will no longer be affected by any changes to `A.foo` or `B.foo` – it's safe and permanently unambiguous. This still isn't 100% bulletproof. When `B.foo` is initially introduced, your code that used `foo`, expecting to call `A.foo`, will break when `foo` is called – but you may not have tests to catch this, so it could happen at an inconvenient time. But introducing new exports is *far* less common than adding methods to existing exports and you are much more likely to have tests that use `foo` in *some* way than you are to have tests that exercise a specific ambiguous case. In particular, it would be fairly straightforward to check if the tests use every name that is referred to anywhere in some code – this would be a simple coverage measure. It is completely intractable, on the other hand, to determine whether your tests cover all possible ambiguities between functions with the same name in all your dependencies. Anyway, I hope that's somewhat convincing. I think that the way this has been resolved is a good balance between convenient usage and "programming in the large". On Fri, Apr 24, 2015 at 10:55 PM, Michael Francis <[email protected]> wrote: > the resolution of that issue seems odd - If I have two completely > unrelated libraries. Say DataFrames and one of my own. I export value( > ::MyType) I'm happily using it. Some time later I Pkg.update(), unbeknownst > to me the DataFrames dev team have added an export of value( ::DataFrame, > ...) suddenly all my code which imports both breaks and I have to go > through the entire stack qualifying the calls, as do other users of my > module? That doesn't seem right, there is no ambiguity I can see and the > multiple dispatch should continue to work correctly. > > Fundamentally I want the two value() functions to collapse and not have to > qualify them. If there is a dispatch ambiguity then game over, but if there > isn't I don't see any advantage (and lots of negatives) to preventing the > import. > > I'd argue the same is true with overloading methods in Base. Why would we > locally mask get if there is no dispatch ambiguity even if I don't > importall Base. > > Qualifying names seems like an anti pattern in a multiple dispatch world. > Except for those edge cases where there is an ambiguity of dispatch. > > Am I missing something? Perhaps I don't understand multiple dispatch well > enough?
