Topic: adding something like .. to C++ - comments?
Author: assela@aix.rpi.edu (A. Andre Asselin)
Date: Thu, 19 Mar 1992 16:45:40 GMT Raw View
I've been using C++ to develop a rather large application for Mickeysoft
Windows and have run into kind of an annoying hitch in the language-- I'd
like to propose a small extension to the language to fix this and get
comments to see what you think.
Imagine you're writing a class derived from some other one: for example,
class TMyWindow : public TWindow { ... }. TWindow has all the skeleton
code to handle the basic responsibilities of a window on the screen. While
you're writing it, you add functionality to many of the virtual functions
available in TWindow: for example,
void TMyWindow::SetupWindow(void) {
TWindow::SetupWindow();
<new stuff>
}
After you've written all these functions, you discover that TWindow has a
BUG in it. At this point you have a few options
1. Fix the bug in the code for TWindow. This option is available only
if you have the source code, and isn't particularly "clean", especially
if what you consider a bug the vendor considers a design decision
and all new versions will also have this "bug".
2. Fix it in the code for TMyWindow. While this is entirely possible
to do, it doesn't quite sit right with me. After all, isn't one of
the basic tenets of OOP to resuse old code? Doing it this way, you'd
have to apply your fix to every class derived from TWindow.
3. Define a new class TWindow1, fix it there, and derive TMyWindow from
it. This is the method I favor. Now, whenever you need to define a
new window class, you derive it from TWindow1, and it already has all
the fixes necessary.
OK, now that you have the senerio, here's the problem. Above I wrote all
those member functions to call the parents version of the function before
doing any of my new code. Well, when I insert TWindow1 between TWindow and
TMyWindow, now all those functions have to be changed to call
TWindow1::whatever. This is tedious and error prone.
What I propose is something similar to DOS or UNIX's .. directory. Provide
some syntax for saying execute my parent's version of this function, whoever
my parent may be. For example:
void TMyWindow::SetupWindow(void) {
..::SetupWindow();
<new stuff>
}
The syntax looks ugly, and you're free to suggest an alternative, but I'd
like to see that kind of FUNCTIONALITY available.
Any comments?
- Andre Asselin (assela@rpi.edu)
Author: werner@spss.com (John Werner)
Date: 19 Mar 92 18:18:08 GMT Raw View
In article <kvftz!=@rpi.edu> assela@aix.rpi.edu (A. Andre Asselin) writes:
>What I propose is something similar to DOS or UNIX's .. directory. Provide
>some syntax for saying execute my parent's version of this function, whoever
>my parent may be. For example:
> void TMyWindow::SetupWindow(void) {
> ..::SetupWindow();
> <new stuff>
> }
[Note: I'm in no way connected with the ANSI committee, so all of this is
second- or third-hand....]
I think an extension like this was proposed to the committee by Apple
and perhaps others. They wanted a new "inherited" keyword, so your
example would look like:
void TMyWindow::SetupWindow(void) {
inherited::SetupWindow();
<new stuff>
}
This wasn't accepted, because it turns out that it is fairly easy to
get this functionality without an extension to the language. If you
put a typedef for 'inherited' in the class declaration, like so:
class TMyWindow : public TWindow1 {
typedef TWindow1 inherited;
public:
...
};
Then you can use the private 'inherited' type inside TMyWindow
methods, just like my first example, and it will resolve to TWindow1.
Nested type declarations like this haven't always been legal in C++; I
think they were added in version 2.1, but I could be wrong.
There's one more reason not to add a new 'inherited' keyword or '..'
token to the language: how would it behave with multiple inheritance?
--
-------------------------------------------------------------------------
John Werner | werner@spss.com | If these were SPSS's opinions,
SPSS, Inc. | (312) 329-3677 | I wouldn't be posting them.
Author: pool@cs.utwente.nl (Sander Pool)
Date: 20 Mar 92 10:06:11 GMT Raw View
In article <1992Mar19.181808.6509@spss.com>, werner@spss.com (John Werner) writes:
|> In article <kvftz!=@rpi.edu> assela@aix.rpi.edu (A. Andre Asselin) writes:
|> >What I propose is something similar to DOS or UNIX's .. directory. Provide
|> >some syntax for saying execute my parent's version of this function, whoever
|> >my parent may be. For example:
|> > void TMyWindow::SetupWindow(void) {
|> > ..::SetupWindow();
|> > <new stuff>
|> > }
|>
< deleted >
|> This wasn't accepted, because it turns out that it is fairly easy to
|> get this functionality without an extension to the language. If you
|> put a typedef for 'inherited' in the class declaration, like so:
|>
|> class TMyWindow : public TWindow1 {
|> typedef TWindow1 inherited;
|> public:
|> ...
|> };
|>
|> Then you can use the private 'inherited' type inside TMyWindow
|> methods, just like my first example, and it will resolve to TWindow1.
|> Nested type declarations like this haven't always been legal in C++; I
|> think they were added in version 2.1, but I could be wrong.
|>
|> There's one more reason not to add a new 'inherited' keyword or '..'
|> token to the language: how would it behave with multiple inheritance?
well, that's easy of course (or am I being totally ignorant ;-). multiple inheritance can only be used if there are no duplicate identifier names, right?
so, using '..' or something else would simply result in the compiler looking up that particular ID in any of it's parents classes. if more than one of those ID's exist than the compiler would have complained anyway!
multiple inheritance gives a few problems, but creates no new ones when adding
a '..' directive. IMHO this is much nicer than using a typedef (which is a nice alternative as long as it's the only thing around).
Regards, Sander.
|>
|> --
|> -------------------------------------------------------------------------
|> John Werner | werner@spss.com | If these were SPSS's opinions,
|> SPSS, Inc. | (312) 329-3677 | I wouldn't be posting them.
******************************************************************
Sander O. Pool Twente University,
department of Computer Science
SETI group / TRESE project H303
__________________________________________________________________
address:PO Box 217 | misc. phone +31-53-893715
7500 AE Enschede | fax +31-53-356531
The Netherlands | email pool@cs.utwente.nl
******************************************************************
Author: jbn@lulea.trab.se (Johan Bengtsson)
Date: 20 Mar 92 12:26:56 GMT Raw View
werner@spss.com (John Werner) writes:
:
: class TMyWindow : public TWindow1 {
: typedef TWindow1 inherited;
: public:
: ...
: };
:
: Then you can use the private 'inherited' type inside TMyWindow
: methods, just like my first example, and it will resolve to TWindow1.
: Nested type declarations like this haven't always been legal in C++; I
: think they were added in version 2.1, but I could be wrong.
No, you are right, although the _implementation_ of nested
types and typedefs in 2.1 (CFront) is broken (and I am not
referring to the backward compatibility with 2.0).
Below is a test program that illustrates this (if you are
using nested types under 2.1, you should feel a bit uneasy).
Does it work with 3.0?
--------------------------------------------------------------------------
| Johan Bengtsson, Telia Research AB, Aurorum 6, S-951 75 Lulea, Sweden |
| Johan.Bengtsson@lulea.trab.se; Voice:(+46)92075471; Fax:(+46)92075490 |
--------------------------------------------------------------------------
//
// brokenNested.C
//
// Illustrates the brokenness of C++ 2.1's treatment of
// nested typedefs.
//
// This program prints:
// X
// Y
// Y
//
// If you change the name "NotSameName" to "SameName",
// then it prints:
// X
// X
// X
//
// i.e. the typedef inside class Enclose has no effect in this case
// (no warning!).
//
#include <iostream.h>
class NotSameName {
public:
char* type() { return "X"; }
};
class Y {
public:
char* type() { return "Y"; }
};
class Enclose {
public:
typedef Y SameName;
SameName a;
};
class Derived : public Enclose {
public:
SameName b;
};
int main()
{
NotSameName obj;
Enclose e;
Derived d;
cout << obj.type() << endl; // X
cout << e.a.type() << endl; // X or Y ? (should be Y)
cout << d.b.type() << endl; // X or Y ? (should be Y)
return 0;
}
--
--------------------------------------------------------------------------
| Johan Bengtsson, Telia Research AB, Aurorum 6, S-951 75 Lulea, Sweden |
| Johan.Bengtsson@lulea.trab.se; Voice:(+46)92075471; Fax:(+46)92075490 |
--------------------------------------------------------------------------
Author: dag@control.lth.se (Dag Bruck)
Date: 23 Mar 92 12:58:21 GMT Raw View
In article <1992Mar19.181808.6509@spss.com> werner@spss.com (John Werner) writes:
>I think an extension like this was proposed to the committee by Apple
>and perhaps others. They wanted a new "inherited" keyword, so your
>example would look like:
>
> void TMyWindow::SetupWindow(void) {
> inherited::SetupWindow();
> <new stuff>
> }
Your description of the proposal and the "typedef" work-around is
quite correct.
>There's one more reason not to add a new 'inherited' keyword or '..'
>token to the language: how would it behave with multiple inheritance?
As the proposer of this feature, I beg to disagree. The advantage of
the built-in keyword "inherited" is that you would be guaranteed a
compile-time error in the case of an ambiguity caused by MI.
If you explicitly name the base class there is a risk that the code
incorrectly points at one of the base classes, in particular if you
modify an existing SI class hierarchy to take advantage of MI. The
typedef work-around has this problem too, but you only have to worry
about a single occurance, not base class names all over the code.
I think the typedef work-around will do the job well in almost every
case. I should point out that it was Mike Tiemann who invented the
work-around during one of the meetings.
-- Dag
Author: linden@fanout.et.tudelft.nl (Hans van der Linden)
Date: 25 Mar 92 16:05:26 GMT Raw View
In article <4010@holden.lulea.trab.se>, jbn@lulea.trab.se (Johan Bengtsson) writes:
|> werner@spss.com (John Werner) writes:
|> :
|> : class TMyWindow : public TWindow1 {
|> : typedef TWindow1 inherited;
|> : public:
|> : ...
|> : };
|> :
|> : Then you can use the private 'inherited' type inside TMyWindow
|> : methods, just like my first example, and it will resolve to TWindow1.
|> : Nested type declarations like this haven't always been legal in C++; I
|> : think they were added in version 2.1, but I could be wrong.
|>
|> No, you are right, although the _implementation_ of nested
|> types and typedefs in 2.1 (CFront) is broken (and I am not
|> referring to the backward compatibility with 2.0).
|>
|> Below is a test program that illustrates this (if you are
|> using nested types under 2.1, you should feel a bit uneasy).
|> Does it work with 3.0?
|>
|> --------------------------------------------------------------------------
|> | Johan Bengtsson, Telia Research AB, Aurorum 6, S-951 75 Lulea, Sweden |
|> | Johan.Bengtsson@lulea.trab.se; Voice:(+46)92075471; Fax:(+46)92075490 |
|> --------------------------------------------------------------------------
|> //
|> // brokenNested.C
|> //
|> // Illustrates the brokenness of C++ 2.1's treatment of
|> // nested typedefs.
|> //
|> // This program prints:
|> // X
|> // Y
|> // Y
|> //
|> // If you change the name "NotSameName" to "SameName",
|> // then it prints:
|> // X
|> // X
|> // X
|> //
|> // i.e. the typedef inside class Enclose has no effect in this case
|> // (no warning!).
|> //
|>
|> #include <iostream.h>
|>
|> class NotSameName {
|> public:
|> char* type() { return "X"; }
|> };
|>
|> class Y {
|> public:
|> char* type() { return "Y"; }
|> };
|>
|> class Enclose {
|> public:
|> typedef Y SameName;
|> SameName a;
|> };
|>
|> class Derived : public Enclose {
|> public:
|> SameName b;
|> };
|>
|> int main()
|> {
|> NotSameName obj;
|> Enclose e;
|> Derived d;
|>
|> cout << obj.type() << endl; // X
|> cout << e.a.type() << endl; // X or Y ? (should be Y)
|> cout << d.b.type() << endl; // X or Y ? (should be Y)
|>
|> return 0;
|> }
|> --
|> --------------------------------------------------------------------------
|> | Johan Bengtsson, Telia Research AB, Aurorum 6, S-951 75 Lulea, Sweden |
|> | Johan.Bengtsson@lulea.trab.se; Voice:(+46)92075471; Fax:(+46)92075490 |
|> --------------------------------------------------------------------------
If I compile above code as is using Cfront 2.1 on a Sun4 I get as output:
fanout /users/ub/linden/cxx/hldiv 205 % CC2.1 testtypedef.cxx -o ttd
"testtypedef.cxx", line 27: warning: obj used but not set
"testtypedef.cxx", line 28: warning: e used but not set
"testtypedef.cxx", line 29: warning: d used but not set
fanout /users/ub/linden/cxx/hldiv 206 % ttd
X
Y
Y
So that is what is expected, and not the wrong result that would indicate that typedef is
broken. Odd...
Hans.
--
//////////////////////////////////////////////////////////////////////////////
/ Hans van der Linden. Put your favourite slogan/disclaimer/saying/joke here:
/ e-mail: linden@fanout.et.tudelft.nl or JThvdLinden@et.tudelft.nl /
//////////////////////////////////////////////////////////////////////////////