Topic: Using namespaces (even more)
Author: damian@cs.monash.edu.au (Damian Conway)
Date: Wed, 9 Feb 1994 19:17:15 GMT Raw View
bs@alice.att.com (Bjarne Stroustrup) writes:
>The general idea is to have
> // header:
> namespace header {
> #include <header.h> // the old textual #include
> }
> using namespace header;
Bjarne,
Did/would you consider the variant:
using namespace header {
#include <header.h> // the old textual #include
}
I know the gain is trivial, but there's a long and glorious history... :-)
damian
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
who: Damian Conway email: damian@bruce.cs.monash.edu.au
where: Dept. Computer Science phone: +61-3-565-5184
Monash University fax: +61-3-565-5146
Clayton 3168 quote: "A pessimist is never disappointed."
AUSTRALIA
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: Fri, 11 Feb 1994 18:58:21 GMT Raw View
Thanks you, Bjarne Stroustrup for your detailed answer.
[Bjarne Stroustrup (bs@alice.att.com) writes:]
> > Have there been any considerations to distinguish between public and
> > private members of a namespace? This mechanism could be used like private
> > class-members....
> > [..]
> Yes. We considered that and many other variants. Most variants were rejected
> to avoid adding complications.
When I heard that members of namespaces are qualifiedly named
X::foo, X::Type, X::enum_value_1 X::Y::foo
this reminded my about accessing static members of classes:
A::foo, A::Type, A::enum_value_1, A::B::foo
I just thought since there are private class-members, there are
also private namespace-members. And I thought that private members
of a namespace could be something like global 'static'. Never mind.
So what are the advantages of namespaces to static class-members?:
One may split the declaration of a namespace, and one may apply using.
Besides this namespace-members and public static members of classes
behave the same way, they can be accessed the same way and namespace-
declarations can be nested like class-declarations.
> > May I write a sequence of usings like 'using X::fct1, X::fct2;'?
>
> No. I experimented with variants like that and found them not very useful.
I just thought it is a general concept in most programming languages to
allow sequencialization of declarations:
int a, b(), *c, d[10];
typedef int e, f(), *g, h[10];
template<class T> int i(T), j(T), k(T);
> I am not keen on further evolution of the namespace concept. I'd rather
> see a stable definition and a standard.
>
> - Bjarne
I too would appreciate if we had the new standard right now. IMHO if
one would generalize the concept of namespaces instead of adding just
new features 'namespace' and 'using' to the language, one could
prevent that C++ gets even more complex.
And the level of complexity may be one of the most serious handicaps
that C++ will have in the competition with other programming languages.
Ulf
--------------------------------------------------------------------
Ulf Sch nemann
schuenem@informatik.tu-muenchen.de
Institut f r Informatik, Technische Universit t M nchen.
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: Tue, 8 Feb 1994 09:33:51 GMT Raw View
Hello again,
Sorry for my duplicate article (I had problems with the server).
First let me answer an e-mail:
I got the mentioned Resolutions-paper via ftp from world.std.com,
directory: AW/stroustrup2e, file: iso.ps (postscript) size: 52589
I have some more questions:
7) May I write a sequence of usings like 'using X::fct1, X::fct2;'?
8) Am I right that using is transitive?
namespace X {
int fct1();
}
namespace Y {
using X::fct1;
}
void f()
{ using namsepace Y; // -> I can use fct1 from X
fct1();
}
void g()
{ using Y::fct1; // -> X::fct1 is accessed here
fc1();
}
9) When are collisions forbidden: at the point of declaration
or application?
namespace X {
int var1;
}
void f()
{ int var1;
{ using namsepace Y; // Does Y::var1 hide former
// declaration of var1 ?
}
using namsepace Y; // Is this an error/waring:
// duplicate var1 (local and in X) (?)
using Y::var1; // Is the error here (like anoher int var1-declaration):
// duplicate var1 (local and in X) (?)
var1++; // or here:
// ambigous var1 (local or X) (?)
}
namespace Y {
int var1;
}
10) r.3.3.1.3 says: For purpose of names lookup the scope of a class
is a namspace... A using-decl. used as a member
declaration must refer ....
So inside a class I can have private and public 'using'. (This refers to
my question 6 - private namespace-members).
Can I access the vars/fcts used by 'using' like an ordinary static member
of that class?
struct B {
using X::fct;
};
void f()
{ B b;
b.fct(); // is this legal?
}
11)
May I write 'using namspace B;' or 'using B::x;' if B is a class
and I want to access the public _static_ members of B (e.g. x)
without scope-qualification?
12) Have there been considerations to extend the 'using' mechnism to
_instances_ of a class (struct)? e.g.:
struct PersonData {
int bith,death;
int region;
static int regional_average_livetime[ MAXREGION ];
...
};
int still_living (PersonData p)
{ using namespace p; // or 'using p;' (see my question 2, previous article)
if( death!= -1) return death - time();
int age = time() - birth;
return age - regional_average_livetime[ region ];
}
(I know, still_living should be a member of PersonData, but its just an
example) I would appreciate if one could do this.
Thanks for reading all these questions. I just had to ask them.
I hope it helps me and others understand using namespaces. And maybe
my questions (6,7,11,12) can lead to an evolution of the namespace-
mechanism which shurely is an important enhencement and a generalization
of the access-rules for classes.
Ulf Sch neman
schuenem@informatik.tu-muenchen.de
Author: bs@alice.att.com (Bjarne Stroustrup)
Date: 8 Feb 94 22:23:20 GMT Raw View
schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann) writes
> (I hope this article does not come dubble)
It did.
> Hello,
>
> Now that I managed to get the ANSI/ISO Resolutions for their draft working paper,
> I have some questions concerning namespaces. If these questions have already been
> discussed in this newsgroup, please tell me how I can access these articles.
> The Resolution-paper r.3.3.1.1 says:
> >...
> >using-declaration:
> > using Namespacename::Identifier;
> >using-directive:
> > using namespace Namespacename;
> >...
> 1) May the Identifier in the using-declaration be a namespace?
Yes.
> 2) Why do I have to write 'using namespace X;' and not just 'using X;'? The
> compiler will always be able to determine if X is a namespace or something
> else. Or is it for some reason important to distinguish lexically between
> using-declaration and using-directive? IMHO writing 'namespace' is just
> superflous. Please correct me.
I tried ``using X;'' It led to confusion among users. ``using namespace X;''
makes it easier for people to grasp the difference between a using-directive
and a using-declaration. Also, implementors found the more explicit form
preferable for parsing, error handling, etc.
> 3) r.3.3.1.3 says:
> >... Unnamed namespaces make global static (r.7.1.1) redundant....
>
> Does this mean that function and variable names that are members of
> an unnamed namespace will not appear in the objectfile and thus
> not be accessable from outside this compilation-unit (like it is
> the case with global static fcts/vars)?
Yes, though there is nothing in C or C++ that prohibits linkers from
making such names accessible to a debugger; they just cannot interfere
with names from other compilation units.
> 4) This is rather an implementation-question than a language-question,
> but it would help understanding how namespaces work:
> a) Will the namespaces of identifiers be encoded into their names in
> the objectifile, so that the linker can ditinginguish between A::var1
> and B::var1?
A::var1 and B::var1 must be distinguished in the object file.
> b) But if so, how can I wrap a namespace around a library/object-file
> (that was compiled without namespaces) afterwads? E.g.:
> namespace XLibrary {
> #include <Xlib.h>
> }
> Or does this result in a linker-error as it wount find
> XLibrary::XOpenDisplay()?
You can't except if the library has C linkage. Systematic use of namespaces
requires cooperation from library suppliers or access to the source code.
> 5) In some articles #include <header> was mentioned. As far as I
> understood it
> #include <header.h> works like it always worked, and
> #include <header> wraps the declarations that are
> in the file 'header.h' into a namespace called 'header'.
> - Please corect me if I'm not right.
You are right.
> My question is:
> How does header.h look like. Do there have to be any namespace or
> using declarations(or -directives or whatever) so that the preprocessor
> (or who does it) is able to do #include <header>?
> Can anyone give me a kind of rewrite-rule like:
> #include <header> => namespace header {
> #include <header.h> // the old textual #include
> }
> (This interferes with question 4)
> Or if there has to be a namespace-wrapper _inside_ header.h:
> namespace header {
> #include <old_header.h>
> }
> Than the rewrite-rule could be:
> #include <header.h> => #include <header.h> // old textual #include
> using header;
The general idea is to have
// header:
namespace header {
#include <header.h> // the old textual #include
}
using namespace header;
but the exact details are not fixed by the standard (except for the
standard headers) and the details may vary from header to header.
> 6) Have there been any considerations to distinguish between public and
> private members of a namespace? This mechanism could be used like private
> class-members to controll access to critical functions (E.g. recursive
> functions that will only terminate with some special parameter-values)
> E.g.:
>
> namespace X {
> private:
> const int MAX = 9999;
> int impl (int a, int b, int c, int d);
> public:
> inline int fct0 (int b) { return impl(0,b,0,MAX); }
> inline int fct1 (int b) { return impl(1,b,1,MAX); }
> inline int rfct0 (int a) { return impl(a,0,MAX,0); }
> inline int rfct1 (int a) { return impl(a,1,MAX,1); }
> }
>
> I would appreciate if this mechanism could be introduced analogously(?spelling?)
> with classes (well, what would 'protected' be then?)
Yes. We considered that and many other variants. Most variants were rejected
to avoid adding complications.
I think your example is best handled like this:
namespace X_impl { // implementation details for X
const int MAX = 9999;
int impl(int a, int b, int c, int d);
}
namespace X {
inline int fct0(int b) { return X_impl::impl(0,b,0,X_impl::MAX); }
inline int fct1(int b) { return X_impl::impl(1,b,1,X_impl::MAX); }
inline int rfct0(int a) { return X_impl::impl(a,0,X_impl::MAX,0); }
inline int rfct1(int a) { return X_impl::impl(a,1,X_impl::MAX,1); }
}
> (Oh this is quite long, maybe it would have been better to split these
> questions into several articles).
Personally I find it easier to deal with a bundle of questions, but the
probability of people finding the time to answer probably goes down :-)
- Bjarne
Author: bs@alice.att.com (Bjarne Stroustrup)
Date: 8 Feb 94 22:23:42 GMT Raw View
schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann) writes
> Hello again,
>
> Sorry for my duplicate article (I had problems with the server).
Politeness is so refreshing.
> First let me answer an e-mail:
> I got the mentioned Resolutions-paper via ftp from world.std.com,
> directory: AW/stroustrup2e, file: iso.ps (postscript) size: 52589
Comment: Some people in europe have had problems with printing that.
It is a postscript implementation compatibility problem. The file
can be printed; you may however need help from a local guru to delete
a few lines. Sorry, I'm not a postscript guru.
> I have some more questions:
>
> 7) May I write a sequence of usings like 'using X::fct1, X::fct2;'?
No. I experimented with variants like that and found them not very useful.
> 8) Am I right that using is transitive?
> namespace X {
> int fct1();
> }
> namespace Y {
> using X::fct1;
> }
> void f()
> { using namsepace Y; // -> I can use fct1 from X
> fct1();
> }
Yes. Actually, Y has a f that just happens to refer to X's f.
> void g()
> { using Y::fct1; // -> X::fct1 is accessed here
> fc1();
> }
Yes.
> 9) When are collisions forbidden: at the point of declaration
> or application?
>
> namespace X {
> int var1;
> }
> void f()
> { int var1;
> { using namsepace Y; // Does Y::var1 hide former
> // declaration of var1 ?
No. However, you can't use an undefined namespace.
> }
> using namsepace Y; // Is this an error/waring:
> // duplicate var1 (local and in X) (?)
No
> using Y::var1; // Is the error here (like anoher int var1-decl > aration):
Error
> // duplicate var1 (local and in X) (?)
> var1++; // or here:
> // ambigous var1 (local or X) (?)
> }
> namespace Y {
> int var1;
> }
I wrote longish papers explaining these issues for the committee.
Unfortunately, I haven't had time to get them published.
B. Stroustrup: Library Design Using C++
The C++ Report. Vol 5 no 5. pp 14-22
June 1993.
answers a few questions, and I recall follow-up papers on namespaces by others
(Josee Lajoie?) in the C++ Report.
The short answer is: clashes with using-declarations happens at the point of
declaration and clashes with using-directives happen at the point of use.
A using-declarations declares a local synonym, a using-directive simply
makes members from a namespace accessible wherever the namespace was defined.
> 10) r.3.3.1.3 says: For purpose of names lookup the scope of a class
> is a namspace... A using-decl. used as a member
> declaration must refer ....
> So inside a class I can have private and public 'using'. (This refers to
> my question 6 - private namespace-members).
Yes.
> Can I access the vars/fcts used by 'using' like an ordinary static member
> of that class?
Yes.
> struct B {
> using X::fct;
> };
> void f()
> { B b;
> b.fct(); // is this legal?
> }
No, a member declared using a using-declaration must refer to an accessible
member of a base class.
> 11)
> May I write 'using namspace B;' or 'using B::x;' if B is a class
> and I want to access the public _static_ members of B (e.g. x)
> without scope-qualification?
As currently defined: No. The question is whether allowing such access
for static members only is more or less confusing than disallowing
it for all (static and non-static members).
> 12) Have there been considerations to extend the 'using' mechnism to
> _instances_ of a class (struct)? e.g.:
>
> struct PersonData {
> int bith,death;
> int region;
> static int regional_average_livetime[ MAXREGION ];
> ...
> };
> int still_living (PersonData p)
> { using namespace p; // or 'using p;' (see my question 2, previous article)
> if( death!= -1) return death - time();
> int age = time() - birth;
> return age - regional_average_livetime[ region ];
> }
> (I know, still_living should be a member of PersonData, but its just an
> example) I would appreciate if one could do this.
Yes, it was considered. I don't think it would be a net gain to the language.
it would allow some ``neat tricks'' and a lot of confusion. Namespaces is
a scope manipulation tool, not a pointer/object manipulation tool.
> Thanks for reading all these questions. I just had to ask them.
> I hope it helps me and others understand using namespaces. And maybe
> my questions (6,7,11,12) can lead to an evolution of the namespace-
> mechanism which shurely is an important enhencement and a generalization
> of the access-rules for classes.
I am not keen on further evolution of the namespace concept. I'd rather
see a stable definition and a standard.
- Bjarne
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: Wed, 9 Feb 1994 09:55:24 GMT Raw View
Alan.Sloane@Eng.Sun.COM sent me a reply per e-mail:
>> 6) Have there been any considerations to distinguish between public and
>> private members of a namespace? This mechanism could be used like private
>> class-members to controll access to critical functions (E.g. recursive
>> functions that will only terminate with some special parameter-values)
> I never heard it suggested seriously. You *can* use using-declarations to
> (laboriously) simulate the effect. IMHO it's complicated enough already !
Of course it would be more complicated if one thinks of 'namespace' and 'class'
(and the others) as distinct concepts. But IMHO C++ could reach a
SIMPLIFICATION(!) if one brings the concepts of 'namespace' and 'class' (etc)
as close together as possible and achieves a general concept for all kind of
namespaces (especially for the access to members of namespaces)
Namespace-members are static, it is not possible to create instances of a namespace.
Of course classes are more than simple namespaces, they also are a _type_ of which
you can create instances and of course with namespaces you can't have ctor/dtor,
operators, virtual functions etc.
But I can't see any real difference between STATIC members of a class and members
of a namespace. And I can't see any reason to make syntactic differences. To me
namespaces only play a role in the way one can ACCESS its members. (Please, please
correct me if I am wrong)
I think the same basic idea was expressed in the Resoultion-paper r.3.3.1.3:
> For purpose of name lokup, the scope of a class is a namespace.
> The scope of a derived class is nested in the scope of each of its base classes.
> Qualifications and using apply to classes exactly as to (other) namespaces.
To generalize access to members of namespaces of any kind I would propose:
1. Members:
Nonstatic members of a class are rather part of an instance than directly members
of the namespace of its class because members of a namespaces are static.
2. Public - Private:
All members of a namespace can be declared private or public (like in classes).
Members of 'enum' are allways public, members of struct are by default public,
members of class are by default private ....
3. Access:
Private members can only be accessed by the members of the same namespace.
Public members can be accessed by the members of the same namespace and from
outside this namespaces if this namespace is declared inside a namespace
that is public to me. All global namespaces are public.
3. Qualified access:
All public members of a namespace can be accessed by Namespacename::Membername
4. Using:
Qualified access can be avoided by a using-declaration or a using-directive
(as is proposed oinly for 'namespace' by the Resolutions-paper).
The result of my proposal would be that the left and the right side in this
example behave the same:
namespace X { class X {
public: public:
Mode { AA,BB}; Mode { AA,BB};
int x; static int x;
inline int fct(Mode m) static int fct(Mode m)
{ return foo(m,x,y,0); } { return foo(m,x,y,0); }
private: private:
int y; static int y;
int foo(Mode,int,int,int); static int foo(Mode,int,int,int);
} };
void f() void f()
{ X::x++; { X::x++;
X::fct(X::AA); X::fct(X::AA);
using X::Mode; using X::Mode;
X::fct(AA); X::fct(AA);
using X::fct; using X::fct;
fct(AA); fct(AA);
using namespace X; using namespace X;
x++; x++;
fct(AA); fct(AA);
} }
Don't you think this would be a simplification because it is a generalization?
There are two difference between 'namespace' and 'class' that do not
need to be eliminated because they are rather an aspect of _construction_
than of access (please tell me if you can think of some more):
1. 'A namespace that is a class cannot have names added by further namespace
declarations' (r.3.3.1.3) Of course we do not want that for classes:
the one-interface paradigm. Although I think there has been a discussion
to allow private (static?) members to be introduced outside the real
class-body.
2. Classes can be derived:
> The scope of a derived class is nested in the scope of each of its base
> classes.
Well I think without having instances derivation of 'namespace' is not very
interesting. (Maybe you have an idea?)
Please, I would be very interested in hearing your opinion.
Thanks for reading this,
Ulf Sch nemann
schuenem@informatik.tu-muenchen.de