Forums before death by AOL, social media and spammers... "We can't have nice things"
|    comp.lang.c++.moderated    |    Moderated discussion of C++ superhackery    |    33,346 messages    |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
|    Message 32,836 of 33,346    |
|    fmatthew5876 to Francis Glassborow    |
|    Re: iostream replacement    |
|    28 Jan 13 15:10:25    |
   
   From: fmatthew5876@googlemail.com   
      
   On Sunday, January 27, 2013 11:43:30 PM UTC-5, Francis Glassborow wrote:   
   > 1) The << and >> operators have no meaning outside the context of the C   
   > family of languages. That is in marked contrast to mathematical   
   > operators (and I wish we had a way to provide new operator symbols so   
   > that expressions would look more familiar to domain specialists. Unicode   
   > has all the glyphs available and even has a page of mathematical   
   > symbols.) Even the logic operators, though sometimes using strange   
   > glyphs map to non-computing concepts. However bit shifting and other bit   
   > level operations are computer domain specific. That is why I have no   
   > problem with them having overloaded meanings that are completely   
   > different to the original ones. In addition (though this was not the   
   > primary reason for their choice) they are visually appropriate.   
   >   
      
   When I think of operators I think of their meaning for primitive types. I use C   
   as my model first and general math notation second. Sticking with the C meaning   
   removes all possible ambiguity. If I'm overloading an operator and its not   
   entirely obvious how my new type extrapolates a primitive type, I don't do it.   
      
   Overloading operator+() for strings is also somewhat suspect.   
      
   I also believe leveraging operator overloading for streams gives a bad example   
   for new programmers. Their first hello world program shows them how they can   
   use operator overloading to invent all kinds of new meanings for operators.   
      
   > Actually now that I reflect on it, << and >> have sometimes been used in   
   > mathematics to mean 'much greater than' and 'much less than' so using   
   > them for bit shifts is already a little suspect (to those who wish to   
   > confine operator overloading to a single overarching meaning)   
      
   Maybe so but in programming such notions as 'much greater than' are arbitrary   
   and have no meaning. This mathematical syntax is not often used either so I   
   don't take issue with << and >> being used for bit shift. Even if we don't   
   like the operator chosen by C, we should keep its meaning consistent.   
      
   >   
   >   
   >   
   > 2) I have never had a problem with providing different formats for user   
   > defined types depending on context. When writing overloads it is easy to   
   > distinguish between various types of I/O stream and change the output   
   > appropriately. For example I often want more detailed output to the   
   > screen than I do for a data file (think of complex numbers where pairs   
   > of values are fine in a data file but where many would want something   
   > more in a display.   
      
   I'm not sure I agree with the idea of changing the output format based on the   
   type of stream.   
      
   First there is no indication of what output format you're using.   
   Foo f;   
   ofstream fout;   
   cout << f;   
   fout << f;   
      
   This is far from self documenting code.   
      
   This approach also breaks on generic code. What if you want to do this?   
      
   void print_stuff(ostream& out) {   
    Foo f;   
    out << f;   
   }   
      
   int foo() {   
   if(/*something*/)   
   print_stuff(cout);   
   } else {   
   ofstream fout;   
   fout.open("some file");   
   print_stuff(fout);   
   }   
      
   One of the hallmark features of a good io library is that streams should have   
   a polymorphic interface, so that clients can just read and write to them   
   without having to know whether they are talking to the network or a file or   
   anything else.   
      
      
      
   > If you really need a great deal of variability in output/input and do   
   > not want to write your own manipulators (can be quite hard work, but   
   > once it is done it can be used forever) you can use inheritance and casting:   
   >   
   > class mytype{   
   > // what ever   
   > };   
   >   
   >   
   > class mytype_to_file: public mytype{}   
   >   
   >   
   > ostream & operator << (ostream &, mytype_to_file const &){   
   > // provide output formatted for file storage   
   > }   
   >   
   >   
   > void foo(){   
   > // create an object called mt   
   > cout << (mytype_to_file)mt;   
   > }   
   >   
   >   
   >   
   > Yes, ugly but it can be polished up considerably and the above is just   
   > an outline to show how taking a little time designing and implementing   
   > your i/o for a UDT can produce largely self documenting code.   
      
   Just be sure not to forget the cast. Otherwise your code silently breaks.   
      
      
   --   
    [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
    [ comp.lang.c++.moderated. First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
(c) 1994, bbs@darkrealms.ca