January 06, 2004
> if we disallow member-operators (wich i don't see useful anyways), then
each
> operator has an unique name, and can only exist one time. i think you
should
> simply drop any modularisation for operators. they are syntactic glue,
nothing
> more.

<snip>

How so? If you define a String class, and I define a Date class, are you saying that D should not support the ability for us to integrate them into, say, a generic serialisation library? Or to concatenate your string and my string? Or to work with your Transformation function and my Matrix?

Is D to be extensible by users, like C and C++, or only by DM, like Java?


January 06, 2004
"Hauke Duden" <H.NS.Duden@gmx.net> wrote in message news:bte5b4$3cq$1@digitaldaemon.com...
> Walter wrote:
> > The problem is if opAdd() is defined in another module that is not the current module. It will not be found with the normal scoped lookup. With ordinary functions, one just does:
> >
> >     foo.opAdd(a,b)
> >
> > if the function is in module foo. That doesn't work out so good for
operator
> > overloads. What ADL does is look at the types of the arguments to the function, and uses those types to add more scopes to look for the opAdd
in.
>
> Would that even be sufficient? Doesn't one expect to be able to write an opAdd that works on objects whose classes are defined in other modules?

Can't the function dispatch a method call by hand? For example
Number opAdd(Number a, Number2 b) {
  return b.opAdd(a);
}
Then it is up to Number2 (or a subclass of Number2) to define opAdd. It
would be nice to have the compiler's ability to detect if a method exists of
a given signature before calling it, though, which would mean some
reflection support. I would definitely want to keep all function resolution
to things in scope and leave unscoped function resolution to run-time
dispatching. That seems the only sane way to go.

> I.e. what if the opAdd is in neither of the object modules, but in a completely different one?
>
> Seems to me that the only sensible solution is to require that the module opAdd is defined in has to be imported for it to be used. Apply the same rules as in overloaded function calling - it IS only syntactic sugar, after all.
>
> import math.vectors;
> import gnu.bignum;
> import bigNumIntegration; //defines opAdd(Vector,BigNum)
>
> Vector v;
> BigNum b;
>
> v + b; //works only if fancyOperatorModule is imported
>
> And if a compatible operator is defined in more than one imported module then a qualified call of the type bigNumIntegration.opAdd(v,b) instead of (v + b) can be used. Those cases should be rare, so no big deal.
>
>
> Hauke


January 06, 2004
Matthew wrote:
>>I.e. what if the opAdd is in neither of the object modules, but in a
>>completely different one?
>>
>>Seems to me that the only sensible solution is to require that the
>>module opAdd is defined in has to be imported for it to be used. Apply
>>the same rules as in overloaded function calling - it IS only syntactic
>>sugar, after all.
> 
> 
> But what about when you're working with permutations of all kinds of types
> from potentially unlimited modules, in generic code?
> 
> D wants to be generic. Therefore D needs ADL. If ADL is hard for compilers,
> so be it. Those appear to be the breaks.

I have no idea what ADL is, but wouldn't the same problem also apply to all other overloaded global functions?

I think maybe I understand the problem now. Please correct me if I'm wrong:

If you write a template that contains a function call to foo(A a,B b), where A and B are template parameters, then this template will be instantiated only once for each combination of (A,B) it is used with.

The problem is that if you want to overload foo in a module unrelated to A and B, then the template instance becomes dependent not only on the types A and B, but also on the module where foo is defined. But THAT may be different, depending on where the template is actually used, since different places of usage may import different modules.

I do not see how this problem can ever be solved, except by treating templates like macros and simply always compiling it in the context it is used in, every time.

But if this isn't solved for "normal" global functions, why does it have to be solved for global operators?

Besides, I think the problem should be pretty rare in practice. The only situation where it would cause trouble is if the same template is used with the same two types at two different places in the program, and you have imported a different definition of the operator/global function in one context than in the other. In the case of stream operators and stuff like that, I think that you'll usually have at most one overload for each combination of types.

So, can't the calls of global functions/operators inside templates be resolved from the context where the template is instantiated first? That seems to be the only workable alternative to me.


Hauke
January 06, 2004
Matthew wrote:
> How so? If you define a String class, and I define a Date class, are you
> saying that D should not support the ability for us to integrate them into,
> say, a generic serialisation library? Or to concatenate your string and my
> string? Or to work with your Transformation function and my Matrix?

I think a workaround with RTTI (safe cast) and interfaces can be found for the rare cases where it matters. For example for strings and for the IO streams library. This would also mean that we could have a great advantage, if structs would be able to implement interfaces and could be casted to classes (of the same name) using automatic boxing.

You would be advised to look at the library design of such a smart, pure object-oriented, multiple-inheritance, interface-based, add more buzwords here, language as Sather. ;)

Bottom line: ADS is not necessary. Non-member operators are not necessary. Some thinking is.

-eye

January 06, 2004
unique per type-pair

thats what i ment.

In article <bteaec$akr$3@digitaldaemon.com>, Matthew says...
>
>> if we disallow member-operators (wich i don't see useful anyways), then
>each
>> operator has an unique name, and can only exist one time. i think you
>should
>> simply drop any modularisation for operators. they are syntactic glue,
>nothing
>> more.
>
><snip>
>
>How so? If you define a String class, and I define a Date class, are you saying that D should not support the ability for us to integrate them into, say, a generic serialisation library? Or to concatenate your string and my string? Or to work with your Transformation function and my Matrix?
>
>Is D to be extensible by users, like C and C++, or only by DM, like Java?
>
>


January 06, 2004
>Bottom line: ADS is not necessary. Non-member operators are not necessary. Some thinking is.

show me how.


January 06, 2004
"Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:bteaea$akr$1@digitaldaemon.com...
> Not true. Generalising shims require ADL for a kick off.

Example?


January 06, 2004
"Hauke Duden" <H.NS.Duden@gmx.net> wrote in message news:bte5b4$3cq$1@digitaldaemon.com...
> Walter wrote:
> > The problem is if opAdd() is defined in another module that is not the current module. It will not be found with the normal scoped lookup. With ordinary functions, one just does:
> >
> >     foo.opAdd(a,b)
> >
> > if the function is in module foo. That doesn't work out so good for
operator
> > overloads. What ADL does is look at the types of the arguments to the function, and uses those types to add more scopes to look for the opAdd
in.
>
> Would that even be sufficient? Doesn't one expect to be able to write an opAdd that works on objects whose classes are defined in other modules?

Of course. But how member operator lookup works is:

    a + b

If a is an instance of Foo, then Foo.opAdd(b) is looked for. Foo can be in another module. No special ADL rule is required.


January 06, 2004
"Walter" <walter@digitalmars.com> wrote in message
news:btf3no$1hk9$2@digitaldaemon.com...
|
|
| Of course. But how member operator lookup works is:
|
|     a + b
|
| If a is an instance of Foo, then Foo.opAdd(b) is looked for. Foo can be in
| another module. No special ADL rule is required.
|
|

What if all operators can be reversed? That way, if there's no
Foo.opAdd(typeof(b)), the compiler will look for typeof(b).opAdd_r(Foo).
Also, those who want to possibly extend a stream class, would do
MyType.opAdd_r(Stream). What about that?

-----------------------
Carlos Santander Bernal


January 07, 2004
"Carlos Santander B." <carlos8294@msn.com> wrote in message news:btfh6d$26rc$1@digitaldaemon.com...
> "Walter" <walter@digitalmars.com> wrote in message
> news:btf3no$1hk9$2@digitaldaemon.com...
> |
> |
> | Of course. But how member operator lookup works is:
> |
> |     a + b
> |
> | If a is an instance of Foo, then Foo.opAdd(b) is looked for. Foo can be
in
> | another module. No special ADL rule is required.
> |
> |
>
> What if all operators can be reversed? That way, if there's no
> Foo.opAdd(typeof(b)), the compiler will look for typeof(b).opAdd_r(Foo).

Since add is commutative, the compiler will first look for typeof(a).opAdd,
if that isn't found, it will look for typeof(b).opAdd.

> Also, those who want to possibly extend a stream class, would do MyType.opAdd_r(Stream). What about that?

I philosophically object to using operator overloading for stream I/O <g>.