[gnu.g++] problems with genclass

riedl@cs.purdue.EDU (John T Riedl) (09/27/89)

We've been unhappy with the classes generated by genclass because each
type needs to be separately generated, including the entire
super-class hierarchy for the new class.  For instance, to create a
set class containing elements of class intElement we have to generate
SLSet, Set, and SLList classes for intElement.  If we have another
type intElement1 for which we need similar sets, we have to generate
an additional three clasees for intElement1.

Ideally we would like to have a single class Set which takes a member
type as an argument to its constructor.  Thus we would only need code
for a container class once, no matter how many different types it was
used for.  Being able to share code would be one advantage, but the
biggest advantage is in making it easy for programmers to use
container classes.

The libg++ manual (User's Guide to GNU C++ Library) suggests in
section six, introduction to container class prototypes, that
a container class can be instantiated using 'void *' as the type.
Then, any pointer can be stored in the container.  This approach is
based on Stroustrup, pp 204-210.  

Unfortunately, these containers cannot use methods of the contained
class.  In particular, comparison operators are not available.  These
operators may be needed for building data structures such as heaps or
AVL-trees from ordered sets.  A partial solution is provided through
the <type>.defs.h files.  These files contain #defines for comparison
operators for <type>.  However, only one set of comparisons can be
active for a given compilation,  Hence, this trick only supports one
base type per container type at a time.

We are thinking of building a new Set class that would take as an
argument of its constructor the comparison functions for the contained
type.  These functions would be stored in the private area of the
class, and could be used by the methods of the class in place of the
#define'd types.  This way, a single void * class hierarchy could be
shared between members of any number of base types.

Has anyone done something like this?  Is there an easier solution to
the problem?  When are real C++ generics coming?

Thanks!
John Riedl
Jagannathan Srinivasan

dl@G.OSWEGO.EDU (Doug Lea) (09/28/89)

> We've been unhappy with the classes generated by genclass because each
> type needs to be separately generated, including the entire
> ... 
 
First, please use bug-lib-g++ for libg++-related questions. (There is
no info-lib-g++, just use the bug list.)

Possibly the best solution in your case would be to

    1) have all your classes be derived from a common base, that
        includes a virtual int compare(Base* b);

    2) Have all your containers be of Base*'s (suitably typedef'ed)

    3) Edit the CMP(a, b) macro to call a->compare.

And/Or similarly for the EQ macros, etc.


This gets you heterogenous containers. If you want homogenous
containers, then you probably want to live with multiple implementations.

The main disadvantage of the current container library is that you can't
readily set things up so that you can have subclasses of Set, each of
which shares the basic Set code but operates on pointers of an
*unrelated* different type.

I don't think that full C++ support for generics will happen in the
near future.

-Doug

T.Day@ucl-cs.UUCP (10/04/89)

From: Tim Day <T.Day@uk.ac.ucl.cs>

You can take a lot of the pain out of genclass with makefile rules
e.g from my own setup for bags: (works OK on Gnu make 3.54)
Note that
  $(GDEP) is the name of a file which can be touched to cause all genclassed
  code to be rebuilt.
  $(Gcomp) is the g++ compile macro (= $(C++) $(C++FLAGS) etc)
  Bags/Lists of Ptrs are pass by value (created by $(genclassV)).
  Anything else is pass by reference (created by $(genclassR)).
  useful.h is included everywhere
  The $(genclass ) macros...
    genclass the required class
    Insert a #include for the name of the ``contained'' class
    Insert a #include "useful.h"
    Touch a .cc file in case genclass didn't produce one
The result is that you can get all the .SLList, .Bag and .SLBag files generated
just by mentioning a .SLBag.h dependency.  (Of course you still have to 
remember to archive or link all three .o files) 

define genclassR
genclass $(basename $(basename $(notdir $@))) ref $(suffix $(basename $(notdir $@)))
prepend '#include "$(basename $(basename $(notdir $@))).h"' $(basename $(notdir $@)).h
prepend '#include "useful.h"' $(basename $(notdir $@)).h 
touch $(basename $(notdir $@)).cc
endef

define genclassV
genclass $(basename $(basename $(notdir $@))) val $(suffix $(basename $(notdir $@)))
prepend '#include "$(basename $(basename $(notdir $@))).h"' $(basename $(notdir $@)).h
prepend '#include "useful.h"' $(basename $(notdir $@)).h 
touch $(basename $(notdir $@)).cc
endef


%Ptr.SLList.h %Ptr.SLList.cc:		$(GDEP)
					$(genclassV)

%Ptr.SLList.o:				useful.h %Ptr.h %Ptr.defs.h %Ptr.SLList.h %Ptr.SLList.cc
					$(Gcomp)

%Ptr.Bag.h %Ptr.Bag.cc:			$(GDEP)
					$(genclassV)

%Ptr.Bag.o:				useful.h %Ptr.h %Ptr.defs.h %Ptr.Bag.h %Ptr.Bag.cc
					$(Gcomp)

%Ptr.SLBag.h %Ptr.SLBag.cc:		$(GDEP) %Ptr.SLList.h %Ptr.Bag.h 
					$(genclassV)

%Ptr.SLBag.o:				$(GDEP) useful.h %Ptr.h %Ptr.defs.h %Ptr.SLList.h %Ptr.Bag.h %Ptr.SLBag.h %Ptr.SLBag.cc
					$(Gcomp)


%.SLList.h %.SLList.cc:			$(GDEP)
					$(genclassR)

%.SLList.o:				useful.h %.h %.defs.h %.SLList.h %.SLList.cc
					$(Gcomp)

%.Bag.h %.Bag.cc:			$(GDEP)
					$(genclassR)

%.Bag.o:				useful.h %.h %.defs.h %.Bag.h %.Bag.cc
					$(Gcomp)

%.SLBag.h %.SLBag.cc:			$(GDEP) %.SLList.h %.Bag.h 
					$(genclassR)

%.SLBag.o:				$(GDEP) useful.h %.h %.defs.h %.SLList.h %.Bag.h %.SLBag.h %.SLBag.cc
					$(Gcomp)

You'll probably have to declare all the .h files you create as precious, 
otherwise make regards them as intermediate and deletes them after its built
the .o... not much use for libraries.  I think make can also get a little
confused by genclass creating two files at once.  You need slightly 
different versions of the genclass macros for bags of builtins (e.g int) or
supplied classes (e.g String). 

My favourite class ? String.%Ptr.SplayMap, v. useful for writing parser type
things
+-----------------------------------------------------------------------------+
Tim Day                           | Meet every second in life as challenge;
Department of Photogrammetry      | Respond fully to whatever happens
UCL, Gower St., London  WC1E 6BT  |  without anxiety, or complaint, or clinging
+-----------------------------------------------------------------------------+