If you had to judge by today's
software engineering standards (if
there actually is any general
agreement on these), would C++'s
IOStreams still be considered
well-designed? (I wouldn't want to
improve my software design skills from
something that's generally considered
outdated.)
I would say NO, for several reasons:
Poor error handling
Error conditions should be reported with exceptions, not with operator void*
.
The "zombie object" anti-pattern is what causes bugs like these.
Poor separation between formatting and I/O
This makes stream objects unnecessary complex, as they have to contain extra state information for formatting, whether you need it or not.
It also increases the odds of writing bugs like:
using namespace std; // I'm lazy.
cout << hex << setw(8) << setfill('0') << x << endl;
// Oops! Forgot to set the stream back to decimal mode.
If instead, you wrote something like:
cout << pad(to_hex(x), 8, '0') << endl;
There would be no formatting-related state bits, and no problem.
Note that in "modern" languages like Java, C#, and Python, all objects have a toString
/ToString
/__str__
function that is called by the I/O routines. AFAIK, only C++ does it the other way around by using stringstream
as the standard way of converting to a string.
Poor support for i18n
Iostream-based output splits string literals into pieces.
cout << "My name is " << name << " and I am " << occupation << " from " << hometown << endl;
Format strings put whole sentences into string literals.
printf("My name is %s and I am %s from %s.\n", name, occupation, hometown);
The latter approach is easier to adapt to internationalization libraries like GNU gettext, because the use of whole sentences provides more context for the translators. If your string formatting routine supports re-ordering (like the POSIX $
printf parameters), then it also better handles differences in word order between languages.