C# and Java benefit from running on just one (virtual) system.
They avoid the multiplicity of text file formats in the real
world by, well, avoiding the multiplicity of text file formats
in the real world. C and C++, by contrast, have faced the
problem head on for many years and have dealt with it pretty
successfully.
My response is this: Java and C# provide their portability at runtime. They
run on an abstraction layer which maps their data and I/O representations
to platform specific representations. Mathematica also does this kind of
thing. Bear in mind that Gosling was the first to port Emacs to C. That's
byte-compiled, garbage-collected, exception-throwing, pointerless (from the
user's perspective) library-loading, ELisp virtual machine, Emacs.
Two other noteworthy programmers got their start in XEmacs, which is a fork
of Emacs that tries to remain compatable. Marc Andreesen and Jamie
Zawinski. They were two of the most significant actors in the creation of
Netscape. Netscap uses a somewhat different approach to platform
abstraction than to CLI and the JVM. It's called the Netscape Portable
Runtime. It's kind of like Netcape/Mozilla has the virtual machine built
in to it. Look at the TOC and you should be able to understand it as an
outline of a collection of interfaces:
http://www.mozilla.org/projects/nspr/reference/html/index.html
Mozilla has many features similar to Emacs, such as the built-in
interpreter, the event loop, the multiple buffers, etc.
The C++ approach should be to provide the abstraction in the form of source
code that can be optionally compiled into the user's program to the minimal
extent it is useful.
Did so years ago. We've even implemented it and licensed it to
others. But don't get Pete Becker started on all the things wrong
with Java I/O, however, because he bore the brunt of the effort.
I never said it was perfect. And I am not speaking from the implementor's
perspective. I am talking about the ease of use, and relative uniformity
of interfaces.
Thanks for the advice, but I've been writing tutorial books (over
a dozen) and articles (about 350) for several decades now. I spend
a *lot* of time considering such matters.
I'm not sure if you can appreciate how inelegant C++'s I/O library looks
from my perspective. Don't get me wrong, there are nice parts of it too.
Nonetheless, it's difficult trying to remember the meaning of a couple
dozen cryptically named state flags, the counter intuitive functions to
read and modify their values, the half a dozen pointers into the input and
output buffers (eback is the front, mind you), which function such as
snextc() calls another function such as sbumpc(), and under what
conditions, what the difference between uflow() and underflow() is, etc.
That doesn't even address the couple dozen <cstdio> functions. It's hard
to know what function and flags are relevant to the current state. Which
function are redundant, which modifications to the stream state only apply
for the duration of one function call to the stream extractor or inserter,
how to save the state of the stream before you modify it, so that you can
recover it, etc.
All that lowlevel stuff is useful in some circumstances, but there is no
coherent interface for a person who wants to work with a file (in the Unix
sense). There should be file descriptor objects that provides information
about the file such as is typically found on any operating system. The
abstraction doesn't have to be part of a runtime virtual machine. It can
be a simple abstract base class or class template that is implemented for
each environment. I want to open the file and read it into whatever buffer
is best suited to my application. I shouldn't need to remember a whole
bunch of information, or pull out some esoteric function just because I
want raw data.
What's a binary stream? Well, it's kind of like a stream of text, except it
doesn't modify the data to suit the platform. Can I use it to read binary
data? Well, sort of, but there are a few caveats which you will probably
have to figure out through experimentation. What is the underlying data
representation? It depends.
So far, in the past 48 hours I've seen three examples of veteran programmers
not fully understanding basic notions associated with C++ I/O.
I can think of several ways of doing this, none of which are
particularly hard. Or hard to teach, at least to a student
with an open mind.
Where's my_binary_file.begin() and my_binary_file.end()?
What a coincidence. C is implemented in C, with just a little bit
of assembly language mixed in. And C++ is implemented in C and C++,
with just a little bit of assembly language mixed in. Coincidence?
I don't think so.
That's great, but I see no reason that C++ should fail to provide a higher
level of abstraction which presents the low level services it can
manipulate, in a coherent, minimal, yet complete interface.