digitalmars.D - overloading operators for I/O
- Walter Bright (46/54) Feb 14 2007 because that
- Michiel (24/35) Feb 14 2007 + is intuitively addition because it's been that way in mathematics long...
- Manfred Nowak (6/7) Feb 14 2007 This is as true as "[", "(" and "{" are arrows.
-
Walter Bright
(3/12)
Feb 14 2007
I didn't expect to convince you
. - Michiel (8/10) Feb 14 2007 It would just be good if there was a standard and universally recognizab...
- Bill Baxter (4/11) Feb 14 2007 Have you looked at Tango's IO classes? I think Tango has that pretty
- Derek Parnell (9/13) Feb 14 2007 Moving away from the idea of *overloading* existing operators, is there ...
- Andrei Alexandrescu (See Website For Email) (4/12) Feb 14 2007 Imho the only serious reason for overloading << in C++ for I/O was the
- Manfred Nowak (15/21) Feb 14 2007 What one thinks depends on the education.
- Walter Bright (8/23) Feb 14 2007 Of course. I assume here a computer programming background, where the
- Manfred Nowak (12/15) Feb 14 2007 I do not understand with what you disagree.
- Michiel (7/9) Feb 14 2007 I would like that. Just some extra operators that you can use for your
- Manfred Nowak (8/15) Feb 14 2007 New operators are not intuitiv either, because one has to learn their
- Walter Bright (5/14) Feb 14 2007 The problem with using unicode operators is that unicode isn't as well
- Manfred Nowak (9/13) Feb 14 2007 The degree sign does not require unicode; it is in the normal ISO/IEC
- Derek Parnell (10/27) Feb 14 2007 The editors I use all trap keystrokes and none of them allow 'raw' alt-x...
- Walter Bright (3/5) Feb 14 2007 All characters above 0x7F require unicode multibyte encodings. The
- Manfred Nowak (4/6) Feb 14 2007 This invalidates the proposed character only, which is of minor
- Walter Bright (2/9) Feb 14 2007 There isn't much left below 0x7F :-(
- Chad J (14/27) Feb 14 2007 Hmmmm, abstract algebra...
- Walter Bright (2/13) Feb 14 2007 Yes.
- Bill Baxter (16/30) Feb 14 2007 You mean yes on both counts?
- Andrei Alexandrescu (See Website For Email) (4/37) Feb 14 2007 Cecil too. Didn't have a problem with it.
- Manfred Nowak (9/13) Feb 15 2007 Then this seems to be the way to go, thanks Chad.
- Manfred Nowak (6/9) Feb 15 2007 Addendum:
- Lars Ivar Igesund (7/27) Feb 15 2007 Very good example of exactly why that would be a problem :)
- Manfred Nowak (3/4) Feb 15 2007 Thx. I simply should have edited a .d-file to avoid this stupid error.
-
Daniel Giddings
(5/8)
Feb 14 2007
Won't that treat the >> in b
> as the shift right operator and fail - Alexander Panek (10/16) Feb 14 2007 I can just fully agree with you, though, I slightly like Tango's Cout
-
Hasan Aljudy
(8/90)
Feb 14 2007
That's because you're a nerd, Walter
- Walter Bright (3/17) Feb 14 2007 Every other "C like" language uses << for shifting.
- Don Clugston (13/91) Feb 14 2007 I agree. There's another problem -- it really doesn't scale well. With
- Michiel (5/8) Feb 15 2007 But it has the added advantage that there is no need for run-time
- Bill Baxter (7/16) Feb 15 2007 I wonder how much difference that makes given that most IO tends to be
- Michiel (5/15) Feb 15 2007 Well, you're right of course. But strictly speaking it's still an
- Walter Bright (6/20) Feb 15 2007 C++ iostreams has the further "advantage" of being neither
- Andrei Alexandrescu (See Website For Email) (6/27) Feb 15 2007 It's a myth that iostreams benefit much the speed advantage of not
- James Dennett (15/44) Feb 17 2007 Hmmmmn, the only global state is the standard stream objects,
- renoX (19/22) Feb 15 2007 Agreed, and writef is even better:
- Frits van Bommel (10/13) Feb 15 2007 A syntax like this may be possible with string mixins. I'm pretty sure
- Andrei Alexandrescu (See Website For Email) (3/17) Feb 15 2007 Walter was talking about implementing this as an example :o).
- renoX (8/22) Feb 16 2007 I know, that's in my TODO list, but I wanted to do 'printable enums'
- nazo (14/14) Feb 15 2007 I didn't see all posts. but "stdout ~= tuple(a,b,c,d)" is best for
Michiel wrote:message toAnd 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 thethe destination. Should the operator only be used for shiftingbecause thathappens to have been its first purpose? I also like how you can send a message to an abstract object. Andthat can be acout, a cerr, an error console in a GUI, or something else. Samething the otherway 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 <<.
Feb 14 2007
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.
Feb 14 2007
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
Feb 14 2007
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>.
Feb 14 2007
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.
Feb 14 2007
Michiel wrote:Have you looked at Tango's IO classes? I think Tango has that pretty much. --bbThis 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.
Feb 14 2007
I had actually not. :) I'll look into that, thanks. I still think it deserves to be in the standard library, though.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.
Feb 14 2007
Michiel wrote:that's what Tango is trying to be, *the* standard library.I had actually not. :) I'll look into that, thanks. I still think it deserves to be in the standard library, though.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.
Feb 14 2007
On Wed, 14 Feb 2007 14:45:50 -0800, Walter Bright wrote:Michiel wrote:Moving away from the idea of *overloading* existing operators, is there any case for new operators that implement I/O? -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 15/02/2007 11:36:07 AMTo sum up: I love D. But I also like the streaming operator.I didn't expect to convince you <g>.
Feb 14 2007
Derek Parnell wrote:On Wed, 14 Feb 2007 14:45:50 -0800, Walter Bright wrote:Imho the only serious reason for overloading << in C++ for I/O was the lack of decent variadic functions. AndreiMichiel wrote:Moving away from the idea of *overloading* existing operators, is there any case for new operators that implement I/O?To sum up: I love D. But I also like the streaming operator.I didn't expect to convince you <g>.
Feb 14 2007
Walter Bright wroteYou 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
Feb 14 2007
Manfred Nowak wrote:Walter Bright wroteOf 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.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.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.
Feb 14 2007
Walter Bright wroteI 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.I do not understand with what you disagree. However, I agree with you, that the semantics of << in C++ distorts at least my thinking as much as 1- x in the semantics of lisp. I understand your wish to have fixed meanings for several operators. But I do not understand that D does not provide similar operators for free usage. "+", "-" and all the others with fixed meaning could be prefixed for example by the degree symbol "°+", "°-" and provided with the same priorities as their unprefixed counter parts. Thus enabling a possibly interwoven parallel expression hierarchy. -manfred
Feb 14 2007
But I do not understand that D does not provide similar operators for free usage.I would like that. Just some extra operators that you can use for your personalized types. I'm not sure if I like the prefix-idea, though. An operator should be intuitive (readable) and easy to use. A prefix pretty much removes that advantage, and I would rather use functions. (By the way, I think the operator-symbols should at least be on a standard keyboard.) But ->, <-, postfix !, !in, etc. would be good.
Feb 14 2007
Michiel wroteAn operator should be intuitive (readable) and easy to use. A prefix pretty much removes that advantage, and I would rather use functions. (By the way, I think the operator-symbols should at least be on a standard keyboard.) But ->, <-, postfix !, !in, etc. would be good.New operators are not intuitiv either, because one has to learn their priorities---or one will end up with fully parenthesed expressions. Whether a prefix or a postfix and what characters will be choosen are of minor importance. I referred to the degree sign, because it is on the german standard keyboard and reminds at the often used middle circle in abstract algebras. -manfred
Feb 14 2007
Manfred Nowak wrote:I understand your wish to have fixed meanings for several operators. But I do not understand that D does not provide similar operators for free usage. "+", "-" and all the others with fixed meaning could be prefixed for example by the degree symbol "°+", "°-" and provided with the same priorities as their unprefixed counter parts. Thus enabling a possibly interwoven parallel expression hierarchy.The problem with using unicode operators is that unicode isn't as well supported as it should be. It's one thing to support unicode in the language, it's another to require one to use a unicode capable text editor to edit source code.
Feb 14 2007
Walter Bright wroteThe problem with using unicode operators is that unicode isn't as well supported as it should be. It's one thing to support unicode in the language, it's another to require one to use a unicode capable text editor to edit source code.The degree sign does not require unicode; it is in the normal ISO/IEC 8859-1 or latin1 table. Every editor should be capable to display it. Every system should be able to enter it. The degree sign "°" is under windows reachable via <alt>0176. The masculine ordinal indicator "º" via <alt>0186. The currency sign "¤" via <alt>0164. So: there is no such problem. -manfred
Feb 14 2007
On Thu, 15 Feb 2007 01:53:47 +0000 (UTC), Manfred Nowak wrote:Walter Bright wroteLOL ... just because something *should* doesn't mean that it *will*.The problem with using unicode operators is that unicode isn't as well supported as it should be. It's one thing to support unicode in the language, it's another to require one to use a unicode capable text editor to edit source code.The degree sign does not require unicode; it is in the normal ISO/IEC 8859-1 or latin1 table. Every editor should be capable to display it. Every system should be able to enter it.The degree sign "°" is under windows reachable via <alt>0176. The masculine ordinal indicator "º" via <alt>0186. The currency sign "¤" via <alt>0164. So: there is no such problem.The editors I use all trap keystrokes and none of them allow 'raw' alt-xxx entry of characters. So: there is such a problem. <G> -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 15/02/2007 1:15:44 PM
Feb 14 2007
Manfred Nowak wrote:The degree sign does not require unicode; it is in the normal ISO/IEC 8859-1 or latin1 table.All characters above 0x7F require unicode multibyte encodings. The latin1 table is not an encoding subset of unicode.
Feb 14 2007
Walter Bright wroteAll characters above 0x7F require unicode multibyte encodings. The latin1 table is not an encoding subset of unicode.This invalidates the proposed character only, which is of minor importance. -manfred
Feb 14 2007
Manfred Nowak wrote:Walter Bright wroteThere isn't much left below 0x7F :-(All characters above 0x7F require unicode multibyte encodings. The latin1 table is not an encoding subset of unicode.This invalidates the proposed character only, which is of minor importance.
Feb 14 2007
Walter Bright wrote:Manfred Nowak wrote:Hmmmm, abstract algebra... would this be easily parsable? other objections? a = b (+) c; a = b (-) c; a = b (*) c; a = b (^) c; a = b (|) c; a = b ($) c; a = b (?) c; etc... That first one kinda reminds me of the everyone's favorite circle-with-plus-inside.Walter Bright wroteThere isn't much left below 0x7F :-(All characters above 0x7F require unicode multibyte encodings. The latin1 table is not an encoding subset of unicode.This invalidates the proposed character only, which is of minor importance.
Feb 14 2007
Chad J wrote:Hmmmm, abstract algebra... would this be easily parsable? other objections? a = b (+) c; a = b (-) c; a = b (*) c; a = b (^) c; a = b (|) c; a = b ($) c; a = b (?) c; etc...Yes.
Feb 14 2007
Walter Bright wrote:Chad J wrote:You mean yes on both counts? It's kind of a controversial thing, I know, but for some types there really are multiple ways to interpret basic operations. Matlab, for example, defines .* to mean element-wise multiplication and * to mean matrix multiplication. Both forms get plenty of use. (Same for exponentiation too -- .^ and ^ both exist). I don't really care either way, but there is at least one example of a widely used language, specifically for math, in which there are more than the standard set of operators. Also Ocaml or Haskell or one of those guys, I forget which, allows definition of new operators using any combination of characters used in the built-in operators. E.g. **+ or */* or +++ or +- can all be made into custom operators. I have to admit, /That/ one seems like a pretty bad idea to me. :-) --bbHmmmm, abstract algebra... would this be easily parsable? other objections? a = b (+) c; a = b (-) c; a = b (*) c; a = b (^) c; a = b (|) c; a = b ($) c; a = b (?) c; etc...Yes.
Feb 14 2007
Bill Baxter wrote:Walter Bright wrote:Cecil too. Didn't have a problem with it. http://compilers.iecc.com/comparch/article/96-12-127 AndreiChad J wrote:You mean yes on both counts? It's kind of a controversial thing, I know, but for some types there really are multiple ways to interpret basic operations. Matlab, for example, defines .* to mean element-wise multiplication and * to mean matrix multiplication. Both forms get plenty of use. (Same for exponentiation too -- .^ and ^ both exist). I don't really care either way, but there is at least one example of a widely used language, specifically for math, in which there are more than the standard set of operators. Also Ocaml or Haskell or one of those guys, I forget which, allows definition of new operators using any combination of characters used in the built-in operators. E.g. **+ or */* or +++ or +- can all be made into custom operators. I have to admit, /That/ one seems like a pretty bad idea to me. :-)Hmmmm, abstract algebra... would this be easily parsable? other objections? a = b (+) c; a = b (-) c; a = b (*) c; a = b (^) c; a = b (|) c; a = b ($) c; a = b (?) c; etc...Yes.
Feb 14 2007
Walter Bright wroteThen this seems to be the way to go, thanks Chad. And because we are at it: please provide the ability to abstract operators into families of operators by allowing an index. This might look like (+:0), (+:1), (+:2), ... where (+) is a shorthand for (+:0). Because of the overloading capabilities I do not see any other urgent need for this than to allow redundancy, but I might be wrong. -manfredwould this be easily parsable? other objections? a = b (+) c;Yes.
Feb 15 2007
Manfred Nowak wroteBecause of the overloading capabilities I do not see any other urgent need for this than to allow redundancy, but I might be wrong.Addendum: Bill has given the example of normal and dotwise matrix operations. Because these cannot be expressed by overloading, there is a need for indexing. -manfred
Feb 15 2007
Manfred Nowak wrote:Walter Bright wroteVery good example of exactly why that would be a problem :) -- Lars Ivar Igesund blog at http://larsivi.net DSource & #D: larsivi Dancing the TangoThe problem with using unicode operators is that unicode isn't as well supported as it should be. It's one thing to support unicode in the language, it's another to require one to use a unicode capable text editor to edit source code.The degree sign does not require unicode; it is in the normal ISO/IEC 8859-1 or latin1 table. Every editor should be capable to display it. Every system should be able to enter it. The degree sign "°" is under windows reachable via <alt>0176. The masculine ordinal indicator "º" via <alt>0186. The currency sign "¤" via <alt>0164. So: there is no such problem. -manfred
Feb 15 2007
Lars Ivar Igesund wroteVery good example of exactly why that would be a problem :)Thx. I simply should have edited a .d-file to avoid this stupid error. -manfred
Feb 15 2007
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 ;-)
Feb 14 2007
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
Feb 14 2007
That's because you're a nerd, Walter <g> I learned C++ I/O long long before I learned bit manipulation and bit shifting. In fact, I was kinda surprised when I learned that C uses << as a bit shifting operator.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.Same goes for using them as bit shifting, to say it scream bit shifting is not because it does, but because you are accustomed to it. Walter Bright wrote: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 <<.
Feb 14 2007
Hasan Aljudy wrote:That's because you're a nerd, Walter <g>Yup <g>.I learned C++ I/O long long before I learned bit manipulation and bit shifting. In fact, I was kinda surprised when I learned that C uses << as a bit shifting operator.Every other "C like" language uses << for shifting.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.Same goes for using them as bit shifting, to say it scream bit shifting is not because it does, but because you are accustomed to it.
Feb 14 2007
Walter Bright wrote: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.I agree. There's another problem -- it really doesn't scale well. With printf, you can do "%3.5f" to print a floating point number with a given precision. With <<, that same operation is really horrible. I'd like to see a couple more clarifications in the spec, wrt operator overloading: * If both opAddAssign and opAdd are provided, the compiler is permitted to replace expressions of the form a = a+b; with a+=b; (that is, a+=b _must_ mean a=a+b). And similarly for the other operators. It's just insanity to make a+=b mean anything other that a = a + b. Incidentally, this would make my 'operator overloading without temporaries' proposal a non-breaking change. And if a, b, etc. are non-trivialexpressions, 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 <<.
Feb 14 2007
Don Clugston wrote:I agree. There's another problem -- it really doesn't scale well. With printf, you can do "%3.5f" to print a floating point number with a given precision. With <<, that same operation is really horrible.But it has the added advantage that there is no need for run-time parsing of that string. C++ parses all << stuff at compile time. -- Michiel
Feb 15 2007
Michiel wrote:Don Clugston wrote:I wonder how much difference that makes given that most IO tends to be slow anyway. On a 1 GHz proc, with a disk that has 10msec seek time that means a hit to the disk can cost you ten million cycles, right? Spending a few cycles to parse a format string at runtime isn't going to kill you. --bbI agree. There's another problem -- it really doesn't scale well. With printf, you can do "%3.5f" to print a floating point number with a given precision. With <<, that same operation is really horrible.But it has the added advantage that there is no need for run-time parsing of that string. C++ parses all << stuff at compile time.
Feb 15 2007
Bill Baxter wrote:Well, you're right of course. But strictly speaking it's still an advantage. ;) -- MichielBut it has the added advantage that there is no need for run-time parsing of that string. C++ parses all << stuff at compile time.I wonder how much difference that makes given that most IO tends to be slow anyway. On a 1 GHz proc, with a disk that has 10msec seek time that means a hit to the disk can cost you ten million cycles, right? Spending a few cycles to parse a format string at runtime isn't going to kill you.
Feb 15 2007
Michiel wrote:Bill Baxter wrote:C++ iostreams has the further "advantage" of being neither exception-safe nor thread-safe (since it manipulates global state in order to do formatting). This is only excusable because iostreams was added to C++ years before exception handling was and before anyone knew anything about threaded programming.Well, you're right of course. But strictly speaking it's still an advantage. ;)But it has the added advantage that there is no need for run-time parsing of that string. C++ parses all << stuff at compile time.I wonder how much difference that makes given that most IO tends to be slow anyway. On a 1 GHz proc, with a disk that has 10msec seek time that means a hit to the disk can cost you ten million cycles, right? Spending a few cycles to parse a format string at runtime isn't going to kill you.
Feb 15 2007
Walter Bright wrote:Michiel wrote:It's a myth that iostreams benefit much the speed advantage of not needing to do type retrieval at runtime. They are marred by a convoluted design and the need to synchronize with C's stdio library. By the time you saved that penny, you've spent all of those pounds already. AndreiBill Baxter wrote:C++ iostreams has the further "advantage" of being neither exception-safe nor thread-safe (since it manipulates global state in order to do formatting). This is only excusable because iostreams was added to C++ years before exception handling was and before anyone knew anything about threaded programming.Well, you're right of course. But strictly speaking it's still an advantage. ;)But it has the added advantage that there is no need for run-time parsing of that string. C++ parses all << stuff at compile time.I wonder how much difference that makes given that most IO tends to be slow anyway. On a 1 GHz proc, with a disk that has 10msec seek time that means a hit to the disk can cost you ten million cycles, right? Spending a few cycles to parse a format string at runtime isn't going to kill you.
Feb 15 2007
Andrei Alexandrescu (See Website For Email) wrote:Walter Bright wrote:Hmmmmn, the only global state is the standard stream objects, and you don't have to use those. The use of globals is certainly a nightmare for thread-safety (though exception safety is less of an issue), but it's limited to this one set of global variables.Michiel wrote:Bill Baxter wrote:C++ iostreams has the further "advantage" of being neither exception-safe nor thread-safe (since it manipulates global state in order to do formatting).Well, you're right of course. But strictly speaking it's still an advantage. ;)But it has the added advantage that there is no need for run-time parsing of that string. C++ parses all << stuff at compile time.I wonder how much difference that makes given that most IO tends to be slow anyway. On a 1 GHz proc, with a disk that has 10msec seek time that means a hit to the disk can cost you ten million cycles, right? Spending a few cycles to parse a format string at runtime isn't going to kill you.I think current implementations aren't very good. And given how long we've had since IOStreams was first used, that's not an optimistic picture.This is only excusable because iostreams was added to C++ years before exception handling was and before anyone knew anything about threaded programming.It's a myth that iostreams benefit much the speed advantage of not needing to do type retrieval at runtime.They are marred by a convoluted design and the need to synchronize with C's stdio library.The latter is turned off with a function call, which does make a significant difference. The convoluted design is just unfortunate. IOStreams isn't useful for much serious work. Not for notational reasons though; the design is just lousy. -- James
Feb 17 2007
Don Clugston a écrit :I agree. There's another problem -- it(<<) really doesn't scale well. With printf, you can do "%3.5f" to print a floating point number with a given precision. With <<, that same operation is really horrible.Agreed, and writef is even better: writef("x is %d",vx," y is %g\n",vy); No need to put the format string on one side and variables on the other side.. It has still deficiencies: - a syntax 'a la Ruby' would permit to see better the resulting string: writef("x is %{vx}, y is %{vy}\n"); of course you could still specify the format if you want: writef("x is %08x{vx}\n"); - why writef doesn't call to_String on struct or on a type? I.e: typedef int foo; char[] toString(foo x) { return "foo"; } doesn't work as expected in a writef, same with a struct defining a toString function.. renoX
Feb 15 2007
renoX wrote:- a syntax 'a la Ruby' would permit to see better the resulting string: writef("x is %{vx}, y is %{vy}\n"); of course you could still specify the format if you want: writef("x is %08x{vx}\n");A syntax like this may be possible with string mixins. I'm pretty sure you could write that like this: --- mixin(write!("x is %{vx}, y is %{vy}\n")); --- and get away with it, given the proper 'write' template. It might not even be very difficult, it'd just need to find the %{} groups, parse them out and generate the proper call(s) to other functions. The backend could be writef, or Tango's Stdout.format or something custom-written.
Feb 15 2007
Frits van Bommel wrote:renoX wrote:Walter was talking about implementing this as an example :o). Andrei- a syntax 'a la Ruby' would permit to see better the resulting string: writef("x is %{vx}, y is %{vy}\n"); of course you could still specify the format if you want: writef("x is %08x{vx}\n");A syntax like this may be possible with string mixins. I'm pretty sure you could write that like this: --- mixin(write!("x is %{vx}, y is %{vy}\n")); --- and get away with it, given the proper 'write' template. It might not even be very difficult, it'd just need to find the %{} groups, parse them out and generate the proper call(s) to other functions. The backend could be writef, or Tango's Stdout.format or something custom-written.
Feb 15 2007
Frits van Bommel a écrit :renoX wrote:I know, that's in my TODO list, but I wanted to do 'printable enums' first and I had 'startup' problem (not being very familiar with template programming). Now that kevin bealer has provided 'reflexive enums', I want to refine the implementation (struct or not struct?), do the write stuff, then world domination. renoX- a syntax 'a la Ruby' would permit to see better the resulting string: writef("x is %{vx}, y is %{vy}\n"); of course you could still specify the format if you want: writef("x is %08x{vx}\n");A syntax like this may be possible with string mixins. I'm pretty sure you could write that like this: --- mixin(write!("x is %{vx}, y is %{vy}\n")); --- and get away with it, given the proper 'write' template. It might not even be very difficult, it'd just need to find the %{} groups, parse them out and generate the proper call(s) to other functions. The backend could be writef, or Tango's Stdout.format or something custom-written.
Feb 16 2007
I didn't see all posts. but "stdout ~= tuple(a,b,c,d)" is best for Output, I think. and need more short tuple syntax like a:b:c:d. Example: stdout ~= a:b:c:d; //call stdout.opCat(a,b,c,d) stdout ~= e:f; stdout ~= g:h; I have no idea for Input best solution without opPopAssign_r. Example: int a; char[] b; a:b = stdin.pop; //call stdin.opPopAssign_r!(typeof(a:b))(); //return type is typeof(a:b). //"decide template from return type" is needed. These ideas have problem for binary size :-( #Sorry for my poor English
Feb 15 2007