Topic: ctors & dtors for namespaces


Author: jones@cais.cais.com (Ben Jones)
Date: 23 Jun 1994 15:45:40 GMT
Raw View
Adrian Filipi-Martin (adrian@mo.cs.wm.edu) wrote:
: Hi everyone,

:  While brushing my teeth this morning, a useful feature for
: namespaces occurred to me. In short, I would like to propose that each
: namespace be allowed to have a constructor and a destructor
: function/method. These constructors and destructors could then be used
: to initialize global data for each namespace. While most global data
: can simply have their values assigned to them directly in the source,
: the constructors could come in handy for specifying the order in which
: global instances of a class are initialized. This could be used to
: avoid using cumbersome workarounds for dynamic initialization as
: described in [D&E] on p.97. in the very least it performs the rote
: technique required to avoid such problems.
:   ...

This is a good idea but what might be even better is to make "namespace" a
class where all members are static.  As such it could inherit other classes
and namespaces.  To inherit a class would mean that an anonymous instance of
that class becomes a [static] member of the namespace with its members
directly accessible.  This might help to ease the transition to
object-oriented programming.  Non-object-oriented programming often
means global functions operating on global names.  Enclose them in a
namespace and you don't have global conflicts.  Change it to a class
and you can make instances of the formerly global data.

This scheme is implemented in the ARC++ extension to C++ (except that
the "namespace" is called "package".  It doesn't currently include
constructors and destructors for packages but I had thought about
including something like that in a future release.

Ben Jones
jones@arsoftware.arclch.com





Author: adrian@mo.cs.wm.edu (Adrian Filipi-Martin)
Date: Fri, 24 Jun 1994 15:56:59 GMT
Raw View
In article <2ucan4$4m3@sun.cais.com>, jones@cais.cais.com (Ben Jones) writes:
> This is a good idea but what might be even better is to make "namespace" a
> class where all members are static.  As such it could inherit other classes
> and namespaces.  To inherit a class would mean that an anonymous instance of
> that class becomes a [static] member of the namespace with its members
> directly accessible.  This might help to ease the transition to
> object-oriented programming.  Non-object-oriented programming often
> means global functions operating on global names.  Enclose them in a
> namespace and you don't have global conflicts.  Change it to a class
> and you can make instances of the formerly global data.

 Making namespaces into true classes would create a  lot of wierd
exceptions to normal class usage & structure. Inherited namespaces would need to
be references to avoid duplication of namespaces. (What would be the end result
of multiple instances of "namespace iostream" or even a pointer to one?) I agree
that it isn't far off from what I suggested, but I think that leaving classes as
a specialized form of namespace is the way to go.

 Presently namespaces & classes only share the scoping properties: using,
:: and nesting. Giving namespaces ctors & dtors would be consistent with current
usage of classes. My suggestion would extend the set of common features of
classes and namespaces by allowing a single constructor without arguments (aka a
default ctor) and a destructor. The view of classes as specialized/enhanced
namespaces would be that classes may have constructor which take parameters and
may have multiple instances.

 I still think that namespace ctors & dtors would be useful for the global
data initialization and order dependency resolution within a namespace. Think of
iostreams. If you poke around libg++, you'll notice that cin, cout & cerr are not
even real classes. They are implemented as look-alike structures called
appropriately _fake_istream & _fake_ostream. Hence, no ctors. If the iostream
namespace had a mechanism for guaranteeing correct and timely construction, it
may be possible to avoid this wierdness and improve code maintainability.
Shadow/aliased data structures can be a good source for bugs.

cheers,
 Adrian
--
adrian@cs.wm.edu          ---->>>>| Support you local programmer,
adrian@icase.edu            --->>>| STOP Software Patent Abuses NOW!
Member: The League for        -->>| membership info at ftp.uu.net:/doc/lpf
       Programming Freedom      ->| print "join.ps.Z" for an application




Author: adrian@mo.cs.wm.edu (Adrian Filipi-Martin)
Date: Wed, 22 Jun 1994 14:30:26 GMT
Raw View
Hi everyone,

 While brushing my teeth this morning, a useful feature for
namespaces occurred to me. In short, I would like to propose that each
namespace be allowed to have a constructor and a destructor
function/method. These constructors and destructors could then be used
to initialize global data for each namespace. While most global data
can simply have their values assigned to them directly in the source,
the constructors could come in handy for specifying the order in which
global instances of a class are initialized. This could be used to
avoid using cumbersome workarounds for dynamic initialization as
described in [D&E] on p.97. in the very least it performs the rote
technique required to avoid such problems.

  The namespace constructors would need to be called in the
order of inclusion/occurrence/instantiation of the namespaces within
each module. (I use "instantiation," because the declaration of a
namespace is effectively its creation as an entity in the source of a
program.  This makes namespaces akin to global static objects.)
Additionally, each constructor should only be called once and take no
arguments. I see no reason why this would be difficult to implement,
even in the case where a namespace is included multiple times in
different header files. A simple implementation could be based upon
the workaround described in [D&E]:

   Per object file the compiler could generate an internal
initialization function which calls each constructor in the order the
namespaces are defined/instantiated. Then for each namespace, a static
flag could be allocated internally to indicate whether the namespace
constructor has been called.  Lastly, in the constructor, if the the
constructor has been called before, simply return, otherwise set the
flag and continue. The only difficulty to be worked out is how the
compiler would ensure that all the initialization functions are called
(in any order). I suspect the mechanism for calling constructors for
global objects will probably be sufficient. To ensure that destructors
are called in the opposite order, the flag could be set to the number
corresponding to the order in which the constructors were called. That
is the 1st namespace constructor flag, gets 1, the 2nd gets 2,
etc. The destructors would then be called in descending order of the
values of their flags.

 Aside from the obvious benefits derived by preventing order
dependence problems, this also would remove the need for the ugly and
inefficient use of flags by the programmer within the class. After the
first call of a method, the flags value is fixed. All other
comparisons based on it are a waste of time. Namespace constructors
would make this unnecessary, because they would guarantee that if an
object or function is visible and available for use in code (eg. it
has been declared in a header), that it is _also_ safe and available
for use when that code is running. This is consistent with the use of
constructors for instances of objects.

Consider the following code fragment:

////////// example.cc
 #include <iostream>

 class My_class
 {
 public:
  My_class() { cerr << "This is trouble, if no cerr yet.\n";}
  ~My_class() { cerr << "This is trouble, if cerr is gone.\n";}
 } my_class;

 int main(int, char*[])
 {
  cout << "hello world\n";
 }


////////// iostream(.h)
 namespace iostream
 {
  iostream() : cerr(), cout(), cin()
  {
   // initialize other global data for namespace.
  }
  ~iostream()
  {
   // do any clean up not handled by dtors for
   // global classes & resources.
  }

  // class definitions here.

  extern ostream cout, cerr;
  extern istream cin;
 }


////////// iostream.cc
 ostream cout, cerr;
 istream cin;
 // blah, blah, blah....


 In this scenario, all namespace constructors would be called,
then all global constructors and finally the main would be called. In
detail the order of method/function calls would be: cerr(), cout(),
cin(), iostream(), my_class(), main(), ~my_class() and ~iostream().

       Well, what do you think? See any fundamental problems with this?

cheers,
 Adrian



--
adrian@cs.wm.edu          ---->>>>| Support you local programmer,
adrian@icase.edu            --->>>| STOP Software Patent Abuses NOW!
Member: The League for        -->>| membership info at ftp.uu.net:/doc/lpf
       Programming Freedom      ->| print "join.ps.Z" for an application