January 06, 2004
dunno.. i thought thats only for namespaces..

In article <btda5i$1puo$1@digitaldaemon.com>, Walter says...
>
>
>"Antti Sykäri" <jsykari@gamma.hut.fi> wrote in message news:slrnbvjcbm.69b.jsykari@pulu.hut.fi...
>> If there are any other valid reasons against non-member operators, please bring them forth because I for one have forgotten them. Did the original D "vision" include them? Why/why not? Is the reason that they haven't been implemented a reason of principle or merely a practical one?
>
>The problem is that if they were implemented, then there'd be a need for Koenig lookup. Once there's Koenig lookup, then there's the export lookup madness.
>
>


January 06, 2004
> "Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:btdalv$1qml$1@digitaldaemon.com...
> >
> > "Walter" <walter@digitalmars.com> wrote in message news:btda5i$1puo$1@digitaldaemon.com...
> > >
> > > "Antti Sykäri" <jsykari@gamma.hut.fi> wrote in message news:slrnbvjcbm.69b.jsykari@pulu.hut.fi...
> > > > If there are any other valid reasons against non-member operators, please bring them forth because I for one have forgotten them. Did
the
> > > > original D "vision" include them? Why/why not? Is the reason that
they
> > > > haven't been implemented a reason of principle or merely a practical one?
> > >
> > > The problem is that if they were implemented, then there'd be a need
for
> > > Koenig lookup.
> >
> > With you so far
> >
> > > Once there's Koenig lookup, then there's the export lookup madness.
> >
> > Please explain
>
> I've done some extensive googling for info on export. It seems the main difficulty with export is the ADL. The two phase lookup comes in to play, once when the template is defined and the other when it is instantiated.
The
> second lookup is the ADL one. The ADL can cut across all of the
'translation
> units', meaning an arbitrarilly large number of separate symbol tables
need
> to be analyzed. This is essentially madness.
>
> As best as I can tell, this problem was not realized when export was voted into the Standard, and is the source of many opinions that export is unimplementable. EDG proved it could be implemented, reportedly consuming
3
> man years, but I don't hear any more about the alleged advantages of
export
> (code hiding, faster compilation), and hence I suspect those advantages do
> not occur in practice.
>
> Export is a canonical example of how backwards compatibility with
seemingly
> innocuous design decisions can lead to disaster.
>
> I do not wish to import that madness into D <g>.

I've not given it enough thought on a global scale, but I can't see how you can expect to get away without ADL, with functions and non-member operators.

If this means you must go for export madness, then you'd better get out the white coat.


January 06, 2004
"Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:bte1ib$2v71$1@digitaldaemon.com...
> I've not given it enough thought on a global scale, but I can't see how
you
> can expect to get away without ADL, with functions and non-member
operators.

ADL is justified by non-member operators. Without non-member operators, no ADL is needed.

> If this means you must go for export madness, then you'd better get out
the
> white coat.


January 06, 2004
i don't see how the operator overloading can result in more work to "look up"..

if the parser finds some code snipped like this:

a + b

then it simply translates it to

opAdd(a,b)

directly. and then its just a normal function call.. and done. the normal operator rules for encoding/parsing code-lines with operators still apply, and the endresult is pleasing, and with no issues in parsing at all..

class Printer {
Printer print(char[] text) { ...; return this; }
}

Printer opStream(Printer p,char[] text) { return p.print(text); }
Printer opStream(Printer p,int value) { return p.print(toString(value)); }

say opStream is <~ (my lovely token:D)..

then you can write

Printer opStream(Printer p,vec3 v) {
p <~ '(' <~ x <~ ',' <~ y <~ ',' <~ z <~ ')';
}

and a simple piece of code would be like this:

Printer p(stdout);

p <~ "Position: " <~ position;

wich would translate to

opStream(opStream(p,"Position: "),position);

and would then simply decode to

opStream(opStream(Printer,char[]),vec3);

for now, it would be doable with opCall.. (as yet suggested by some).

opStream could get some syntactic sugar, like we don't need to write

StreamerType opStream(StreamerType s,T) {
/* access stream */
return s;
}

but only

char[] opStream(T) {
/* access stream */
return streamlined data packet; // doesn't have to be char[], but in case of io,
you stream with char[] often
}

and

class StreamerType {
opStream(char[] s) {
/* print stream */
}
}


example:

class Printer {
opStream(char[] s) {
printf("%.*s",s);
}
}

char[] opStream(char[] text) {
return text; // just rewrite it to the stream as its the base format.
}

char[] opStream(vec3) {
return <~'('<~x<~','<~y<~','<~z<~')';
}

Printer p;

p <~ "Position: " <~ position;

would translate to

p.opStream(opStream(text) ~ opStream(position));

this thought is not finished, but merely an idea..

but overloadable non-member operators are ESSENCIAL. and i don't see why they are, at all, different, than what we have now. technically.

In article <slrnbvjcbm.69b.jsykari@pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?= says...
>
>In article <btbv9t$2p2s$1@digitaldaemon.com>, Felix wrote:
>> Me too, I find a little weird the syntax Ta.opAdd(Tb) but, if I remember, this is the standard way to overload operators in C++, too. Maybe, if cannot be simply dropped, an alternative definition will be suitable.
>
>There's no "standard" way in C++, you can pick any way you like. The things that affect your choice are the same with operators and other functions:
>
>- only member functions/operators can be overridden in a derived class - only non-member functions can be used to extend the class after it has
>  been closed
>
>For example, suppose that the standard output mechanism in D would be something like
>
>Printer stdout;
>void main()
>{
>    stdout ~ "Hello world " ~ 1 ~ 2 ~ 3 ~ endl;
>}
>
>And Printer implemented something like:
>
>class Printer
>{
>    Printer opCat(int i) { .. }
>    Printer opCat(char[] c) { .. }
>    Printer opCat(Object o) { .. }
>}
>
>[replace Printer with OutputStream if you feel very generic]
>
>then the only way to introduce a new printable user-defined type, say Vector3, that isn't derived from Object but still can be printed to stdout is to make a free-standing function:
>
>Printer opCat(Printer p, Vector3 v)
>{
>    p ~ "(" ~ v.x ~ ", " ~ v.y ~ ", " ~ v.z ~ ")";
>}
>
>That is, if that was possible in D. You can do that in C++. If D was an OO only language, then making types not derived from Object would not be possible and the issue would be moot. Heck, we could be as well programming in Java. But I gather D is supposed be multiparadigm and all that, and you ought to be able to do stuff also without objects if you want. I object to objects.
>
>And if there is some template code somewhere, saying "stdout ~ t" where t is of type which is argument for the template, you sure as hell want your Vector3 to be printed instead of getting a message along the lines of "Printer does not have member function opCat(Printer, Vector3). Wanna change it? You can't! Bwahaha!". Duh!
>
>So to conclude the rant, I fully agree with davepermen:
>
>> just get rid of it. binary operators don't belong to a member. they never did.
>
>and Matthew:
>
>> That's something we need that is supported by a large number of issues, not just this one. It's an absolute must, and I can't seee Walter escaping us on this one. :)
>
>The only potential problems I see with free-standing operators are:
>
>1. Importing or not importing a module containing operators will affect
>   the way functions are overloaded. "a + b" might mean a different
>   thing after adding an import. On the other hand, normal function
>   calls are already vulnerable for this and I haven't experienced any
>   problems whatsoever. Nor have I had any problems with the issue in
>   C++, where it also exists.
>
>2. The overloading rules might be a tad more complex with freestanding
>   operators. That is, they might require some thinking so that they
>   don't cause any surprises. Maybe there is someone less tired to
>   perform the thinking ;) Complexity doesn't bother me if the rules are
>   sufficiently simple to grasp intuitively. (Unless they end up in some
>   Snake-Tongued Two-Phased Koenig Lookup or similar maze of mirrors)
>
>If there are any other valid reasons against non-member operators, please bring them forth because I for one have forgotten them. Did the original D "vision" include them? Why/why not? Is the reason that they haven't been implemented a reason of principle or merely a practical one?
>
>By tackling those issues one by one we might even arrive at a solution that satisfies everyone. At least, one can hope...
>
>-Antti
>


January 06, 2004
"davepermen" <davepermen_member@pathlink.com> wrote in message news:bte3p3$pp$1@digitaldaemon.com...
> i don't see how the operator overloading can result in more work to "look
up"..
>
> if the parser finds some code snipped like this:
>
> a + b
>
> then it simply translates it to
>
> opAdd(a,b)
>
> directly. and then its just a normal function call.. and done. the normal operator rules for encoding/parsing code-lines with operators still apply,
and
> the endresult is pleasing, and with no issues in parsing at all..

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.


January 06, 2004
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?

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
Hauke Duden wrote:
> v + b;    //works only if fancyOperatorModule is imported

Sorry, that should have been

v + b;    //works only if bigNumIntegration is imported

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.

else we just use a using statement to import the operators of some module. shouldn't be that hard..

and else, just ADL around.. if needed. the feature is essencial for oo design, as well as for generic design.

nobody wants to write

output(output(output(output(buffer,"Hello, my name is "),name),", and i come
from "),country);

i see a one-one mapping from function to operator. i see why you don't. but i think the same rules can simply be applied..

and if you need the operators of some math library, wich you can only access by math.someFunction, how about this?

with(math) {
a += b;
}

(as a proposed using statement..)

and else..

a math.+= b; doesn't look _THAT_ bad :D

so you would not require the ADL thingy at all.. or too ugly?

In article <bte4a7$1je$1@digitaldaemon.com>, Walter says...
>
>
>"davepermen" <davepermen_member@pathlink.com> wrote in message news:bte3p3$pp$1@digitaldaemon.com...
>> i don't see how the operator overloading can result in more work to "look
>up"..
>>
>> if the parser finds some code snipped like this:
>>
>> a + b
>>
>> then it simply translates it to
>>
>> opAdd(a,b)
>>
>> directly. and then its just a normal function call.. and done. the normal operator rules for encoding/parsing code-lines with operators still apply,
>and
>> the endresult is pleasing, and with no issues in parsing at all..
>
>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.
>
>


January 06, 2004
"Walter" <walter@digitalmars.com> wrote in message news:bte342$31cg$1@digitaldaemon.com...
>
> "Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:bte1ib$2v71$1@digitaldaemon.com...
> > I've not given it enough thought on a global scale, but I can't see how
> you
> > can expect to get away without ADL, with functions and non-member
> operators.
>
> ADL is justified by non-member operators. Without non-member operators, no ADL is needed.

Not true. Generalising shims require ADL for a kick off.


January 06, 2004
> 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?

Absolutely. And without which, we'll all be hitting ourselves in the head and turning for the C++ compiler.

> 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.