 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
psyko Guest
|
Posted: Tue Jun 06, 2006 4:26 am Post subject: Why do you deserve a better IO library |
|
|
Hi!
In this article I'll try to summarize the reasons that lead me to
dislike IOStream as
it is now, and to hanker for a better IO library for C++. The arguments
are presented are
of two kinds:
- Cosmetic Problems: has to do with bad names, bad conventions, ...
etc. Basically, these
can be solved without major rework.
- Design Problems: are the fundamental problems with the design of
IOStream. Solving
these may mean coming up with a whole new library.
The arguments are numbred for easy reference.
Cosmetic Problems:
^^^^^^^^^^^^^^^^^^
1- Very complicated (and overlapping) state access functions, all with
strange names: rdstate(),
clear(), setstate().
2- fail() tests for both eofbit (which is a rather expected cause of
failure) and failbit (which
less expected). inorder test for fail alone you have to come up with
rdstate()&failbit.
4- Input operations set eofbit _and_ failbit on EOF, which makes it
impossible to make stream
classes throw only when operation fails because of stream error, and
not because of EOF.
3- The use of implicit convertion to void* (or to bool) does more harm
than good. It is not
really clear what are we testing for in 'if(cin) { ... }'
4- Unformatted input functions handle exceptions specially (I hate
special cases)
5- Format flag manipulation is unnecessarily complicated by strange
names (and too much overlap
in functionality): setf(f), setf(f, m), unsetf(f), flags(), flags(f),
(even with
io manipulators) setiosflags(f), resetiosflags()
6- All these basic_ prefixes look bad. Why don't we simply have
template versions named
std::stream<T=char> whith a default template parameter set to char?
7- To say nothing about members of streambuf: putback, unget get,
eback, gptr, egptr, setp,
pbase, pptr, gbump, uflow, snextc, sbumpc, sgetc, sputc, sputn,
showmanyc,
pbackfail... etc
Design Problems:
^^^^^^^^^^^^^^^^
1- The simple fact of #including <iostream> incur some overhead on the
generated code. Can you
bear it?
2- std::cout is an instance of std::ostream, and std::ostreams have a
seekp() member that allows
to traverse the character sequence. But it is meaningless to seekp()
forward with
std::cout. So seekp() isn't defined for the standard output? Ok! then
either:
- std::cout shouldn't be an instance of std::ostream, or
- std::ostream shouldn't contain a seekp() member
Which lead (respectively) to tow questions:
- std::cout should be an instance of which class then?
- Then where to put seekp()?
3- Uppon failure, IOStream (partiularily file stream classes) throw
instances of ios_base::failure.
But this isn't much of help. If try to open a file and get an
ios_base::failure, what
can you do? You can't output the result of the what() member because
its content is
undefined and surley not in the "right" natural language. Indeed, you
have absolutly no
idea of _what_ happend: file_not_found? permission_access_error?
bad_filename?
system_error? disk_error? would have been more informative things to
throw. Providing
an error report in the form of a simple character string (in some
arbitrary language) is
simply not enough.
5- The use of virtual inheritance is not justified in my opinion. Did
anyone ever handled a
stream throught a basic_ios<>* pointer? Aggregation would have been a
better option.
4- streambuf is a kind of "super class" that has members for everything
(input, output, seek in
both directions ... etc), even though most of its instances can't
actually support all
the operations.
-5 streambuf is actually mixing two compleatly unrelated concepts: The
concept of a buffer for
IO, and the concept of an external source/sink of data, which makes
extending the
library to support new kind of stream unnecessarily difficult.
Epilogue:
^^^^^^^^^
Design problems are (of course) more important than cosmetic ones. And
I think the most important
problem is the fact that instances don't support all the operations
exported by classes. For
example, if I write a prototype like:
void encrypt(std::istream&, std::ostream&);
Can encrypt() seek the streams? Given that it is declared to take
std::streams and that std::streams
export seek members, the answer would nomrally be 'yes'. But suppose
another person looks at
the prototype and asks himself "Can I pass std::cout as a second
argument?", "Given
that std::cout is an std::ostream (as required by the prototype)....."
you get the idea. This
kind of problem shouldn't exist, otherwise why are we bothering with
classes and OO?
I'd be glad to hear you opinion.
P.S.: It would be nice if every one said with which points (as numbered
above) he agrees (in
addition to those with which he disagrees).
Yours,
Anis Benyelloul
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Wed Jun 07, 2006 2:54 am Post subject: Re: Why do you deserve a better IO library |
|
|
psyko wrote:
| Quote: | In this article I'll try to summarize the reasons that lead me
to dislike IOStream as it is now, and to hanker for a better
IO library for C++. The arguments are presented are of two
kinds:
- Cosmetic Problems: has to do with bad names, bad conventions, ...
etc. Basically, these
can be solved without major rework.
- Design Problems: are the fundamental problems with the design of
IOStream. Solving
these may mean coming up with a whole new library.
|
IOStream's isn't without its problems, but it's a considerable
improvement (easier to use, more intuitive, much more flexible,
and much, much safer) over what we had in C. Realistically,
however, I doubt that there will be any significant changes in
it, for the simple reason that this sort of streamed IO has
pratically lost most relevance for most programs: human readable
IO is mostly via a GUI, and iostreams are not really the answer
to binary IO. If I look at any of my recent applications,
iostream's has been limited to log files (for which it is about
the only solution, but needs to be wrapped), and ostringstream,
to format various types. And getline for reading configuration
files (which are then parsed by a number of different parsing
tools, including occasional use of istringstream to convert
individual values into the correct types).
| Quote: | The arguments are numbred for easy reference.
|
It's probably worth noting that a number of your points (not all
of them) reflect more your misunderstanding than any defect
(except maybe lack of good documentation) in iostream itself.
The naming conventions in iostream aren't always ideal -- in the
case of the streambuf interface, they are frankly horrible --
but that's no excuse for not reading the documentation.
| Quote: | Cosmetic Problems:
^^^^^^^^^^^^^^^^^^
1- Very complicated (and overlapping) state access functions,
all with strange names: rdstate(), clear(), setstate().
|
Historical reasons, of course. At least partially -- why the
committee didn't adopt some sort of coherent naming convention
for the functions it added is beyond me.
| Quote: | 2- fail() tests for both eofbit (which is a rather expected
cause of failure) and failbit (which less expected). inorder
test for fail alone you have to come up with
rdstate()&failbit.
|
That's simply false. fail() is one of the rare well-named
functions; it returns true if and only if a previous IO attempt
failed. It does NOT return true if only eofbit is set (but you
almost never want to test eofbit). Failbit is a bit of a
misnomer, in that it doesn't cover all cases of failure --
failure is either failbit or badbit. But it's not a real
problem, because you practically never use the names for the
actual bits (unless you are writing a >> or a << operator which
uses the streambuf directly, in which case, you have to set the
correct bits in case of error).
The real problem is in the other direction: unlike fail, good()
does take eofbit into consideration, which means that it is
practically unusable. Worse, it is NOT the opposite of fail()
or of bad(), as the name might suggest. In practice, of course,
you almost never call either of these two.
Still, I would agree that the error handling needs some cleaning
up. At an even deeper level; there is a fundamental problem in
that the streambuf interface doesn't provide for different types
of returns: end of file, error, etc. In practice, today, this
is easy to work around -- an error in the streambuf triggers an
exception, and an exception causes badbit to be set. It would
also be nice if there were separate fail bits for failure due to
eof, and failure due to a format error -- as it stands, there
are certain ambiguous cases where you cannot distinguish between
the two.
| Quote: | 4- Input operations set eofbit _and_ failbit on EOF, which
makes it impossible to make stream classes throw only when
operation fails because of stream error, and not because of
EOF.
|
In practice, I can't think of a reasonable case where you'd want
an exception in case of fail. About the only case where I would
find exceptions reasonable is when badbit is set. (Note that
the failbit is only set in the case of "expected" failure: end
of file, or an illegal format in a text file. Any real IO
errors should cause badbit to be set. Because the streambuf
interface doesn't provide any immediate way of distinguishing
between an IO error and end of file, however, and the fact that
exceptions are a relatively new feature -- newer that iostream,
at any rate -- filebuf in a lot of implementations will still
never throw an exception. So badbit will never be set on input,
and you have absolutely no way what so ever of distinguishing
between a real end of file, and a read error on the disk.)
| Quote: | 3- The use of implicit convertion to void* (or to bool) does
more harm than good. It is not really clear what are we
testing for in 'if(cin) { ... }'
|
You're testing whether all of the previous input or output
succeeded or not. I agree that requiring separation between the
actual IO and the test for success would probably result in
cleaner code, but there seems to be a lot of resistence to the
extra verbiage. So while I would prefer that the standard idiom
be something like:
std::cin >> someInt ;
if ( cin.succeeded() ) { ... }
most people seem to prefer to put it all in the if.
| Quote: | 4- Unformatted input functions handle exceptions specially (I
hate special cases)
|
Explain? I'm not aware of the slightest difference between
unformatted and formatted functions with regards to error
handling and exceptions.
| Quote: | 5- Format flag manipulation is unnecessarily complicated by
strange names (and too much overlap in functionality):
setf(f), setf(f, m), unsetf(f), flags(), flags(f), (even with
io manipulators) setiosflags(f), resetiosflags()
|
The format flags are designed to be basic tools; you don't
typically use any of the standard manipulators (except maybe
std::setw, or in quicky test programs); you use custom,
application specific manipulators. Manipulators are text
markup, and anyone having to deal with text formatting knows
that logical markup is to be preferred by far to physical
markup. (If you're writing a web page, you don't use
<i>...</i>, do you?)
As for the overlap, it is more or less natural, as different
sets of functions address different use cases: setf(f)/unsetf(f)
for specific boolean flags, setf(f,m) for larger fields, and
flags for saving and restoring the state. On the whole, it
makes the class easier to use.
| Quote: | 6- All these basic_ prefixes look bad. Why don't we simply
have template versions named
std::stream<T=char> whith a default template parameter set to char?
|
Historical reasons. I think it's pretty clear now that
templating the iostream stuff was a bad idea. (But your
solution means that there would be no simple name for wistream,
etc.)
| Quote: | 7- To say nothing about members of streambuf: putback, unget
get, eback, gptr, egptr, setp, pbase, pptr, gbump, uflow,
snextc, sbumpc, sgetc, sputc, sputn, showmanyc, pbackfail...
etc
|
The function names in streambuf *are* pretty awful.
| Quote: | Design Problems:
^^^^^^^^^^^^^^^^
1- The simple fact of #including <iostream> incur some
overhead on the generated code. Can you bear it?
|
On the generated code? What? All <iostream> should contain is
a couple of forward declarations and some extern's.
| Quote: | 2- std::cout is an instance of std::ostream, and std::ostreams
have a seekp() member that allows to traverse the character
sequence. But it is meaningless to seekp() forward with
std::cout.
|
That pretty much depends on what cout is connected to, doesn't
it? And of course, you don't know that until runtime.
| Quote: | So seekp() isn't defined for the standard output? Ok! then
either:
- std::cout shouldn't be an instance of std::ostream, or
- std::ostream shouldn't contain a seekp() member
Which lead (respectively) to tow questions:
- std::cout should be an instance of which class then?
- Then where to put seekp()?
|
In general, supporting seek in a class named stream is a hack,
present for historical reasons. Once you accept that seek is
supported, however, you have to accept the fact that it may
fail, because you don't know what actual device your input or
output is connected to.
A worse problem is the fact is the different definition of seek
depending on whether the file is text or binary. Again,
necessary for historical reasons.
| Quote: | 3- Uppon failure, IOStream (partiularily file stream classes)
throw instances of ios_base::failure.
|
Since when? I've never seen an exception from iostreams. Ever.
| Quote: | But this isn't much of help. If try to open a file and
get an ios_base::failure, what can you do? You can't output
the result of the what() member because its content is
undefined and surley not in the "right" natural language.
Indeed, you have absolutly no idea of _what_ happend:
file_not_found? permission_access_error? bad_filename?
system_error? disk_error? would have been more informative
things to throw. Providing an error report in the form of a
simple character string (in some arbitrary language) is simply
not enough.
|
Propose an alternative. That can be implemented on all possible
systems.
I think this is the crux of the problem here. IOstreams error
reporting stinks; there's no doubt about it. But what can you
require, portably?
| Quote: | 5- The use of virtual inheritance is not justified in my
opinion. Did anyone ever handled a stream throught a
basic_ios<>* pointer? Aggregation would have been a better
option.
|
Sorry, the virtual inheritance is both necessary and natural
here. And I'd phrase the question differently: have you ever
seen an application that didn't have some code which manipulated
ios*'s? At the very least, you need it in you IOSave class, or
whatever you call it; it also typically occurs in some of your
manipulators.
| Quote: | 4- streambuf is a kind of "super class" that has members for
everything (input, output, seek in both directions ... etc),
even though most of its instances can't actually support all
the operations.
|
Agreed. It probably would have been better if there had been
several different interfaces, with mixin's used to create the
concrete instances. Of course, that would have meant a lot of
multiple inheritance. (But see my comments on the next
question.)
| Quote: | -5 streambuf is actually mixing two compleatly unrelated
concepts: The concept of a buffer for IO, and the concept of
an external source/sink of data, which makes extending the
library to support new kind of stream unnecessarily difficult.
|
Three, not two: the standard filebuf also handles code
conversion. And you're right, it's conceptually wrong.
It's important, however, to put at least one thing in context.
If I were designing streambuf today, for today's machines, it
wouldn't have buffering implicit in the base class, and filebuf
wouldn't have code conversion. Rather, both would be handled,
as necessary by filtering streambufs. I frequently chain four
or five filtering unbuffered streambufs, despite the fact that
this means four or five virtual function calls for every
character extracted or inserted into the buffer. Without
performance problems. On today's machines -- on the machines I
used 15 or 20 years ago, I think I'd have definitely seen the
slow down. One of the design requirements in the early days was
that reading or writing a single character must be a simple,
inlinable function. Which imposes buffering in the base class,
whether you need it or not.
| Quote: | Epilogue:
^^^^^^^^^
Design problems are (of course) more important than cosmetic
ones. And I think the most important problem is the fact that
instances don't support all the operations exported by
classes.
|
That is, I fear, inevitable. How can it be otherwise if the
support for the operation depends on user input. If I specify
"/dev/tty" as a filename, for example, seek doesn't work. But
there's absolutely no way to know at compile time whether I will
specify this filename or not.
| Quote: | For example, if I write a prototype like:
void encrypt(std::istream&, std::ostream&);
Can encrypt() seek the streams?
|
Can it even write binary data to the ostream? There's
certainly more justification for separate stream types for
binary and text data than for seekable/non-seekable. AND... the
program generally can know whether the file should be opened in
binary or not.
If you want to extract all of these features into the
inheritance tree, however, you're going to end up with something
extremely complex. And that still requires some form of
run-time checking -- even if you change the encrypt interface to
take the names of files, and it is responsible for opening them
(in order to ensure that the output file is binary, for
example), it will still have to check dynamically whether
seeking works or not, because this depends on the filename I
give.
| Quote: | Given that it is declared to take std::streams and that
std::streams export seek members, the answer would nomrally be
'yes'. But suppose another person looks at the prototype and
asks himself "Can I pass std::cout as a second argument?",
"Given that std::cout is an std::ostream (as required by the
prototype)....." you get the idea. This kind of problem
shouldn't exist, otherwise why are we bothering with classes
and OO?
|
You've effectively raised a complicated issue here. One that
has no simple solution. With your prototype above, you'll have
to document a lot of restrictions concerning the output file, at
least -- e.g. it must be opened in binary mode if it is a
filebuf.
Right off the bat, I'd say that one thing is essential: the
ability to ask a file whether it is in binary mode or not. (But
this only makes sense for filebuf -- stringbuf, etc., don't have
this distinction.) Ideally, we should be able to change this on
the fly, but it's not possible under some OS's (e.g. IBM
mainframes, etc.).
| Quote: | I'd be glad to hear you opinion.
|
I think you're approaching the problem backwards. I think that
there is a serious problem with iostream, in that it tries to be
something for everyone. I think we've reached a point with
regards to IO that one size doesn't fit all, and I seriously
doubt that we can design a single class which will handle
network protocols, data base accesses, GUI displays and
keybords, and simple input and output streams, and still be
simple and conceptually elegant. I think, too, that there is a
serious lack of any requirements specification concerning what
is wanted in a replacement (or the replacements). IMHO, the
<iostream.h> by Jerry Schwarz did an exceptionally good job of
meeting its requirements specifications, such as they were
twenty years ago -- my only serious criticism of it, as it was
then, and for the requirements at that time, is the function
names in streambuf. Since then, handling for binary files on
systems where binary files and text files are different (or
where the text file representation isn't exactly conform with
the internal requirements of C++), and even more so, trying to
load internationalization, especially support for multiple code
sets, on its back, have not improved it. Trying to modify a
class to do something it wasn't initially designed for never
does.
I think that it is time to start thinking about a replacement.
As it stands, iostream is still, today, a pretty good solution
for mono-lingual streamed text input and output (what it was
designed for). But that's not all of our IO needs today, not by
far. But the place to start would be by defining the
requirements.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
James Dennett Guest
|
Posted: Fri Jun 09, 2006 9:10 am Post subject: Re: Why do you deserve a better IO library |
|
|
Alf P. Steinbach wrote:
| Quote: | * psyko:
I'd be glad to hear you opinion.
Yes, the templated iostreams are inefficient, complex, and whatever bad
word exists for a design it applies to them; they even include two-phase
initialization and modal operation as if the designer searched the
darkest most inaccessible places for bad things to throw in, and,
although that's part of the "complex", they lack separation of concerns,
especially basic binary i/o versus formatting and parsing.
|
The separation into streambufs (for basic, unformatted I/O)
and streams (for parsing)?
I have a great dislike of the naming of many streambuf members,
but they're there for times when we just want a transport layer
without formatting.
-- James
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Ivan Vecerina Guest
|
Posted: Sat Jun 10, 2006 3:12 am Post subject: Re: Why do you deserve a better IO library |
|
|
"James Dennett" <jdennett (AT) acm (DOT) org> wrote in message
news:kkWhg.102786$iU2.96680@fed1read01...
: Alf P. Steinbach wrote:
: > * psyko:
: >> I'd be glad to hear you opinion.
: >
: > Yes, the templated iostreams are inefficient, complex, and whatever
bad
: > word exists for a design it applies to them; they even include
two-phase
: > initialization and modal operation as if the designer searched the
: > darkest most inaccessible places for bad things to throw in, and,
: > although that's part of the "complex", they lack separation of
concerns,
: > especially basic binary i/o versus formatting and parsing.
:
: The separation into streambufs (for basic, unformatted I/O)
: and streams (for parsing)?
:
: I have a great dislike of the naming of many streambuf members,
: but they're there for times when we just want a transport layer
: without formatting.
But in fact, the streambuf (sub-)classes are IMO *unusable*
when binary i/o is needed:
- Absence of type discrimination between input-only,
output-only, and i/o instances.
- Absence of type discrimination between stream-only
or random access storage.
(in practice, I find 90% of my i/o code is stream-only,
when I access random-access disk storage I usually prefer
other techniques, such as memory-mapping).
- What do locales (streambuf::getloc/pubimbue) have
to do with binary i/o ?
- Inconsistent error handling: depending on the instance
or subclass being worked with, errors may be reported using
exceptions or using an eof return value. It is difficult
and expensive to write code that is correct in both cases.
I would much prefer to have distinct throwing
and non-throwing functions in the interface.
- Cryptic function names, complexity.
- Usually poor performance in most of the available
implementations.
As a result, if I am ever forced to use a streambuf instance
for binary i/o, I will definitely want to wrap it behind
a 'facade' class with a cleaner interface.
Cheers,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Roland Pibinger Guest
|
Posted: Sat Jun 10, 2006 4:37 am Post subject: Re: Why do you deserve a better IO library |
|
|
On 8 Jun 2006 19:17:35 -0400, "psyko" <anis.benyelloul (AT) gmail (DOT) com>
wrote:
| Quote: | kanze wrote:
this sort of streamed IO has pratically lost most relevance for
most programs: human readable IO is mostly via a GUI, and iostreams
are not really the answer to binary IO.
If I look at any of my recent applications, iostream's has been
limited to log files (for which it is about the only solution,
but needs to be wrapped), and ostringstream,
to format various types. ....
So you're implying that a general purpose IO library is not useful?
Or not worth the trouble? Personally I don't think so, even though
end-user UI is mostly graphical nowadays, many
developper/administrator/power_user tools (..etc) remain command
line based.
|
The problem is that a standardized library is essentially frozen. It
cannot be changed any more (without massive objection), at best
extended. What originally has been considered a good idea almost
inevitably becomes a 'legacy' over time. Moreover, people seemingly
prefer promising, innovative but unproven ideas for standardization
(iostreams, STL, auto_ptr, ...) which increases the probability of
failure.
IMO, the better alternative is not to standardize new libraries for
C++ but to provide (a) forum(s) for people interested in a certain
domain (e.g. IO) and let them create libraries and frameworks which
are discussed with potential users. The results may compete and
overlap (a plurality of approaches instead of one 'Standard') and may
change over time. Users pick what seems most suitable for them.
Best wishes,
Roland Pibinger
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
psyko Guest
|
Posted: Sat Jun 10, 2006 4:38 am Post subject: Re: Why do you deserve a better IO library |
|
|
| Quote: | Yes, the templated iostreams are inefficient, complex, and whatever bad
word exists for a design it applies to them;
|
So, on this point we agree. (except that you're going a bit far with
the
'whatever word exists for a bad design it applies', IOStream is bad but
not
evil).
| Quote: | The worst two symptoms of the totally failed design is that you cannot
write "cat" in standard C++ for Windows,
|
Why? What's the problem with:
#include <iostream>
int main(int, char**)
{
std::cout<< std::cin.rdbuf();
}
| Quote: | the standard iostreams have Undefined Behavior for input
(due to definition in terms of scanf-family),
|
Oops, still don't get it! could you explain?
| Quote: | plus the complexity means they're great to
write books about, and (apart from boost::lexical_cast) that's what
they're used for.
|
Are you joking here? Now what about std::coffee_machine which is
bad,
useless, and complicated enough to keep book witers busy for years!
(to say nothing about std::time_machine, std::cheese_burger, ... etc)
More seriously, I don't think the C++ standard is for book writers, it
is
for programmers, and if something isn't much of use to programmers it
shouldn't be.
| Quote: | Instead of new iostreams I'd like to see support added for defining
one's own alternatives.
[...]
a standardized way to associate basic types (including
possibly typedef'ed types such as size_t) with data necessary for i/o,
|
Do you mean changes in the language? can you elaborate?
Yours,
-- Anis Benyelloul
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Sat Jun 10, 2006 4:40 am Post subject: Re: Why do you deserve a better IO library |
|
|
James Dennett wrote:
| Quote: | Alf P. Steinbach wrote:
* psyko:
I'd be glad to hear you opinion.
Yes, the templated iostreams are inefficient, complex, and whatever
bad word exists for a design it applies to them; they even include
two-phase initialization and modal operation as if the designer
searched the darkest most inaccessible places for bad things to
throw in, and, although that's part of the "complex", they lack
separation of concerns, especially basic binary i/o versus
formatting and parsing.
The separation into streambufs (for basic, unformatted I/O) and
streams (for parsing)?
I have a great dislike of the naming of many streambuf members, but
they're there for times when we just want a transport layer without
formatting.
|
The naming of the streambuf members is a basic flaw -- in general, the
standard library seems to be very weak in this regard, but streambuf is
even worse than most.
For the rest: I've come to actually like iostream, at least compared to
any of the other systems I've used. The separation of formatting and
the transport layer is fundamental -- it's a powerful hook for
customizing. I don't really like the state hanging around between
requests, but I've yet to see any proposals which give anywhere near
the
same flexibility without such state.
Having gotten used to the extreme flexibility iostream's offer, I've
come to conclude that any streaming abstraction must offer the
following:
-- Separation of formatting and transport, with the possibility for
the
user to define his own transport mechanisms; it must also be
possible to chain the transport mechanisms to provide filtering.
-- Possibility for the user to define formatting for his own types.
-- Possibility for the user to define highlevel format specifiers, in
order to implement application specific logical mark up.
If the desire is to improve on isotream, the most critical weakness
I've
seen is in its error reporting. Confusing a disk read error with end
of
file (and many implementations still do this) just doesn't cut it.
Alf's right, too, to mention that inputting numerical values is
formally
undefined behavior, and that it shouldn't be. In practice, all of the
implementations I know do the right thing here, but there's no excuse
for not requiring it. The original posters suggestion of somehow
making
the information available in errno for FILE* available in the iostream
is a good idea too.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Alf P. Steinbach Guest
|
Posted: Sun Jun 11, 2006 12:37 am Post subject: Re: Why do you deserve a better IO library |
|
|
* psyko:
| Quote: | Yes, the templated iostreams are inefficient, complex, and whatever bad
word exists for a design it applies to them;
So, on this point we agree. (except that you're going a bit far with
the
'whatever word exists for a bad design it applies', IOStream is bad but
not
evil).
The worst two symptoms of the totally failed design is that you cannot
write "cat" in standard C++ for Windows,
Why? What's the problem with:
#include <iostream
int main(int, char**)
{
std::cout<< std::cin.rdbuf();
}
|
X:\> cl /nologo /GX /GR cat.cpp
cat.cpp
X:\> cat <cat.cpp
#include <iostream>
#include <ostream>
int main()
{
std::cout<< std::cin.rdbuf();
}
X:\> cat <cat.exe >poi.exe
X:\> dir | find ".exe"
10.06.2006 02:04 73 728 cat.exe
10.06.2006 02:04 4 378 poi.exe
X:\> _
The problem here is that C++ allows a translation of the data, which
translation logically belongs to a much higher formatting layer or
alternatively outside the program. Newline markers are translated, and
ASCII value 26 (control Z) is interpreted as end-of-stream. And that
makes the functionality unusable.
| Quote: | the standard iostreams have Undefined Behavior for input
(due to definition in terms of scanf-family),
Oops, still don't get it! could you explain?
|
As I wrote, because of the definition in terms of the scanf-family,
which for some cases has undefined behavior when input is not as
expected; that C library UB then bubbles up into the C++ library.
| Quote: | plus the complexity means they're great to
write books about, and (apart from boost::lexical_cast) that's what
they're used for.
Are you joking here?
|
Yes, but as Piet Hein remarked,
"Den som kun tar spøk for spøk og alvor kun alvorligt, han og hun har
faktisk fattet begge dele dårligt."
In English translation by Babelfish, uh, wait, it doesn't have
Norwegian, using InterTran instead (hopefully not written in C++?),
"Whoever barely grasping spøk for spøk and earnestness barely
earnest , he and she has actual comprehend both dårligt."
| Quote: | Instead of new iostreams I'd like to see support added for defining
one's own alternatives.
[...]
a standardized way to associate basic types (including
possibly typedef'ed types such as size_t) with data necessary for i/o,
Do you mean changes in the language? can you elaborate?
|
Language or library support, or both.
Although I'm not a fan of iostreams, I think implementing them provides
a good test case for whether the language & library is /complete/.
Regarding associations, think about portably writing a template function
template< typename T >
std::string printfSpecifier();
With one C++ compiler std::size_t may be typedef unsigned long size_t,
with another it might be that std::size_t isn't any of the built in types.
There is at least one portable solution, assuming that it's not
necessary to identify e.g. size_t as being size_t (i.e. that only the
characteristics are important), but it's ugly and possibly inefficient.
Regarding initialization, std::cout is ready-to-use at any time, even in
a constructor of a global object; you can not achieve that for your own
object. That functionality ties in with e.g. logger singletons. And
with the whole problem area of well-defined initialization order (or
rather, the lack of that) across translation units.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Valentin Samko Guest
|
Posted: Sun Jun 11, 2006 12:58 am Post subject: Re: Why do you deserve a better IO library |
|
|
Roland Pibinger wrote:
| Quote: | Moreover, people seemingly
prefer promising, innovative but unproven ideas for standardization
(iostreams, STL, auto_ptr, ...) which increases the probability of
failure.
|
Most libraries from TR1 have been around for quite a while, so I wouldn't call them
"unproven ideas". Also, many have used STL before the C++ standard came out, so there
was a lot of implementation and usage experience.
| Quote: | IMO, the better alternative is not to standardize new libraries for
C++ but to provide (a) forum(s) for people interested in a certain
domain (e.g. IO) and let them create libraries and frameworks which
are discussed with potential users. The results may compete and
overlap (a plurality of approaches instead of one 'Standard') and may
change over time. Users pick what seems most suitable for them.
|
Such "forums" already exist, one of them is called Boost.
--
Valentin Samko - http://www.valentinsamko.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Roland Pibinger Guest
|
Posted: Mon Jun 12, 2006 2:41 am Post subject: Re: Why do you deserve a better IO library |
|
|
On 10 Jun 2006 15:58:35 -0400, Valentin Samko
<c++.moderated (AT) digiways (DOT) com> wrote:
| Quote: | Roland Pibinger wrote:
Moreover, people seemingly
prefer promising, innovative but unproven ideas for standardization
(iostreams, STL, auto_ptr, ...) which increases the probability of
failure.
Most libraries from TR1 have been around for quite a while, so I wouldn't call them
"unproven ideas". Also, many have used STL before the C++ standard came out, so there
was a lot of implementation and usage experience.
|
IMO, it's the direct opposite. (To-be) standardized C++ libraries are
usually not exposed to a broader audience of real-world programmers.
Consequently the acceptance of C++ Standard libraries (that are good
in theory but not in practice) among those real-world programmers is
rather low.
| Quote: | IMO, the better alternative is not to standardize new libraries for
C++ but to provide (a) forum(s) for people interested in a certain
domain (e.g. IO) and let them create libraries and frameworks which
are discussed with potential users. The results may compete and
overlap (a plurality of approaches instead of one 'Standard') and may
change over time. Users pick what seems most suitable for them.
Such "forums" already exist, one of them is called Boost.
|
No, not Boost! Boost is focussed on experimental template programming
which is way too narrow for that purpose. I mean something between
'ordinary', unstructured open source programming (probably dozens of
libraries already exist for each domain) and a highly formalized
process like the JCP (Java Community Process).
Best regards,
Roland Pibinger
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
John Nagle Guest
|
Posted: Wed Jun 14, 2006 3:33 am Post subject: Re: Why do you deserve a better IO library |
|
|
Roland Pibinger wrote:
| Quote: | On 10 Jun 2006 15:58:35 -0400, Valentin Samko
c++.moderated (AT) digiways (DOT) com> wrote:
Roland Pibinger wrote:
Moreover, people seemingly
prefer promising, innovative but unproven ideas for standardization
(iostreams, STL, auto_ptr, ...) which increases the probability of
failure.
|
Actually, it might make sense to have formatting support for
strings, rather than focusing on formatting for streams.
Today, most human-readable output is being created for some element of a GUI,
not for a sequential file.
Yes, there's strstream, but it's not quite the right tool for the
job.
John Nagle
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Alf P. Steinbach Guest
|
Posted: Thu Jun 15, 2006 3:24 am Post subject: Re: Why do you deserve a better IO library |
|
|
* kanze:
| Quote: | Alf P. Steinbach wrote:
X:\> cat <cat.exe >poi.exe
X:\> dir | find ".exe"
10.06.2006 02:04 73 728 cat.exe
10.06.2006 02:04 4 378 poi.exe
X:\> _
The problem here is that C++ allows a translation of the data,
which translation logically belongs to a much higher
formatting layer or alternatively outside the program.
Newline markers are translated, and ASCII value 26 (control Z)
is interpreted as end-of-stream. And that makes the
functionality unusable.
The problem here is that one of the goals of C++ is that it can
be implemented on a wide variety of systems. And there are only
a very few systems in which a Unix like cat program is even
possible: although those few (Unix and Windows, in particular)
are fairly widespread, they are hardly representative, or
typical.
|
Sorry, that's not meaningful. (1) Doing The Right Thing would not
restrict C++ to fewer systems, as you imply. 2) Those systems where a
"cat" program is possible really do matter, contrary to what you imply.
| Quote: | (Another part of the problem is that Windows compilers cater to
a certain degree of backwards compatibility. And under CP/M,
you needed that EOF character, because files could not have an
arbirary length.)
|
Sorry, that's not meaningful. Think about it. How could the
possibility of copying data faithfully within the program, be
incompatible with CP/M?
| Quote: | With one C++ compiler std::size_t may be typedef unsigned long
size_t, with another it might be that std::size_t isn't any of
the built in types.
In standard C++, it's required to be one of the four basic,
unsigned integral types.
|
Is it? Then that requirement seems to be from the C-long-ago standard.
Could you please quote the relevant passage, since I don't have that?
Anyway, the problem exists for size_t regardless of the formal specs for
size_t, and it exists in general regardless of size_t.
[snip]
| Quote: | Regarding initialization, std::cout is ready-to-use at any
time, even in a constructor of a global object; you can not
achieve that for your own object.
Sure you can.
|
Show me, please.
| Quote: | Or at least, you can give the same guarantees
that cout gives (which are less than many people think). How do
you think the library authors implement cout?
|
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Alf P. Steinbach Guest
|
Posted: Thu Jun 15, 2006 3:30 am Post subject: Re: Why do you deserve a better IO library |
|
|
* kanze:
| Quote: | Alf P. Steinbach wrote:
as mentioned, you cannot implement "cat" for Windows using only
standard C++ functionality. That's because you cannot access
the underlying binary i/o functionality of the standard input
and output streams: you can only access an interface that's on
top of a modal translation engine where the mode cannot be
changed (all three aspects are horrible! and are not things
that occur naturally, they must be intentionally designed in).
But that's something we inherited from C, and that we won't be
able to change as long as our IO is defined in terms of and by
reference to the C standard.
|
Currently there's no assumption of e.g. std::cout being based on stdout.
The problem is that that infernal translation, or rather, the
/possibility/ of such translation occurring, has been misguidedly
designed in for C++ i/o, in the same way as in the C streams.
The only positive effect is to make it "easy" for a C++ implementor to
reuse the C library's translation, and for that we pay the price of
totally crippled i/o functionality (so that it's often not used anyway).
[snip]
| Quote: | I think you're missing the point that the distinction
binary/text is based on a distinction of actual file types in
many systems. This means that there really isn't anyway to
handle it otherwise.
|
Sorry, James, that's incorrect.
There are systems for which stream i/o isn't possible, but that doesn't
stop us from having it in the standard. There are /conceivably/ systems
where binary i/o isn't possible, but hey, it's in the standard anyway.
There's no system where static type checking can guarantee that you're
using only allowable operations for the right kind of file: that's a
run-time thing, always with the possibility of run-time failure, and it
provides an abundance of options of how to handle it, very otherwise.
Just to show how silly that "can't be done otherwise because of system
XYZ" really is, consider systems with only fixed size record files.
Can't have anything else than fixed size record i/o in the C++ standard
library, because really, it can't be handled otherwise. Hello.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Roland Pibinger Guest
|
Posted: Thu Jun 15, 2006 3:35 am Post subject: Re: Why do you deserve a better IO library |
|
|
On 14 Jun 2006 06:19:30 -0400, Valentin Samko
<c++.moderated (AT) digiways (DOT) com> wrote:
| Quote: | Roland Pibinger wrote:
No, not Boost! Boost is focussed on experimental template programming
which is way too narrow for that purpose.
Have you looked at Boost recently?
Since when are shared pointer, filesystem, date_time, pointer_container, random, range,
string algorithms, threads, ... are "experimental template programming" ?
|
Some of those libraries are conceptually experimental. All have
heavily templated interfaces which significantly narrows their
usability for real-world programmers.
Best regards,
Roland Pibinger
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Roland Pibinger Guest
|
Posted: Thu Jun 15, 2006 3:37 am Post subject: Re: C++ forum, Was: Re: Why do you deserve a better IO libra |
|
|
On 14 Jun 2006 06:20:15 -0400, "Andrei Polushin" <polushin (AT) gmail (DOT) com>
wrote:
| Quote: | Probably, you mean there should be a project which supports developing
and publishing of competing C++ projects. Such project might be focused
on the things like
* domain-wide interfaces,
* unified code conventions,
* unified build system,
* unified test framework,
* unified documentation system,
* unified concurrent release management rules,
* etc. -
thus covering the areas where the C++ community is rather weak, because
they are not directly related to the language itself.
|
Something like the repoitories that scripting languages create around
their language. I'm not sure whether all your 'unified' ideas are
actually desirable. The libraries, components, frameworks ... should
largely be independent of each other.
Best wishes,
Roland Pibinger
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|