I think there's some confusion here.

If BetterA extends a function from A then those are the same function object 
and calling A's function is the same as calling BetterA's function by that name.

If several modules implement a common interface, they shouldn't simply happen 
to use the same names – they should implement different methods of the same 
function object, inherited from a common namespace. These methods should 
dispatch on a connection object that determines who's method to use.

> On Apr 25, 2015, at 8:02 PM, Scott Jones <[email protected]> wrote:
> 
> I think you are again misunderstanding... I am *not* writing "generic" code.
> I am writing code that accesses database A, with names like connect, 
> set_record, get_record, disconnect
> It's connect takes an argument of type A.DBManager, with some parameters like 
> address, port, user, password, and returns an A.DBConnection object.
> There is absolutely no ambiguity with the Base.connect, nor is the interface 
> necessarily even the same, *however*, it is what the users of database A
> would *expect* as far as names (possibly identical names to database A's C 
> bindings).
> I also use some other code that extends that package, say BetterA, adding 
> useful stuff like being able to serialize / deserialize Julia objects, and 
> use set_record and get_record.
> That code was written with A in mind, and *explicitly* imports set_record and 
> get_record, extends them, and exports them.
> My code does using A, using BetterA, and then does things like:
> myconn = connect(aManager, "127.0.0.1", 3000, "scott", "") ; 
> set_record(myconn, myjuliaobject)
> That set_record is actually handled nicely by multiple dispatch, the 
> set_record in BetterA takes the Julia object, builds a string, and then calls 
> A's set_record.
> 
> If I understand correctly (and this is why I said at the very beginning, part 
> of this may be my newness to Julia), then if I have to explicitly reference
> A.set_record, it will not work, because it will *not* dispatch to 
> BetterA.set_record...
> 
> Is that correct or not?
> 
> Note, another reason I *don't* want to have to specify the module/package, is 
> what happens if I want to use another package, that implements the same 
> interface?
> For example, I started out using MongoDB.connect, MongoDB.set_document!, 
> etc., but then my old classmate, friend and great 6.111 partner Brad Kuzsmaul 
> comes along and convinces me that
> TokuMX is the greatest thing since sliced bread, so now I want to simply do:
> using TokuMX instead of using MongoDB, and everything is hunky-dory, but I'll 
> be very sad if I had to go in and edit all the code to say 
> TokuMX.set_document instead of MongoDB.set_document!.
> 
> Now, after I've gotten my code working for multiple data sources I realize I 
> need to connect to a KVS to use as the backend... So, I want to use a package 
> GTM, that has a
> connect(gtm_manager, cluster, namespace), and a set_node!(gtmconnect, global, 
> value, subscripts...).  Later, I discover that there is another package 
> GlobalsDB, that implements the same interface,
> and so I have the same issue, I don't want to have been forced to not do 
> using, when there are absolutely no ambiguities, and I really don't want to 
> have to use module names on my calls!
> 
> The important point is that there can be different, unambiguous, perfectly 
> valid sets of functions, which do not implement the same interface, but which 
> may indeed implement different interfaces
> (MongoDB & TokuMX may implement some sort of Document DB interface, while GTM 
> & GlobalsDB implement an ANSI M interface, and MySQL & Postgres & SQL_Server 
> & ODBC all implement a SQL interface...
> and *all* of them are going to want to call things by the names that make 
> sense to users of their systems... and those users are also going to want to 
> be able to use multiple interfaces without hassle)
> 
> This is all very real world...
> 
> @kevin I hope this answers your question as well
> 
> 
> 
>> On Saturday, April 25, 2015 at 6:56:55 PM UTC-4, Jeff Bezanson wrote:
>> In general connect(x, y, z) is dynamically dispatched: you don't 
>> always know the type of `x`. So you wouldn't be able to write 
>> *generic* code that uses connect. In generic code, there really can be 
>> only one interface: if I write code that's supposed to work for any 
>> `x`, and I say `connect(x, address, port)`, like it or not my code 
>> only works for one of A and B, not both. 
>> 
>> 
>> On Sat, Apr 25, 2015 at 6:25 PM, Scott Jones <[email protected]> wrote: 
>> > No, not at all. 
>> > 
>> > I have a bunch of code written using package A. 
>> > It knows what the correct arguments are to the connect function for type 
>> > AConnectionManager. 
>> > I did using A, because having to specify all the time which package 
>> > (however 
>> > short the name is), 
>> > and it means that I wouldn't be able to use other packages with were 
>> > designed to extend package A 
>> >  (and did use the import A to extend the functions with new methods). 
>> > 
>> > Then I need to connect to another database package, that also used the 
>> > name 
>> > connect, with other arguments, 
>> > but no conflicting signatures at all. 
>> > It has a connect(BConnectionManager, namespacename, globalname) function 
>> > (with a set of methods). 
>> > There might also be further packages which extend module B's functions, 
>> > explicitly doing import B export extendedfunction 
>> > I think that should work just fine, but you are saying that I *must* 
>> > specify 
>> > B.connect, which then also means (AFAIK), 
>> > that I won't get a C.connect that extends B.connect (and intended to). 
>> > 
>> > Why do you want to restrict what can be done, because you have this view 
>> > that, like the Highlander, there can only be *one* true interface for a 
>> > name? 
>> > 
>> > Scott 
>> > 
>> > On Saturday, April 25, 2015 at 6:13:11 PM UTC-4, Jeff Bezanson wrote: 
>> >> 
>> >> When two people write packages independently, I claim there are only 
>> >> two options: (1) they implement a common interface, (2) they don't. To 
>> >> pick option (1), there has to be some kind of centralization or 
>> >> agreement. For option (2), which is effectively the default, each 
>> >> package just gets its own totally separate function, and you have to 
>> >> say which one you want. We're not saying "you'd better get together 
>> >> with all other developers", because with option (2) you don't need to. 
>> >> 
>> >> IIUC, you're proposing option (3), automatically merge everybody's 
>> >> methods, assuming they don't conflict. But I don't see how this can 
>> >> work. We could have: 
>> >> 
>> >> module A 
>> >> type AConnectionManager 
>> >> end 
>> >> 
>> >> function connect(cm::AConnectionManager, port, address) 
>> >> end 
>> >> end 
>> >> 
>> >> module B 
>> >> type BConnectionManager 
>> >> end 
>> >> 
>> >> function connect(cm::BConnectionManager, address, port) 
>> >> end 
>> >> end 
>> >> 
>> >> Obviously, you cannot do `using A; using B`, and then freely use 
>> >> `connect` and have everything work. The fact that the type of the 
>> >> first argument distinguishes methods doesn't help. The rest of the 
>> >> arguments don't match, and even if they did the behaviors might not 
>> >> implement compatible semantics. The only options I see are my options 
>> >> 1 and 2: (1) move to a common interface, or (2) specify A.connect or 
>> >> B.connect in client code, because the interfaces aren't compatible. 
>> >> 
>> >> 
>> >> On Sat, Apr 25, 2015 at 5:55 PM, Scott Jones <[email protected]> 
>> >> wrote: 
>> >> > The problem is, in practice, people *will* have names that collide, and 
>> >> > will 
>> >> > not mean the same thing. 
>> >> > It seems that people here are trying to say, if you have a particular 
>> >> > name 
>> >> > you'd like to use, 
>> >> > you'd better get together with all other developers past and future and 
>> >> > hammer out who 
>> >> > "owns" the name, and what concept it can be used for... (like 
>> >> > mathematical 
>> >> > sin and fun sin, 
>> >> > or tree bark and dogs bark... it gets even worse when you consider 
>> >> > other 
>> >> > languages... 
>> >> > [Say I'm in Spain, and I write a robotics package that has a function 
>> >> > "coger"..., and somebody in Argentina 
>> >> > writes a function "coger" that does something, well, XXX...]) 
>> >> > 
>> >> > I just don't see this as working for any length of time (and I think it 
>> >> > is 
>> >> > already breaking down with Julia... 
>> >> > to me, the fact that DataFrames picked using ~ as a binary operator, 
>> >> > when 
>> >> > that might have been 
>> >> > something that somebody wanted to use in the core language, shows how 
>> >> > fragile things 
>> >> > are now...) 
>> >> > 
>> >> > Scott 
>> >> > 
>> >> > On Saturday, April 25, 2015 at 5:27:10 PM UTC-4, Mauro wrote: 
>> >> >> 
>> >> >> I don't think it is realistic to expect be able to willy-nilly be 
>> >> >> 'using' any number of packages and it just works.  The way you propose 
>> >> >> may work most of the time, however, there were some solid arguments 
>> >> >> made 
>> >> >> in this thread on how that can lead to hard to catch failures. 
>> >> >> 
>> >> >> And maybe more importantly, from a programmer's sanity perspective, I 
>> >> >> think it is imperative that one generic function does just one 
>> >> >> conceptual thing.  Otherwise it gets really hard to figure out what a 
>> >> >> piece of code does. 
>> >> >> 
>> >> >> On Sat, 2015-04-25 at 22:24, Scott Jones <[email protected]> 
>> >> >> wrote: 
>> >> >> > On Saturday, April 25, 2015 at 3:58:16 PM UTC-4, Jeff Bezanson 
>> >> >> > wrote: 
>> >> >> >> 
>> >> >> >> I think this is just a different mindset than the one we've 
>> >> >> >> adopted. 
>> >> >> >> In the mindset you describe, there really *ought* to be only one 
>> >> >> >> function with each name, in other words a single global namespace. 
>> >> >> >> As 
>> >> >> >> long as all new definitions for a function have disjoint 
>> >> >> >> signatures, 
>> >> >> >> there are no conflicts. To deal with conflicts, each module has its 
>> >> >> >> own "view" of a function that resolves conflicts in favor of its 
>> >> >> >> definitions. 
>> >> >> >> 
>> >> >> > 
>> >> >> > As a practical point, *why* should I have to know about every other 
>> >> >> > package 
>> >> >> > or module that users of my package might possibly want to use at the 
>> >> >> > same 
>> >> >> > time? 
>> >> >> > With the way it is now, it seems I have to force everybody to not 
>> >> >> > use 
>> >> >> > using, and use fully specified names, which seems utterly against 
>> >> >> > the 
>> >> >> > extensibility of Julia, 
>> >> >> > because if I try to export a function, I must know the intentions of 
>> >> >> > every 
>> >> >> > user, which packages they might load, etc. that might possibly have 
>> >> >> > the 
>> >> >> > same name. 
>> >> >> > 
>> >> >> > I have a module that defines a packed database format, and I want to 
>> >> >> > define 
>> >> >> > a length, push!, and getindex methods... 
>> >> >> > Then (for examples sake) I also want to define a foobar method that 
>> >> >> > people 
>> >> >> > can use, and be able to call it on objects from my module with just 
>> >> >> > foobar(db,arg1,arg2) (where db is from my class). 
>> >> >> > All is well and good, but then some user complains that they can't 
>> >> >> > use 
>> >> >> > my 
>> >> >> > package and package newdb, because coincidentally they also defined 
>> >> >> > a 
>> >> >> > function 
>> >> >> > called foobar, that does have a different signature. 
>> >> >> > 
>> >> >> > I believe they should be able to use both, as long as there aren't 
>> >> >> > any 
>> >> >> > real 
>> >> >> > conflicts, *without* spurious warnings... 
>> >> >> > 
>> >> >> > 
>> >> >> >> This approach has a lot in common with class-based OO. For example 
>> >> >> >> in 
>> >> >> >> Python when you say `x.sin()`, the `sin` name belongs to a single 
>> >> >> >> method namespace. Sure there are different namespaces for *top 
>> >> >> >> level* 
>> >> >> >> definitions, but not for method names. If you want a different 
>> >> >> >> `sin` 
>> >> >> >> method, you need to make a new class, so the `x` part is different. 
>> >> >> >> This corresponds to the requirement you describe of methods 
>> >> >> >> referencing some new type from the same julia module. 
>> >> >> >> 
>> >> >> >> Well, that's not how we do things. For us, if two functions have 
>> >> >> >> the 
>> >> >> >> same name it's just a cosmetic coincidence, at least initially. In 
>> >> >> >> julia two functions can have the same name but refer to totally 
>> >> >> >> different concepts. For example you can have Base.sin, which 
>> >> >> >> computes 
>> >> >> >> the sine of a number, and Transgressions.sin, which implements all 
>> >> >> >> sorts of fun behavior. Say Base only defines sin(x::Float64), and 
>> >> >> >> Transgressions only defines sin(x::String). They're disjoint. 
>> >> >> >> However, 
>> >> >> >> if you say 
>> >> >> >> 
>> >> >> >> map(sin, [1.0, "sloth", 2pi, "gluttony"]) 
>> >> >> >> 
>> >> >> >> you can't get both behaviors. You'll get a method error on either 
>> >> >> >> the 
>> >> >> >> 1.0 or the string. You have to decide which notion of `sin` you 
>> >> >> >> mean. 
>> >> >> >> We're not going to automatically merge the two functions. 
>> >> >> >> 
>> >> >> >> 
>> >> >> > 
>> >> >> > I'm not saying you should... on the other hand, if I have to 
>> >> >> > functions 
>> >> >> > from 
>> >> >> > different packages, developed independently, 
>> >> >> > that happen to have a name in common, (but with different 
>> >> >> > signatures), 
>> >> >> > the 
>> >> >> > users should not have to somehow get the developers 
>> >> >> > together (who may not even be around anymore), to somehow resolve 
>> >> >> > the 
>> >> >> > conflict (which would probably adversely affect other users 
>> >> >> > of both packages if some names had to be changed) 
>> >> >> > 
>> >> >> > 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. 
>> >> >> > 
>> >> >> > 
>> >> >> > I'm sorry, but that just seems like a recipe for disaster... you are 
>> >> >> > saying 
>> >> >> > that *after* users finally 
>> >> >> > decide they want to use two packages together, that then somehow you 
>> >> >> > will 
>> >> >> > force the 
>> >> >> > developers of the packages to agree on a common interface, or change 
>> >> >> > the 
>> >> >> > names of conflicting functions, 
>> >> >> > or make everybody use names qualified with the module name(s)... 
>> >> >> > 
>> >> >> > As for your map, example... 
>> >> >> > If instead, I have map(sin, [1.0, myslothdays, 2pi, mygluttonydays] 
>> >> >> > ), 
>> >> >> > where myslothdays and mygluttonydays both have the type MySinDiary, 
>> >> >> > and 
>> >> >> > there is a Transgressions.sin(x::Transgressions.MySinDiary) 
>> >> >> > method... 
>> >> >> > that should work, right? 
>> >> >> > 
>> >> >> > What is a good reason for it not to work? 
>> >> >> > 
>> >> >> > Scott 
>> >> >> > 
>> >> >> > On Sat, Apr 25, 2015 at 3:27 PM, Scott Jones <[email protected] 
>> >> >> >> <javascript:>> wrote: 
>> >> >> >> > 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]> 
>> >> >> >> >> 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]> 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]> 
>> >> >> >> 
>> >> >> >> >> >> 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