
<iostream> is the only C++ header that extracts a cost simply by including it (in typical implementations). The usual implementation is for it to include a static object of type std::ios_base::Init which is responsible for initializing the 8 terminal streams (cin, cout, cerr, clog, wcin, wcout, wcerr, wclog). I've always thought it good programming practice to avoid including <iostream> if the translation unit didn't actually need one of these 8 terminal streams. For example if I needed to just get to istream and ostream to write my own I/O I would include <istream> and <ostream> but not <iostream> (the naming is very unfortunate). It has recently come to my attention that I could be overly sensitive to this issue and making a fuss about nothing. So I'm writing here for a reality check. Do boost programmers consider the use of <iostream> as a short cut to get to non-terminal-streams I/O a reasonable technique? Or do boost programmers feel that use of <iostream> should be reserved only when using one or more of cin, cout, cerr, clog, wcin, wcout, wcerr, wclog? I did a brief survey of boost 1.33.1 and found many "relaxed" uses of <iostream> under the boost/ directory (i.e. non test-case code). So in practice it does appear that using <iostream> as a shortcut is considered acceptable practice. However I wanted to highlight the point just in case people do view this as a bug that has simply snuck in under the radar to date. -Howard

Howard Hinnant wrote:
I did a brief survey of boost 1.33.1 and found many "relaxed" uses of <iostream> under the boost/ directory (i.e. non test-case code). So in practice it does appear that using <iostream> as a shortcut is considered acceptable practice.
FWIW - I totally agree with you. I don't why <iostream> would have to appear in non-test code. Robert Ramey

On Nov 18, 2006, at 10:20 AM, Howard Hinnant wrote:
I did a brief survey of boost 1.33.1 and found many "relaxed" uses of <iostream> under the boost/ directory (i.e. non test-case code). So in practice it does appear that using <iostream> as a shortcut is considered acceptable practice. However I wanted to highlight the point just in case people do view this as a bug that has simply snuck in under the radar to date.
IIRC, at one point we were supporting a platform that had <iostream> but not <istream> or <ostream>, so I got in the habit of using <iostream> despite its cost. That platform might not matter any more, and I'd support fixing Boost's headers to avoid including iostream.... just not for 1.34.0 :) Cheers, Doug

Douglas Gregor wrote:
On Nov 18, 2006, at 10:20 AM, Howard Hinnant wrote:
I did a brief survey of boost 1.33.1 and found many "relaxed" uses of <iostream> under the boost/ directory (i.e. non test-case code). So in practice it does appear that using <iostream> as a shortcut is considered acceptable practice. However I wanted to highlight the point just in case people do view this as a bug that has simply snuck in under the radar to date.
IIRC, at one point we were supporting a platform that had <iostream> but not <istream> or <ostream>, so I got in the habit of using <iostream> despite its cost. That platform might not matter any more, and I'd support fixing Boost's headers to avoid including iostream.... just not for 1.34.0 :)
I agree. I have a vague recollection the platform was GCC, although that was many years ago so I may be mistaken. Out of curiosity, I changed the uses of <iostream> in my local copy of the random library to use other std headers, and it still passes regression tests for GCC 3.3.4. --Beman

Beman Dawes wrote:
Douglas Gregor wrote:
On Nov 18, 2006, at 10:20 AM, Howard Hinnant wrote:
I did a brief survey of boost 1.33.1 and found many "relaxed" uses of <iostream> under the boost/ directory (i.e. non test-case code). So in practice it does appear that using <iostream> as a shortcut is considered acceptable practice. However I wanted to highlight the point just in case people do view this as a bug that has simply snuck in under the radar to date. IIRC, at one point we were supporting a platform that had <iostream> but not <istream> or <ostream>, so I got in the habit of using <iostream> despite its cost. That platform might not matter any more, and I'd support fixing Boost's headers to avoid including iostream.... just not for 1.34.0 :)
I agree. I have a vague recollection the platform was GCC, although that was many years ago so I may be mistaken.
Out of curiosity, I changed the uses of <iostream> in my local copy of the random library to use other std headers, and it still passes regression tests for GCC 3.3.4.
Same here. No more <iostream> in fusion. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Douglas Gregor wrote:
IIRC, at one point we were supporting a platform that had <iostream> but not <istream> or <ostream>, so I got in the habit of using <iostream> despite its cost. That platform might not matter any more, and I'd support fixing Boost's headers to avoid including iostream.... just not for 1.34.0 :)
gcc 2.95 Regards, m Send instant messages to your online friends http://au.messenger.yahoo.com

Howard Hinnant wrote:
It has recently come to my attention that I could be overly sensitive to this issue and making a fuss about nothing. So I'm writing here for a reality check. Do boost programmers consider the use of <iostream> as a short cut to get to non-terminal-streams I/O a reasonable technique? Or do boost programmers feel that use of <iostream> should be reserved only when using one or more of cin, cout, cerr, clog, wcin, wcout, wcerr, wclog?
I consider it wrong * to include <iostream> when the standard streams do not get used * to include <iostream> as a shortcut for including <istream> and <ostream> The latter isn't guaranteed to work, IIUC, since <iostream> could be written as #include <iosfwd> \n extern std::ostream cout; etc. That way, the free operator<<() functions from <ostream> do not get included and some output will start to look funny. Regards, m Send instant messages to your online friends http://au.messenger.yahoo.com

Howard Hinnant wrote:
It has recently come to my attention that I could be overly sensitive to this issue and making a fuss about nothing. So I'm writing here for a reality check. Do boost programmers consider the use of <iostream> as a short cut to get to non-terminal-streams I/O a reasonable technique? Or do boost programmers feel that use of <iostream> should be reserved only when using one or more of cin, cout, cerr, clog, wcin, wcout, wcerr, wclog?
I did a brief survey of boost 1.33.1 and found many "relaxed" uses of <iostream> under the boost/ directory (i.e. non test-case code). So in practice it does appear that using <iostream> as a shortcut is considered acceptable practice. However I wanted to highlight the point just in case people do view this as a bug that has simply snuck in under the radar to date.
Well it snuck under *my* radar I admit. I think the problem here is that it's tricky to ensure that you have all the necessary headers included: different implementations may or may not flag up an error depending which headers you've included, so including <iostream> is a sort of "belt-and-braces" approach. But in principle you are correct. As an aside, I've always wanted a sort of "conceptual" std lib implementation, that included in each header nothing except what absolutely has to be there. Just the declarations would do, so we could do compile-time tests against it to verify inclusion of the right headers: the only tricky bit is getting the compile time constants correct so that it can still compile meta code. Any volunteers? :-> John.

On Nov 20, 2006, at 7:48 AM, John Maddock wrote:
As an aside, I've always wanted a sort of "conceptual" std lib implementation, that included in each header nothing except what absolutely has to be there. Just the declarations would do, so we could do compile-time tests against it to verify inclusion of the right headers: the only tricky bit is getting the compile time constants correct so that it can still compile meta code. Any volunteers? :->
One of the problems with this project is deciding exactly what should appear in the headers. For example, imho, this is a valid C++ program: #include <iostream> int main() { std::cout << "Hello World\n"; } In order for that to be valid, <iostream> must declare and define the namepace scope: template<class traits> basic_ostream<char, traits>& operator<< (basic_ostream<char, traits>& out, const char* s); which lives in <ostream>. In other words, I think it would be incorrect for <iostream> *not* to include <istream> and <ostream>. I have heard people argue that HelloWorld should include <ostream> explicitly as well. But imho that leads to a C++ language spec that is just too difficult and cumbersome to use (and we're already at risk for that reputation). So to catch this particular bug (mistaken uses of <iostream>) we would need a tool that looked for std::ios_base::Init constructors in the translation unit, but no uses of one of the eight terminal streams. Outside of a grep-like tool operating on the preprocessed translation unit (as an extra compilation phase), I'm not sure how to catch that with a std::lib implementation or prototype. Seems like something the compiler could do no problem though. :-) -Howard

Howard Hinnant wrote:
On Nov 20, 2006, at 7:48 AM, John Maddock wrote:
As an aside, I've always wanted a sort of "conceptual" std lib implementation, that included in each header nothing except what absolutely has to be there. Just the declarations would do, so we could do compile-time tests against it to verify inclusion of the right headers: the only tricky bit is getting the compile time constants correct so that it can still compile meta code. Any volunteers? :->
One of the problems with this project is deciding exactly what should appear in the headers. For example, imho, this is a valid C++ program:
#include <iostream>
int main() { std::cout << "Hello World\n"; }
In order for that to be valid, <iostream> must declare and define the namepace scope:
template<class traits> basic_ostream<char, traits>& operator<< (basic_ostream<char, traits>& out, const char* s);
which lives in <ostream>. In other words, I think it would be incorrect for <iostream> *not* to include <istream> and <ostream>.
But the standard doesn't say so explicitly. So how do we know? Section 27.3 just says that "The header <iostream> declares objects that...". It doesn't say that any types or operators are defined.
I have heard people argue that HelloWorld should include <ostream> explicitly as well. But imho that leads to a C++ language spec that is just too difficult and cumbersome to use (and we're already at risk for that reputation).
It *is* possible to just include <iosfwd> to be able to declare (not define) the extern stream objects. Isn't that what <iosfwd> was designed for? Bo Persson

On Nov 20, 2006, at 7:48 AM, John Maddock wrote:
I think the problem here is that it's tricky to ensure that you have all the necessary headers included: different implementations may or may not flag up an error depending which headers you've included, so including <iostream> is a sort of "belt-and-braces" approach.
The local fix for this is to write a library's cpp file that get compiled into the library.h, whose first line is #include "filename.h". This ensures that all the right headers get pulled in properly. In fact, the standard practice is to always include the headers in *reverse* order of dependency. The same works for the test driver: there is one test file dedicated simply to make sure that #include "filename.h" works without including anything else. It's a bit of a discipline and one must make sure that all code template has been instantiated, so it (like anything else) is not foolproof. You also need a notion of physical dependency and hierarchy levels. For this, I refer to John Lakos' book (whose second edition is in the writing).
As an aside, I've always wanted a sort of "conceptual" std lib implementation, that included in each header nothing except what absolutely has to be there. Just the declarations would do, so we could do compile-time tests against it to verify inclusion of the right headers: the only tricky bit is getting the compile time constants correct so that it can still compile meta code. Any volunteers? :->
John: I'm not sure I understand the only tricky bit. Can you pls elaborate? -- Hervé Brönnimann hervebronnimann@mac.com

Hervé Brönnimann wrote:
On Nov 20, 2006, at 7:48 AM, John Maddock wrote:
I think the problem here is that it's tricky to ensure that you have all the necessary headers included: different implementations may or may not flag up an error depending which headers you've included, so including <iostream> is a sort of "belt-and-braces" approach.
The local fix for this is to write a library's cpp file that get compiled into the library.h, whose first line is #include "filename.h". This ensures that all the right headers get pulled in properly. In fact, the standard practice is to always include the headers in *reverse* order of dependency. The same works for the test driver: there is one test file dedicated simply to make sure that #include "filename.h" works without including anything else. It's a bit of a discipline and one must make sure that all code template has been instantiated, so it (like anything else) is not foolproof. You also need a notion of physical dependency and hierarchy levels. For this, I refer to John Lakos' book (whose second edition is in the writing).
Absolutely, but that still only ensures that filename.hpp compiles cleanly with your specific compiler / std lib combination: many std lib's will pull in code that isn't actually needed according to the std. For example does this compile: #include <stdexcept> std::domain_error d("abc"); You may think "yes" because domain_error is defined in the header included, however the constructor relies on std::string being fully defined, but <stdexcept> need only forward declare std::string to make itself work. There is one lib (STLPort) that actually does it this way too: the rationale, is that you can do things like: #include <stdexcept> void print_message(const char*); int foo() { try{ //something }catch(const std::domain_error& e) { print_message(e.what()); } } without requiring all of <string>. In practice though most other std lib's do include <string> implicitly when you include <stdexcept>. As far as I know there is no concensus on the committee on whether this should work or not. Frankly, it's one of those bicycle-shed discussion items :-( It's also why as things stand, if you want to know whether you have included all the necessary headers you either have to: 1) Test as you indicated above, then fix if it fails on platform X. 2) Do a manual ordit of the code.
As an aside, I've always wanted a sort of "conceptual" std lib implementation, that included in each header nothing except what absolutely has to be there. Just the declarations would do, so we could do compile-time tests against it to verify inclusion of the right headers: the only tricky bit is getting the compile time constants correct so that it can still compile meta code. Any volunteers? :->
John: I'm not sure I understand the only tricky bit. Can you pls elaborate?
Let's suppose that we did write a minimal std lib that included in each header only those things that the header absolutely guarentees. Most of the headers would just contain declarations more or less cut and pasted from the std. There are a few areas though where we would need to define real definitions: std::numeric_limits<long double>::digits would have to have the right value for the platform the lib was used on, or else compile-time decisions based on the value would do the wrong thing. This extends to all the limits macros etc as well. I guess it's probably trivial-ish with a ./configure step, but we tend not to require that around here :-( John.

John Maddock wrote:
<stdexcept> need only forward declare std::string to make itself work. There is one lib (STLPort) that actually does it this way too: [...]
The Rogue Wave library also does it this way. At least rw libstd v2.2 (which is the default library on HP-UX/ia64) and higher. Boris ----- Original Message ----- From: "John Maddock" <john@johnmaddock.co.uk> To: <boost@lists.boost.org> Sent: Tuesday, November 21, 2006 5:09 AM Subject: Re: [boost] mistaken uses of <iostream> Hervé Brönnimann wrote:
On Nov 20, 2006, at 7:48 AM, John Maddock wrote:
I think the problem here is that it's tricky to ensure that you have all the necessary headers included: different implementations may or may not flag up an error depending which headers you've included, so including <iostream> is a sort of "belt-and-braces" approach.
The local fix for this is to write a library's cpp file that get compiled into the library.h, whose first line is #include "filename.h". This ensures that all the right headers get pulled in properly. In fact, the standard practice is to always include the headers in *reverse* order of dependency. The same works for the test driver: there is one test file dedicated simply to make sure that #include "filename.h" works without including anything else. It's a bit of a discipline and one must make sure that all code template has been instantiated, so it (like anything else) is not foolproof. You also need a notion of physical dependency and hierarchy levels. For this, I refer to John Lakos' book (whose second edition is in the writing).
Absolutely, but that still only ensures that filename.hpp compiles cleanly with your specific compiler / std lib combination: many std lib's will pull in code that isn't actually needed according to the std. For example does this compile: #include <stdexcept> std::domain_error d("abc"); You may think "yes" because domain_error is defined in the header included, however the constructor relies on std::string being fully defined, but <stdexcept> need only forward declare std::string to make itself work. There is one lib (STLPort) that actually does it this way too: the rationale, is that you can do things like: #include <stdexcept> void print_message(const char*); int foo() { try{ //something }catch(const std::domain_error& e) { print_message(e.what()); } } without requiring all of <string>. In practice though most other std lib's do include <string> implicitly when you include <stdexcept>. As far as I know there is no concensus on the committee on whether this should work or not. Frankly, it's one of those bicycle-shed discussion items :-( It's also why as things stand, if you want to know whether you have included all the necessary headers you either have to: 1) Test as you indicated above, then fix if it fails on platform X. 2) Do a manual ordit of the code.
As an aside, I've always wanted a sort of "conceptual" std lib implementation, that included in each header nothing except what absolutely has to be there. Just the declarations would do, so we could do compile-time tests against it to verify inclusion of the right headers: the only tricky bit is getting the compile time constants correct so that it can still compile meta code. Any volunteers? :->
John: I'm not sure I understand the only tricky bit. Can you pls elaborate?
Let's suppose that we did write a minimal std lib that included in each header only those things that the header absolutely guarentees. Most of the headers would just contain declarations more or less cut and pasted from the std. There are a few areas though where we would need to define real definitions: std::numeric_limits<long double>::digits would have to have the right value for the platform the lib was used on, or else compile-time decisions based on the value would do the wrong thing. This extends to all the limits macros etc as well. I guess it's probably trivial-ish with a ./configure step, but we tend not to require that around here :-( John. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Howard: Funny you should ask... Since I've joined Bloomberg LP and become their core librarian, I've been removing some dependencies on <cassert> (because Bloomberg has its own assert macros) and <iostream> (because of the cost you mention) galore. Dependencies on malloc were the worst because malloc (which is used by the default allocator in our uses of stlPort) is a tightly regulated function at Bloomberg. In many cases, using <iosfwd> works just fine in the headers. (No problem using <iostream> in the .cpp though.) One typical case I remember was someFunction(std::ostream errorStream = std::cerr); In this case, we got rid of 'cerr' by replacing the function with two overloads: someFunction(); // use cerr in the documentation, but only needed in the .cpp someFunction(std::ostream errorStream); Of course, if someFunction is a function template or member function of a class template, that technique breaks, but then if one is really using cerr in there, there's not much that can be done. In that case, we usually try to push the use of cerr down into some non- template utility class, where we can use the technique above. So far, I think there are no #include <iostream> in any of the header files I'm responsible for. Knock on wood. -- Hervé Brönnimann hervebronnimann@mac.com On Nov 18, 2006, at 10:20 AM, Howard Hinnant wrote:
<iostream> is the only C++ header that extracts a cost simply by including it (in typical implementations). The usual implementation is for it to include a static object of type std::ios_base::Init which is responsible for initializing the 8 terminal streams (cin, cout, cerr, clog, wcin, wcout, wcerr, wclog).
I've always thought it good programming practice to avoid including <iostream> if the translation unit didn't actually need one of these 8 terminal streams. For example if I needed to just get to istream and ostream to write my own I/O I would include <istream> and <ostream> but not <iostream> (the naming is very unfortunate).
It has recently come to my attention that I could be overly sensitive to this issue and making a fuss about nothing. So I'm writing here for a reality check. Do boost programmers consider the use of <iostream> as a short cut to get to non-terminal-streams I/O a reasonable technique? Or do boost programmers feel that use of <iostream> should be reserved only when using one or more of cin, cout, cerr, clog, wcin, wcout, wcerr, wclog?
I did a brief survey of boost 1.33.1 and found many "relaxed" uses of <iostream> under the boost/ directory (i.e. non test-case code). So in practice it does appear that using <iostream> as a shortcut is considered acceptable practice. However I wanted to highlight the point just in case people do view this as a bug that has simply snuck in under the radar to date.
-Howard
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost
participants (10)
-
Beman Dawes
-
Bo Persson
-
Boris Gubenko
-
Douglas Gregor
-
Hervé Brönnimann
-
Howard Hinnant
-
Joel de Guzman
-
John Maddock
-
Martin Wille
-
Robert Ramey