Topic: PROPOSAL: Packages, #include retired etc


Author: abell@atl.mindspring.com (Andrew C. Bell)
Date: 1996/10/18
Raw View
denis@bull.tenet.odessa.ua (Denis Vlasenko) wrote:
>     Include files often used  in  C++  as  a  library  information
>storage. This approach has following disadvantages:
>     1. Include files  are  compiled  again  and  again.  Sometimes
>        compiler consumes more than half  of  the  overall  compile
>        time reading them.

Several of the MS-Windows compilers, and I suspect others, now have
mechanisms for "precompiling" headers, so that such compile time is
drastically reduced.  Certainly there is nothing in the language
specification that prevents a compiler from handling
#include <iostream>
with a pre-parsed representation of what is in iostream.h.

The C++ language shouldn't be changed to solve problems that can be
solved without language changes.

Andrew Bell
abell@mindspring.com, etc.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1996/10/15
Raw View
denis@bull.tenet.odessa.ua (Denis Vlasenko) writes:

> *******  Some things I want to see added to C++ *******************
>
>                 1. Include files retired.
>
>      Include files often used  in  C++  as  a  library  information
> storage. This approach has following disadvantages:
>
>      1. Include files  are  compiled  again  and  again.  Sometimes
>         compiler consumes more than half  of  the  overall  compile
>         time reading them.
>      2. Order of appearance of the include files is important.
>      3. Include files required by  another  include  file  must  be
>         specified explicitly.
>
>      I think include  files  must  be  replaced  by  some  kind  of
> pre-compiled files. I will  call  them  .def  files.  Special  WITH
> declaration can be used for reading of pre-compiled .def file. .Def
> files are produced by compiler instead of old-style .obj files.

    [...]

As far as I can tell, what you propose is a legal implementation of
include files.  I also expect that once things are fully stabilized, the
standard include files will be "built-in" to the compiler; perhaps
quality of implementation will impose that the vendors make this
building-in mechanism available to the user.

(To make myself clearer: when I say built-in, I do not mean for an
instance that the compiler will start recognizing e.g. string as a
keyword token.  Rather, the compiler will have access to a pre-compiled
image of what the compilation of the standard header would have given,
perhaps with some additional information for optimization purposes.  The
vendor could, of course, make compiler options available to generate
such a file; the optimization information could be provided by pragmas,
or simply not be supported for user headers.)

>                 2. Name space control.
>
>      This is major problem in  C++.  When  projects  grow  big  and
> complicated, I found that I can't define objects  with  names  like
> "print", "buffer", "allocate"  etc  without  name  collision  risk.
> Sometimes I can put them inside a class, but then I forced  to  use
> awkward syntax  MyClassName::print...  The  solution  is  Ada-style
> packages.

    [...]

This is the problem that namespace is supposed to solve.

>         2.2. Classes.
>
>      Class can have an initializer/de-initializer. Their purpose is
> the  same  as  of  package  initializer/de-initializer.

    [...]

This can easily be achieved using a static data member.

>         2.3. Nested functions and :: operator.
>
>      Functions can be nested. Nested functions cannot use values of
> automatic local variables  of  embedding  function,  in  all  other
> respects local names of embedding function are visible and  can  be
> used:

If they cannot use the local variables, what is gained by nesting?

> void outer() {
>     int localVar = 0;
>     static int staticVar = 0;
>
>     void inner() {
>         int i;
>         i = staticVar;          // Ok
>         i = localVar;           // Error
>         i = sizeof(localVar);   // Ok
>     }
> }
>
>      This feature enables class definitions inside  functions  with
> non-inline function members.

I make extensive use of local class definitions, but only when all of
the member functions are very simple (so the requirement to inline them
is not a constraint).  Otherwise, I think that they can lead very
quickly to unreadable code.

Note that the fact that you define the function in the class definition
does not mean that the compiler has to generate it inline.  In fact,
most of the time that I use such classes, it cannot; the functions in
question are virtual, and will be called virtually from outside the
function.

    [...]

>                 3. Minor changes.
>
>      Return type of a function cannot be implicitly assumed  to  be
> int. It must be specified explicitly.

Accepted (I think).

>      Class or package inheritance  type  (public/private)  must  be
> specified explicitly.

Might break code.

>      After opening brace of class or package definition, "public:",
> "private:" or "protected:" must follow.

Would definitly break significant amounts of code, and leads to a major
incompatibility with C, since C-like struct declarations would no longer
be legal.

>      Structs cannot have  non-public  members.  Structs  cannot  be
> derived privately.

Why?  This would represent a major change of philosophy in C++.  At
present, struct and class are, for all practical purposes, synonyms.

>      Static functions of a class also can be virtual.

Agreed, but not really worth the bother.  If the function is to be
virtual, it doesn't *have* to be static.  (The only functions that
*have* to be static are those that must be called without an instance of
the class.)

>      Semicolon must not appear after closing brace in struct/vector
> variable definition like these:
>
> struct s = { 1, "ABC", 'x' };
> char c[] = { 'a', 'b', 'c' };
>
>      I see no reason why it is there now.

In general, there is no "reason" why the grammar is the way it is.
Given that it is, I see no reason to change it.

>      Private members of a class or  package  are  invisible  rather
> than inaccessible. Example:
>
> class B {
>   public:
>     B() { p = 0; }
>
>   private:
>     int p;
> };
>
> int p = 1;
>
> class D: public B {
>   public:
>     int f() { return p; }       // Returns ::p
> };                              //   (B::p is not visible)

Delicate.  Read Stroustrup for the reasoning.  In general, it is not
desirable that the meaning of a well formed program change when access
is changed.  (A well formed program may become ill formed, or vice
versa, but if both variations are well formed, they should have the same
semantics.

>                 4. Requests for discussion.
>
>         4.1. Template declarations.
>
>      Personally I can't stand so-called "angle  brackets". Template
> declaration syntax is awkward.

We know.  The committee discussed this at length.  The real problem is
in expressions, where < can be either greater than or the opening
bracket of a template.  Consider the expression:

  f < x > ( y ) ;

Depending on the definition of f, this may be the explicit constructor
of the template class f, or a somewhat unusual (but fully legal)
comparison, the equivalent of "(f > x ? 1 : 0) > y".  (This example is
due to Andy Koenig.)

The committee discussed, and voted, at a time when the change might have
still been feasible.  Today, there is just too much template code in
existance to even consider it.

> Consider this fragment:
>
> template <class T>
> class Vector {...};
> typedef Vector<Vector<int>> IntMatrix;
>
>      IntMatrix declaration is invalid  because  compiler  considers
> closing angle braces ">>" as a right-shift  operator!  It  must  be
> written as
>
> typedef Vector<Vector<int> > IntMatrix;

So?  I don't consider this anywhere near as bothersome as my previous
example.  But then, I almost always separate my tokens with whitespace
anyway:

  typedef vector< vector< int > >
                      IntMatrix ;

    [...]

>         4.2. Struct/class declarations.
>
>      Personally  I  don't   like   semicolon   after   struct/class
> definitions. But it is required if we want  to  be  able  to  write
> fragments like this:
>
> struct {
>     int a;
>     int b;
> } s;            // type of s is "anonymous struct"
>
>      Can we abandon this style of variable declaration? Then we can
> abandon trailing semicolon also.

Problem of C compatibility.  There are significant differences between C
and C++, and they are definitel two different languages.  Still, it is,
and IMHO, should continue to be, possible to write common header files
with a minimum of #ifdef's.

>         4.3. Virtual functions in constructors/destructors.

There are virtual functions in constructors and destructors.  You must
simply realize that the dispatch according to the *current* type of the
object (that of the constructor or destructor), not the type that it
might be in the future, or was in the past.

Whether this is correct or not is, of course, debatable.  For once, C++
has opted on the side of safety; I approve the decision.

>      Consider following example:

This would best be handled by templates.  Failing that, restrict the
vector elements to classes derived from a common base (with a virtual
destructor); the only reason I can see for making the physical array
pointers instead of objects is polymorphism.

> class BaseVec {
>   public:
>    ~BaseVec()   { destroyAll(); }
>     ...
>     void destroyAll();
>
>   private:
>     virtual static void kill(void* p)   {}
>     ...
>     void **vec;
>     int  curSize;
> };
>
> class ObjectVec: public BaseVec {
>   public:
>    ~ObjectVec() {}
>     ...
>   private:
>     virtual static void kill(void* p)   { delete (Object*)p; }
> };
>
> void BaseVec::destroyAll() {
>     for(int i=0; i<curSize; i++)
>         kill(vec[i]);   // Urk! BaseVec::kill() called.
> }                       // ObjectVec destructor will not destroy
>                         // vector elements as intended.
>
>      Possible workaround:
>
> class BaseVec {
>     ...
>   private:
>     void (*kill)(void* p);      // Pointer to kill fn
>     ...
> };
>
>      But it is awkward. In fact, it's a virtual  function technique
> in convoluted form.

I've used it in exceptional cases.  The fact that it is exceptional
means that I don't really mind that it is a bit convoluted:-).  Most of
the time, either templates or normal virtual functions (not forgetting
the virtual destructor) will do the trick.

At this point, it is probably worth repeating that before requesting a
lot of changes in the language, it is definitly worth reading "The
Design and Evolution of C++", by Bjarne Stroustrup.  Even if there are
things you don't agree with, it is worth seeing what the author of the
language was trying to accomplish before criticizing it too harshly.
(And I know that it is easier for some of us to get access to such books
than for others.)

--
James Kanze           (+33) 88 14 49 00          email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
                            -- Beratung in industrieller Datenverarbeitung
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]