On Wed, Mar 4, 2015 at 9:46 AM, Christian Gollwitzer <aurio...@gmx.de> wrote: > I can agree with the argument that operator precedence can make > problems; e.g. this > > cout<<a==b; > > does not output the truth value of a==b, but instead outputs a and > compares the stream to b (which will usually fail to compile, but still). > > But the argument that << is a left-shift and nothing else is silly. << > for bitshift is nothing more intuitive than % for modulus (where in math > does this symbol occur?) or [] for indexing. We just got used to it, and > to me << as an arrow for putting someting into a stream seems pretty > obvious.
I don't mind the idea of << meaning something other than left-shift. The problem comes usually when you try to use a binary operator in place of a variadic function, and suddenly you need a pile of hacks to get around operator overloading. If you use << to add a flag to a flag-set (where the "flag-set" might be an integer that retains bit-flags, or a set that retains strings, or whatever), that would make reasonable sense. You take one thing on the left, one thing on the right, and produce a result. (Or you'd use <<= for that, which still looks fine. Then it does an assignment instead of producing a result.) If you create a Path object that responds to binary division with a new Path that combines the left and right sides, that also makes very good sense. The slash means "next path component" rather than "divide", and it still is binary - there's no logical difference between these: Path("/etc") / "network" / "interfaces" (Path("/etc") / "network") / "interfaces" The problems come from needing more than two components at each step, like with string formatting. You could write it like this: "Hello, %s from %s!" % name % location but then it'd be really hard to track down errors - the modulo operator would have to handle the first percent sign and leave any others unchanged. Plus there'd need to be some weird and funky magic to mark the "current interpolation position" in order to cope with %% becoming %, and the possibility that the person's name contains a percent sign. No, string interpolation needs more than two arguments. So either you have to mandatorially package the args up into an iterable: "Hello, %s from %s!" % (name, location) which is very easy to forget (just look at what happens when you use the Python DB API 2.0 and use "cur.execute(sql, single_argument)" - you have to package that up into a one-tuple), or you have a special case for non-tuple arguments, which is what Python has done. This is great, except in the situation where you want to accept *any arbitrary object* as your argument, eg for %r; you have to package that one up, otherwise a tuple will behave very oddly. Hence, hacks on hacks to get around the limitations of binary operators. >> Operator overloading in each case here is "cute", not optimally practical. > > Maybe just sub-optimal? With today's C++ one could use a variadic > template and still have type-safe compile-time bound output formatting. > This hasn't been possible in the original iostream library back then. I'm not sure how that would work, but the main question is: How is it advantageous over a simple call? Actually, here's a simple way to do it: Make the stream object callable. cout("Hello, world!\n"); You can take as many args as you want, precedence and associativity won't bite you, and it still reads reasonably well. The operator method has to prove that it's better than that. ChrisA -- https://mail.python.org/mailman/listinfo/python-list