(#1255 <https://github.com/JuliaLang/julia/issues/1255> would be icing on
the cake here.)

On Sat, Apr 25, 2015 at 8:19 AM, Stefan Karpinski <[email protected]>
wrote:

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

Reply via email to