>
> I am saying that if I have foo(A.type, T1, T2), in module A, and 
> foo(B.type, T2, T1), I should be able to call foo(myA, myT1, myT2), and 
> foo(myB, myT2, myT1) without any
> problems.
>

@Scott: Ah, I see. I apologize for this oversight. I can understand how 
working under this assumption (that the arguments have types specific to 
modules) would simplify the search for the relevant method. But I don't see 
how it comes to bear on the problem of 'foo()''s referent. 

I keep getting accused of insisting that every name have only one 
> meaning. Not at all. When you extend a function there are no 
> restrictions. The `connect` methods for GlobalDB and SQLDB could 
> absolutely belong to the same generic function. From there, it's 
> *nice* if they implement compatible interfaces, but nobody will force 
> them to. 
>

@Jeff: I didn't mean to impute to you that position, though I apologize if 
my wording was unclear.
 
On Monday, April 27, 2015 at 8:05:55 AM UTC-4, Scott Jones wrote:
>
>
>
> On Sunday, April 26, 2015 at 12:10:41 PM UTC-4, David Gold wrote:
>>
>> You, Jeff and Stefan seem to be concerned with different kinds of 
>> "ambiguity." Suppose I import `foo(T1, T2)` from module `A` and `foo(T2, 
>> T1)` from module `B`. I take you to claim that if I call `foo(x, y)` then, 
>> as long as there is no ambiguity which method is appropriate, the compiler 
>> should just choose which of `A.foo()` and `B.foo()` has the proper 
>> signature. I take you to be concerned with potential ambiguity about which 
>> method should apply to a given argument.
>>
>
> No, that is not at all what I am saying.
>
> I am saying that if I have foo(A.type, T1, T2), in module A, and 
> foo(B.type, T2, T1), I should be able to call foo(myA, myT1, myT2), and 
> foo(myB, myT2, myT1) without any
> problems.
>
> Everybody here seems to think I am talking about a quite different case 
> that what I really am... which is the limited case where all of the 
> functions that I export from my module
> have at least one parameter that is a type local to the module, so that 
> the compiler can know right away that it is unambiguous... (since the rule 
> is that you dispatch to the most specific type).
>
> One should be able to write modules in isolation, and as long as one 
> conforms to that simple rule of always having a local type used in all 
> exported functions, that module
> should be able to be used with `using` anywhere, without warnings, without 
> worrying that Base or one of the packages that the module uses have later 
> on added a conflicting name...
>
> Scott
>  
>
>> On the other hand, I take Jeff and Stefan to be concerned with the 
>> ambiguity of to which object the *name* '`foo()`' refers (though they 
>> should chime in if this claim or any of the following are wayward). Suppose 
>> we're the compiler and we come across a use of the name '`foo()`' while 
>> running through the code. Our first instinct when we see a name like 
>> '`foo()`' is to look up the object to which the name refers. But what 
>> object *does* this name refer to? You (Scott) seem to want the compiler 
>> to be able to say to itself before looking up the referent, "If the 
>> argument types in this use of '`foo()`' match the signature of `A.foo()`, 
>> then this instance of '`foo()`' refers to `A.foo()`. If the argument types 
>> match the signature of '`B.foo()`', then this instance of '`foo()`' refers 
>> to '`B.foo()`'." But then '`foo()`' isn't really a name, for the referent 
>> of a name cannot be a disjunction of objects. Indeed, the notion of a 
>> "disjunctive name" is an oxymoron. If you use my name, but your reference 
>> could be to either me or some other object depending on context, then you 
>> haven't really used *my* *name*, which refers to me regardless of 
>> context. 
>>
>> I suspect that many problems await if you try to adopt this "disjunctive 
>> reference" scheme. In particular, you'd need to develop a general way for 
>> the compiler to recognize not only that your use of '`foo()`' isn't 
>> intended as a name but rather as a disjunctive reference but also that 
>> every other name-like object is *actually* a name. I strongly suspect 
>> that there is no general way to do this. After all, what sorts of contexts 
>> could possibly determine with sufficient generality whether or not a given 
>> name-like object is actually a name or instead a disjunctive reference. The 
>> most obvious approach seems to be to let the compiler try to determine the 
>> referent of '`foo()`' and, if there is no referent, then to see whether or 
>> not there exist imported functions with the same name. If such imported 
>> functions exist, then perhaps the compiler decides that '`foo()`' is a 
>> disjunctive reference and tries to find an unambiguously matching method. 
>> But do we really want the compiler to assume, just because you used a 
>> "name" that has no referent but matches the name of one or more imported 
>> functions, that you really intend to use that "name" as a disjunctive 
>> reference? This is not even to mention the performance costs associated 
>> with trying to look up a referent-less "name," deciding that the "name" is 
>> actually intended as a disjunctive reference, and then trying to find a 
>> matching method and determine a "true" reference.
>>
>> Now, if you're not going to try to implement '`foo()`' as a disjunctive 
>> reference, then it must be a name. But to which object does the name refer? 
>> The obvious choice would be some "merged" function that aggregates all the 
>> unambiguously distinct methods of `A.foo()` and `B.foo()`. But where does 
>> this object live? Do we make a *new* object, i.e. a function also named 
>> `foo()` whose methods are copies of all the unambiguously distinct methods 
>> of `A.foo()` and `B.foo()` and which belongs to the scope in which 
>> `A.foo()` and `B.foo()` were imported? But then if one imports `A.foo()` 
>> and `B.foo()` in a global scope one thereby creates a global object as the 
>> referent of '`foo()`'. I suppose this isn't so bad for functions, but it 
>> seems perverse that just importing a name from a module should create 
>> global object.  
>>
>> Okay, so maybe we shouldn't create a new object. The alternative is to 
>> have to have our compiler decide upon import to let '`foo()`' refer once 
>> and for all either to `A.foo()` or `B.foo()`, and whichever one it does 
>> refer to will "absorb" all unambiguously distinct methods from the other. 
>> The first problem here is that it is entirely arbitrary which of the two 
>> functions should be the "true" referent, and which should hand over its 
>> methods. That this decision would be entirely arbitrary suggests (to me, at 
>> least) that it is not the best one to make. And regardless of which 
>> function is chosen to be the "true" referent, we still end up with the 
>> similarly perverse byproduct that just importing a name from module `A` 
>> results in a change to an object from module `B`. This seems to defeat the 
>> purpose of a module.
>>
>> Again, this is just what I understand Stefan and Jeff to be arguing. I 
>> hope that either/both will point out any misinterpretations or errors on my 
>> part.
>>
>>
>> On Sunday, April 26, 2015 at 6:24:15 AM UTC-4, Scott Jones wrote:
>>>
>>> Yes, precisely... and I *do* want Julia to protect the user *in that 
>>> case*.
>>> If a module has functions that are potentially ambiguous, then 1) if the 
>>> module writer intends to extend something, they should do it *explicitly*, 
>>> exactly as now, and 2) Julia *should* warn when you have "using" package, 
>>> not just at run-time, IMO.
>>> I have *only* been talking about the case where you have functions that 
>>> the compiler can tell in advance, just by looking locally at your module, 
>>> by a very simple rule, that they cannot be ambiguous.
>>>
>>> Scott
>>>
>>> On Sunday, April 26, 2015 at 5:46:15 AM UTC-4, [email protected] wrote:
>>>>
>>>>
>>>>
>>>> On Sunday, April 26, 2015 at 7:23:02 PM UTC+10, Scott Jones wrote:
>>>>>
>>>>> Ah, but that is NOT the situation I've been talking about... If the 
>>>>> writer of a module wants to have a function that takes ::Any, and is not 
>>>>> using any other types that are local to that package, then, from the 
>>>>> rules 
>>>>> I'd like to see, they *would* have to explicitly import from Base (or 
>>>>> whichever module they intended to extend).
>>>>>
>>>>
>>>> Neither module is extending anything, they are separate.  Its the user 
>>>> that wants to use them both in the same program, and its the user that 
>>>> Julia is protecting.
>>>>
>>>> Cheers
>>>> Lex
>>>>
>>>>  
>>>>
>>>>>
>>>>> Scott
>>>>>
>>>>> On Sunday, April 26, 2015 at 12:25:28 AM UTC-4, [email protected] 
>>>>> wrote:
>>>>>>
>>>>>> The situation I was describing is that there is:
>>>>>>
>>>>>> module A
>>>>>> type Foo end
>>>>>> f(a::Any)  ...
>>>>>> f(a::Foo) ...
>>>>>>
>>>>>> which expects f(a) to dispatch to its ::Any version for all calls 
>>>>>> where a is not a Foo, and there is:
>>>>>>
>>>>>> module B
>>>>>> type Bar end
>>>>>> f(a::Bar) ...
>>>>>>
>>>>>> so a user program (assuming the f() functions combined):
>>>>>>
>>>>>> using A
>>>>>> using B
>>>>>>
>>>>>> b = Bar()
>>>>>> f(b)
>>>>>>
>>>>>> now module A is written expecting this to dispatch to A.f(::Any) and 
>>>>>> module B is written expecting this to dispatch to B.f(::Bar) so there is 
>>>>>> an 
>>>>>> ambiguity which only the user can resolve, nothing tells the compiler 
>>>>>> which 
>>>>>> the user meant.
>>>>>>
>>>>>> Cheers
>>>>>> Lex
>>>>>>
>>>>>>
>>>>>> On Sunday, April 26, 2015 at 12:00:50 PM UTC+10, Michael Francis 
>>>>>> wrote:
>>>>>>>
>>>>>>> I don't think Any in the same position is a conflict. This would be 
>>>>>>> more of an issue if Julia did not support strong typing, but it does 
>>>>>>> and is 
>>>>>>> a requirement of dynamic dispatch. Consider 
>>>>>>>
>>>>>>> function foo( x::Any ) 
>>>>>>>
>>>>>>> Will never be chosen over 
>>>>>>>
>>>>>>> Type Foo end 
>>>>>>>
>>>>>>> function foo( x::Foo ) 
>>>>>>>
>>>>>>> As such I don't get the argument that if I define functions against 
>>>>>>> types I define they cause conflicts. 
>>>>>>>
>>>>>>> Being in the position of having implemented a good number of modules 
>>>>>>> and being bitten in this way both by my own dev and by changes to other 
>>>>>>> modules I'm very concerned with the direction being taken. 
>>>>>>>
>>>>>>> I do think formalization of interfaces to modules ( and behaviors) 
>>>>>>> would go a long way but expecting a diverse group of people to 
>>>>>>> coordinate 
>>>>>>> is not going to happen without strong and enforced constructs. 
>>>>>>>
>>>>>>> As an example I have implemented a document store database 
>>>>>>> interface, this is well represented by an associative collection. It 
>>>>>>> also 
>>>>>>> has a few specific methods which would apply to many databases. It 
>>>>>>> would be 
>>>>>>> nice to be able to share the definition of these common interfaces. I 
>>>>>>> don't 
>>>>>>> advocate adding these to base so how should it be done? 
>>>>>>>
>>>>>>>

Reply via email to