On Mon, Jan 24, 2005 at 08:15:10PM +0000, Andreas Vox wrote:
> 
> Angus Leeming <[EMAIL PROTECTED]> writes:
> > namespace support = lyx::support;
> > using std::ostream;
> > typedef list<string> SnippetList;
> > 
> > is just baaaddd. 
> 
> Ah, bad for *.h, ok for *.C? 
> Got it.

The reason being that *.h files are included into other files in ways
you cannot control.  Conversely, those including a *.h file into their
own code have no control over its contents (at least in principle).

So, if you pull something into the global namespace in a header file,
like "using std::list;" would, you force EVERY file using your header
file either to use "std::list" at all times or to go through
name-conflict-resolution-gymnatics to use the correct token called
"list".  But the whole point of namespaces is to minimize/eliminate
these sorts of gymnastics in the first place.

But why is it okay for *.C?

First and most obviously, source files aren't included into other
source or headers.  But, more importantly, a source file is a
"translation unit".  That is, the compiler treats it (and any
#include'd headers) as a self-contained entity.  Any references to
outside critters must be flagged as such.

So, doing "using std::ostream;" inside of a source file only affects
the contents of *that* source file, and only during the tokenization
stage of compilation.  (The compiler's gonna internally change any
unqualified "ostream" tokens back into "std::ostream".)

At this point, we enter a discussion of stylistics and code
maintenance.

The bulk of one's work on a piece of code will be maintenance, not
writing it initially.  It's one of the old bromides of software
development, actually.  Therefore, "good coding style" dictates that
you "code in the future tense," using language features only in the
most narrow sense.  For example, you don't make all members of a class
"public"; you only make those you absolutely need to expose public.
In the future, should you need to expose one of your private member
functions, it's trivial to do so witha quick cut-n-paste in your class
header file.

The idea behind a "using" clause is similar.  Localize them to where
you need them most, and only to there.  It's not much effort to add
"using std::string;" at the top of each new function that requires
STL strings.  Then, if you later find that, yes, most of the functions
in this *.C file need STL strings and will never use any other kind of
string, you can easily add a top-level "using std::string;", no
changes to exsting code necessary.

Consider the converse situation, where you use the hydroge-bomb
approach and start out with "using std::map"; at the top of your
source.  You merrily write away.  Then one day, you need to add a new
header file and some special code for a specially-optimized
RDBMS-backed dictionary structure.  It's also called "map".  So you
write your new functions, add a "using somespecial::map" to each, and
WHAMO!  You get a bazillion name-conflicts at compile time.  Now you
not only have to remove the top-level "using std::map", but you need
to sift through hundreds of lines of code to find which functions
actually use std::map and add in a "using" statement to just those
functions.  What a headache!

There are nevertheless reasons for putting a top-level "using
std::foo;" decl. in a file.  Doing so makes a statement:  Don't even
THINK of using another type of "fooXYZ" with this code!  Putting in a
toplevel "using std::ostream;" tells future authors that no one, no
one at all, should even try to use anything but the STL ostream with
this code... put it in another source file and link the two together
instead!


Does that help at all, Andreas?

-- 
John Weiss

Reply via email to