[comp.lang.c++] support for generic classes in c++?

sho@pur-phy (Sho Kuwamoto) (08/06/89)

     Is there any sensible way that support for generic classes could
be added?  I am new to C++ programming, and have no experience with
compiler design, so this may only be a pipe dream....

     What I mean is, is could C++ be extended to allow users to make a
matrix class that could be used as a matrix of homogeneous objects?
Look at vectors.  While it would be nice to use a constructor with
arguments when making a vector, the fact that you *can't* seems to
make it syntactically easier to extend this type of idea to user
defined generic classes....

     What about a syntax like this?  Define keywords generic and thisType:

******
generic class matrix {
    int n, m;
    thisType *data;
public:
    matrix(int wid, int height) { n=wid; m=height; data = new thisType[n*m]; }
    ~matrix() { delete data; }

    thisType& operator()(int j, int i) { return data[m*j+i]; }
};

class point {
    int x, y;
public:
    point(int startX=0, startY=0) { x = startX; y = startY; }
};

main()
{
    double matrix mDouble(3,4);
    int matrix mInt(3,4);
    point matrix mPoint(5,5);		// makes a 5x5 matrix of points, not
    [...]				// a matrix of points (5,5).
}
******

     Since the types given in the declaration are known at compile
time, it seems that at worst, C++ could make three different classes
(double, int, point) with their names munged.  What about operators?
Imagine that the following operator is a friend of matrix.

******
matrix operator+(matrix& m1, matrix& m2)
{
  matrix out;
  // do some error checking to make sure n&m are the same first.
  for(int i=0; i < m1.n*m1.m; i++)
    out = m1.data[i] + m2.data[i];
}
******

     If a new version of this were made for each type, mPoint+mPoint
would be *legal* if point+point was defined, but mDouble+mInt would
not be ok since the type of the return value is ambiguous.  This is
definitely a problem, but could probably be solved by some slight
changes to how user defined type conversion is done.

******
generic class matrix{
    [...]
public:
    double matrix(int matrix)  { double matrix out;  for(int i=0; ....); }
};
******

You may also need the construct,

******
double matrix operator+(double matrix& m1, int matrix& m2)
{ [...] }
******

in some cases.

     What do you think?  Is this too inefficient?  Should I just use
void* everywhere and do explicit type conversion?  Am I being a
complete idiot?  (most likely) It seems to me that it would be simple
to write this if you already had something which parsed C++ correctly
(ha!).  Just make a symbol table containing each class declared
generic, and make a version of that class for each type you use it
for...

-Sho
--
sho@risc.com  <<-- youth wants to know.

trost@crl.labs.tek.com (Bill Trost) (08/10/89)

[I was going to mail this solely to the person who asked the question,
but I've brought up enough questions in my mind with it that I want to
let the rest of the world beat on it]

show@risc.com (Sho Kuwamoto) writes:
>     Is there any sensible way that support for generic classes could
>be added?  I am new to C++ programming, and have no experience with
>compiler design, so this may only be a pipe dream....

...and then goes on to give definitions, uses, and examples.

The question is a good one, and has been discussed far and wide.
After multiple inheritance, parameterized types (as they're more
commonly called in the C++ community) have been the biggest things on
everyone's wish lists (bigger on mine, but maybe my priorities are off
:-) ).  AT&T is supposed to be working on somesuch.  I just hope they
don't use the syntax you proposed....

Yes, I do have an alternative syntax; something like:

	class Stack(X) {
	    X		data;
	    Stack(X)*	next;
	public:	
	    void	Push();
	    X		Pop();
			Stack(X)(int flag);	// the constructor (I guess)
			Stack(int flag)		// an alternative
	};

	typedef Stack(long) StackOfLongs;
	typedef Stack(ostream&) StackOfStreams;
	typedef Stack(streamstack) StackOfStreamStacks;

The syntax seems much cleaner this way (except for problems with the
constructor syntax), and avoids adding a new keyword.  Also, you get a
generalization out of this --- there's no reason that paramaterized
classes should be restricted to one parameter.  A good example would
be:

    class Assoc(left, right) {
	left	name;
	right	value;
    public:
	left	name();
	right	value();
	Assoc(left,right)(left l, right r);
    };

    typedef Assoc(char*, char*) DictionaryEntry;
    typedef Assoc(char, (void*)()) KeyTableEntry;

Of course, this opens new questions.  For instance, can one overload
the paramaterized type mechanism, allowing types of the same name with
a different number of parameters?  Should there be default parameters?
What support is there for inheritance among parameterized types?  Can
I do, for instance:

	class C(X, Y) : public A(X), public B(Y) {...};

or even

	class E(X) : public D(F(X)) {...};

The possibilities for semantic perversion are endless.  Then again,
that's what C++ is all about :-).

Bill Trost, Computer Research Labs, Tektronix
trost@crl.labs.tek.com / tektronix!crl.labs!trost
(trost@reed.bitnet, but probably tektronix!reed!trost)