My point is, if I have been careful, and export methods that always 
reference at least one of type defined locally in my module, so that they
should always be unambiguous, I should NOT have to know about any other 
module (or Base) that a user of my module might also be using having a 
function with the
same name, and should NOT have to do an import.

For methods where I *am* trying to extend some type defined in another 
module/package or base, then yes, I believe you should do something 
explicitly to indicate that.

I don't think there is any real conflict here... right now it is too 
restrictive when the module's programmer has clearly signaled their intent 
by always using their own, unambiguous
signitures for their functions.

Have I got something fundamentally wrong here?

Thanks,
Scott
 
On Saturday, April 25, 2015 at 2:10:25 PM UTC-4, Jeff Bezanson wrote:
>
> Scott, the behavior you're trying to get sounds to me like "IF this 
> function exists in Base then I want to extend it, otherwise just make 
> my own version of the function". That strikes me as a hack. What we've 
> tended to do is let everybody define whatever they want. Then if we 
> see the same name appearing in multiple packages, we decide if there 
> is indeed a common interface, and if so move the packages to using it, 
> e.g. by creating something like StatsBase or maybe adding something to 
> Base. But we don't want Base to grow much more, if at all. 
>
> Getting an error for using both Base and your package seems annoying, 
> but alternatives that involve doing "something" silently surely must 
> be considered worse. If a colliding name gets added to Base, the 
> default behavior should not be to assume that you meant to interfere 
> with its behavior. 
>
> On Sat, Apr 25, 2015 at 1:57 PM, Jeff Bezanson <[email protected] 
> <javascript:>> wrote: 
> > Michael, that's not a bad summary. I would make a couple edits. You 
> > don't really need to qualify *all* uses. If you want to use `foo` from 
> > module `A`, you can put `import A.foo` at the top and then use `foo` 
> > in your code. That will have no surprises and no breakage. 
> > 
> > Also I think calling it "SuperSecretBase" makes it sound worse than it 
> > is. You can have modules that describe a certain named interface, and 
> > then other modules extend it. Which reminds me that I need to 
> > implement #8283, so you can introduce functions without adding methods 
> > yet. 
> > 
> > On Sat, Apr 25, 2015 at 12:31 PM, Stefan Karpinski <[email protected] 
> <javascript:>> 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 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