February 14, 2007 overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Michiel wrote: >> And we should keep on frowning on attempts to use overloaded << for I/O >> purposes <g>. > > Why? I think it's intuitive. The arrows point from the source of the message to > the destination. Should the operator only be used for shifting because that > happens to have been its first purpose? > > I also like how you can send a message to an abstract object. And that can be a > cout, a cerr, an error console in a GUI, or something else. Same thing the other > way around. Good question. C++ conventional wisdom is that's great, because it's always been done that way in C++. Few question it. Let's step back a bit. Suppose I overload '+' to be "launch nuclear missiles." You see some code: x = a + b; and what do you think? I think "add a and b, assign the result to x", but instead, nuclear missiles are launched. It is completely unexpected and unintuitive for '+' to mean anything other than 'add'. To do something completely unrelated to 'add', one should instead write: x = launchNuclearMissiles(a, b); where the meaning is plain, or at least, one isn't assuming it's adding a and b. So why overload operators at all? For the purposes of implementing UDTs (User Defined Types) that have legitimate arithmetic operations on them, such as matrices, extended precision numbers, etc. Now back to '<<' and '>>'. To me, they are arithmetic operators, and mean shift left and shift right. Shift is not an I/O operation. To say they are intuitive is not because they are, but because C++ users are simply accustomed to it. a << b << c << d; That doesn't scream I/O to me. And if a, b, etc. are non-trivial expressions, they wind up: 1) interacting with the operator precedence of << in unfortunate ways 2) suppose you want to print a variable shifted left by a few bits: a << (b << 3) << c << d; blech. 3) Suppose you've got some relational operators and templates thrown in: a << b<c<3>> << c < d << e; and things just go downhill from there. 4) Operators aren't very greppable, meaning it's hard to go grepping through source code looking to see if << has been overloaded. 5) The Spirit library for C++ uses operator overloading to create a specialized DSL for specifying grammar. The trouble is, the code looks exactly like regular C++ expressions (since new operators cannot be defined, nor can operator precedence be changed), and there are some big warning boxes that the resulting appearance may LOOK like C++ but is about as far removed from it as one can get. This doesn't enhance readability. And to sum up: writefln(a, b, c, d); seems pretty intuitive to me. There's just no advantage to overloading <<. |
February 14, 2007 Re: overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | > Good question. C++ conventional wisdom is that's great, because it's always been done that way in C++. Few question it. Sure. I can't deny that I'm used to it because of C++. > Let's step back a bit. > > <nuclear missile example> + is intuitively addition because it's been that way in mathematics long before there were ever computers. Bitshifts, on the other hand, are a bit more recent. And using the << operator for them even more so. It might have been the << operator's first use, but not necessarily its best. << is an arrow. When you point an arrow from a to b, I assume that either a is going to b, or that a becomes b. Not that a is shifted right by b bits. > So why overload operators at all? For the purposes of implementing UDTs (User Defined Types) that have legitimate arithmetic operations on them, such as matrices, extended precision numbers, etc. I totally agree with you here. For example, the way you implemented the equality/inequality and comparison operators is great. Much less room for misuse. And in C++, I never deviated from that behavior. > > <some more examples> > Some good points (though you were using C++ templates as an example, not D templates). But I could make the same argument for writefln: writefln(add(5, 7, 8, pow(42, 3)), f("one", "two", "three, four")); That's not very clear to me either. People will just have to make their own code a bit nicer and use proper spacing or what have you. > And to sum up: > > writefln(a, b, c, d); > > seems pretty intuitive to me. There's just no advantage to overloading <<. What about the other reason I mentioned? About sending messages to abstract objects with a standard operator? "I also like how you can send a message to an abstract object. And that can be a cout, a cerr, an error console in a GUI, or something else. Same thing the other way around." I even missed an important one. File I/O. So if << isn't the right streaming operator, use another one. Like <- and ->. You don't use them anyway. To sum up: I love D. But I also like the streaming operator. |
February 14, 2007 Re: overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote
> You see some code:
>
> x = a + b;
>
> and what do you think? I think "add a and b, assign the result to x"
What one thinks depends on the education.
As soon as one has exposed ones thinking to abstract algebras, the mathematical structures of groups, rings and fields, etc., one looses the binding of addition to "+". It comes back, when one is assured, that the operands are indeed the usual numbers.
"x = a + b;" may then very well mean: start rocket squads from locations a and b, combine them("+") to an attack formation and let them attack("=") location x.
Please be aware that also D currently breaks your thinking:
x = b;
can currently assign a value to b. This contradicts your statement above.
-manfred
|
February 14, 2007 Re: overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michiel | Michiel wrote > << is an arrow. This is as true as "[", "(" and "{" are arrows. As a born french speaker one would "<<" primarily recognise as an opening parentheses: http://www.microsoft.com/typography/developers/fdsspec/punc.htm -manfred |
February 14, 2007 Re: overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manfred Nowak | Manfred Nowak wrote: > Walter Bright wrote >> You see some code: >> >> x = a + b; >> >> and what do you think? I think "add a and b, assign the result to >> x" > > What one thinks depends on the education. Of course. I assume here a computer programming background, where the conventional meaning is, well, conventional. We can relate this to the Lisp thread here, where (1- x) means x-1. The unconventionality of the Lisp syntax makes it a hard sell. > Please be aware that also D currently breaks your thinking: > x = b; > > can currently assign a value to b. This contradicts your statement above. I disagree, because this is in the context of computer programming, not abstract algebra. C++ stands out alone in its use of << for such, and is therefore unconventional. |
February 14, 2007 Re: overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | > 3) Suppose you've got some relational operators and templates thrown in:
>
> a << b<c<3>> << c < d << e;
Won't that treat the >> in b<c<3>> as the shift right operator and fail compilation?
a << b<c<3> > << c < d << e?
which higlights how bad the syntax is I think.
At least thats the only meaning of the code that makes sense to me ;-)
|
February 14, 2007 Re: overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michiel | Michiel wrote: > What about the other reason I mentioned? About sending messages to abstract > objects with a standard operator? > > "I also like how you can send a message to an abstract object. And that can be a > cout, a cerr, an error console in a GUI, or something else. Same thing the other > way around." > > I even missed an important one. File I/O. This can be done using variadic functions or tuples. > To sum up: I love D. But I also like the streaming operator. I didn't expect to convince you <g>. |
February 14, 2007 Re: overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | > This can be done using variadic functions or tuples. It would just be good if there was a standard and universally recognizable way to do it. A standard abstract class for message-sending that you can subclass. With standard subclasses for std-out, std-err, std-in, file-out and file-in. If you really don't want to use an operator, then just some variadic functions? > I didn't expect to convince you <g>. Right back at you. :) But if you leave the streaming operator out of it, how about that class? I could of course write one myself, but it wouldn't be standardized. And I think it should be. |
February 14, 2007 Re: overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> [...]
> And to sum up:
>
> writefln(a, b, c, d);
>
> seems pretty intuitive to me. There's just no advantage to overloading <<.
I can just fully agree with you, though, I slightly like Tango's Cout better. But that's just me - used writefln back then, too.
Frankly, using '>>' and '<<' for streams may seem appropriate, but it's just not any kind of arrow, or such. Bit shifting is a very good use for those operators, though maybe they should /actually/ be bit rotating..I always have to think of VHS cassettes and rewind/forward, when I see the operator.
Best regards,
Alex
|
February 14, 2007 Re: overloading operators for I/O | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michiel | Michiel wrote:
>> This can be done using variadic functions or tuples.
>
> It would just be good if there was a standard and universally recognizable way to
> do it.
>
> A standard abstract class for message-sending that you can subclass. With standard
> subclasses for std-out, std-err, std-in, file-out and file-in.
Have you looked at Tango's IO classes? I think Tango has that pretty much.
--bb
|
Copyright © 1999-2021 by the D Language Foundation