Like I said, this is likely just a newbie mistake... however, if I have the module: module Foo export my_new_function, length import Base.my_new_function import Base.length type Bar ; x::Int ; end length(y::Bar) = 42 my_new_function(y::Bar) = "Thanks for all the fish!" end
It complains about not being able to import Base.my_new_function. However, if I don't have that import, then if somebody (like you or Jeff) adds their nifty new function into Base, I will get an error trying to do using Foo when I try to use the new version... Scott On Saturday, April 25, 2015 at 12:31:47 PM UTC-4, Stefan Karpinski wrote: > > Scott, I'm not really understanding your problem. Can you give an example? > > On Sat, Apr 25, 2015 at 11:53 AM, Scott Jones <[email protected] > <javascript:>> wrote: > >> A problem I'm running into is the following (maybe the best practice for >> this is documented, and I just to stupid to find it!): >> I have created a set of functions, which use my own type, so they should >> never be ambiguous. >> I would like to export them all, but I have to import any names that >> already exist... >> Then tomorrow, somebody adds that name to Base, and my code no longer >> works... >> I dislike having to explicitly import names to extend something, how am I >> supposed to know in advance all the other names that could be used? >> >> What am I doing wrong? >> >> On Saturday, April 25, 2015 at 11:20:14 AM UTC-4, Stefan Karpinski 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? >>> >>> >>> >
