Re: implementing such a merge function.

My first instinct would be to create a list of methods from each function, 
find the intersection, then return a function with methods determined by 
the methods from each input function, with methods in the intersection 
going to the value of "conflicts_favor". My question is, would it be okay 
to create a function f within the scope of merge, add methods to f by 
iterating through a list, and then return f? In particular, if one assigns 
the value of a global constant 'connect' to the returned function of merge, 
is a copy of the returned function created and then bound to 'connect', or 
would 'connect' be bound to something else that would cause trouble down 
the line?

Thank you!
D

On Sunday, April 26, 2015 at 1:41:24 PM UTC-4, Jeff Bezanson wrote:
>
> 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. 
>
> Scott, I think you're overstating the damage done by a name collision 
> error. You can't expect to change package versions underneath your 
> code and have everything keep working. A clear, fairly early error is 
> one of the *better* outcomes in that case. 
>
> In your design, there are *also* situations where an update to a 
> package causes an error or warning in client code. I'll grant you that 
> those situations might be rarer, but they're also subtler. The user 
> might see 
>
> Warning: modules A and B conflict over method foo( #= some huge signature 
> =# ) 
>
> What are you supposed to do about that? 
>
> It's worth pointing out that merging functions is currently very 
> possible; we just don't do it automatically. You can do it manually: 
>
> using GlobalDB 
> using SQLDB 
>
> connect(c::GlobalDBMgr, args...) = GlobalDB.connect(c, args...) 
> connect(c::SQLDBMgr, args...) = SQLDB.connect(c, args...) 
>
> This will perform well since such small definitions will usually be 
> inlined. 
>
> If people want to experiment, I'd encourage somebody to implement a 
> function merger using reflection. You could write 
>
> const connect = merge(GlobalDB.connect, SQLDB.connect, 
> conflicts_favor=SQLDB.connect) 
>
>
> On Sun, Apr 26, 2015 at 12:10 PM, David Gold <[email protected] 
> <javascript:>> 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. 
> > 
> > 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