Topic: Self & Inherited


Author: AllanW@my-dejanews.com
Date: 1999/01/19
Raw View
In article <36A37677.ECC627D7@matfys.lth.se>,
  Petter Urkedal <petter@matfys.lth.se> wrote:
> Siemel Naran wrote:
> >
> > Also, which 'base' should be chosen here?
> >
> > class Base { };
> > struct base { };
> > class Final : public base { typedef base Base; };
>
> In you example the typedef does not affect the base class, so
> I assume you meant
>
>   class Final : public base { typedef Base base; };
>
> or vice versa.  The typedef is a local definition, which shadows
> the global, and thus the derivation is from `base'.  However, I think
> you just pointed out a backwards-compatibility problem, since the
> behaviour in such cases would have to be changed from the present.
> To bad...

Another problem is that it changes the way C++ compilers work. With the
exception of templates, most of C and C++ is designed to allow compilers
to work in a single pass. For instance, this is illegal:
    myClass abc; // Declare a variable of type myClass
    struct myClass { int i; }; // and then define the type
because a single-pass definition can't instanciate the class it hasn't
seen yet. (In some other language this would theoretically be possible,
but the compiler would have to scan the entire source file for definitions,
and then scan it again for declarations.

In this code:
    struct myClass : public myBase {
        // ... lots and lots of stuff here ...
        typedef yourClass myBase;
    };
the base class doesn't make sense until we've already begun parsing the
class type.

> > Maybe something like this would be nice.
> >
> > template <class T> class Base { };
> > class Final : public base=Base<std::pair<int,int> > { };

This is much better, from the perspective I've shown above.
    struct myClass : public myBase = yourClass {
        // ...
    };
This doesn't require a significant amount of read-ahead. As soon as
we've seen "myBase = yourClass" we know what the class's derivation
is, and we also have an extra symbol which we will use to create a
typedef. Much easier to implement.

This also solves the problem quoted at the top:
    class Base { };
    struct base { };
    class Final : public base = Base {
        // typedef Base base;  // Equivalent effect to "base=" above
        base myBase;           // myBase is of type Base
    };
Here, the base class is Base, and there is a local typedef of base
which resolves to Base. Global class base is "shadowed."

> Easy to parse, backwards compatible, looks like default template
> parameters...  And yes, no `base' keyword...  Good!

----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/01/20
Raw View
In article <780keh$ncr$1@nnrp1.dejanews.com>,  <AllanW@my-dejanews.com> wrote:
>*WHAT* common misconception?
>
>Does anyone that reads this newsgroup have the misconception that C++
>compilers can't do multiple inheritance?
>
>Mr. Minnoy and Mr. Naran were discussing the addition of a new keyword
>to C++, and were discussing how it would work. Since it's job would be
>to identify *THE* base class, and since MI has *MULTIPLE* base classes,
>they stated that the (proposed, new, never been done before) keyword
>wouldn't be useful in the presence of multiple inheritance.
>
>Since the discussion was about a hypothetical (proposed, new, never
>been done before) keyword, how could there be a COMMON MISCONCEPTION?
>
The misconception that comes up every time this subject is discussed:
that MI somehow causes a problem for a general 'inherited' keyword.
[And various suggestions for a 'inherited' keyword come up several
times a year].

Implicit in the Minnoy and Naran proposal is the acceptance of this
supposed problem, else they would NOT have explicitly excluded the MI
case from their proposal.


In fact, I would consider an 'inherited' keyword that specifically
excluded MI to be flawed.  All that is necessary is that it use the
*exact* same lookup rules as the compiler *already* has to use for
looking up a name not directly defined in the current class.  If such
a keyword is added, that is really the only rational way to do it.

>> If it were built into the compiler, it should be handled as it is in these
>> cases.
>
>This IS built in to any conforming compiler, and it IS handled as in
>those cases. Has nothing to do with the (proposed, new, never been
>done before) keyword.

Well, except that the 'inherited' keyword, if added, *should* use the
same mechanism.  That is the point.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/01/20
Raw View
On 19 Jan 99 05:33:48 GMT, Fergus Henderson <fjh@cs.mu.OZ.AU> wrote:

>This proposal is NOT new.  What the above posters are proposing is
>basically the same thing that has been proposed before on MANY occaisions.
>Indeed, a proposal basically identical to this one, bar the spelling,
>was used by Bjarne Stroustrup as a canonical example of why not all
>good proposals are accepted.

So why was this "good" proposal not accepted?  There must be a reason,
ever small.  Please explain more.  Mainly, I'm curious to know why.

The stuff in D&E talks about the "__base" keyword, but before anyone
realized that you could put a typedef in the class definition.  The
"__base" keyword we're talking about here is in spite of the fact
that we know we can write the typedef explicitly.  It's just that we
don't want to write the inherited class name twice, because it is so
long.  The D&E does not address this issue.  Eg,
   class Derived : public ... { };
where "..." is a long name, possibly using namespaces and templates
with many arguments.

To me, it seems that the "__base" keyword doesn't solve a big problem.
It just saves us having to write out a long name twice.  A good editor
could do the work for us.  The rule that you can use a typedef name
before it is defined can certainly be made to work, but it complicates
the rules of the standard, makes life hard for the compiler writer,
and does not solve a pressing problem.  But if the problem turns out
to be sufficiently serious, it should receive more serious
consideration.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/01/20
Raw View
sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:

>On 19 Jan 99 05:33:48 GMT, Fergus Henderson <fjh@cs.mu.OZ.AU> wrote:
>
>>This proposal is NOT new.  What the above posters are proposing is
>>basically the same thing that has been proposed before on MANY occaisions.
>>Indeed, a proposal basically identical to this one, bar the spelling,
>>was used by Bjarne Stroustrup as a canonical example of why not all
>>good proposals are accepted.
>
>So why was this "good" proposal not accepted?  There must be a reason,
>ever small.  Please explain more.  Mainly, I'm curious to know why.

I think the main reason was the desire to keep the language simple.
But I don't really know much more than what's in D&E.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "Binaries may die
WWW: <http://www.cs.mu.oz.au/~fjh>  |   but source code lives forever"
PGP: finger fjh@128.250.37.3        |     -- leaked Microsoft memo.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/01/18
Raw View
Petter Urkedal wrote:
>
> Chris Minnoy wrote:
> >
> > Petter Urkedal wrote:
> >
> > >And for that reason I wouldn't want an `inherited' (or `base')
> > >keyword.
> >
> > As you mentioned in your example, it's a nightmare typing and
> > retyping very long names of baseclasses, especially if they
> > are template based. That's why I do wanna a 'inherited' keyword.
> > Also, because most editors show c++ keywords highlighted, so
> > you would notice it better if you forgot to initialise your baseclass
> > in a constructor. The keyword 'inherited' can also be found in
> > Delphi, where they use it very frequently. In Delphi however there
> > isn't multiple inheritence, so they do not have to consider when
> > or not to use it.
>
> Yes.  My point was, however, that the problem can also be resolved
> without the new keyword, or any change of the syntax, and it would
> work as well for multiple inheritance.
>
> > Could you explain your proposal with those templates a bit more.
> > It's not realy clear what you mean by that.
>
> The template was only a present backdoor to the proposed added
> functionality,
>
>     template< typename inherited1 = ..., typename inherited2 = ...>
>     struct derived : inherited1, inherited2 { ... };
>
> and not recommended.  The proposed extension is to make code like
> this legal:
>
>     struct derived : inherited1, inherited2 {
>         typedef ... inherited1;
>         typedef ... inherited2;
>         ...
>     };
>

How would you handle typedefs which are inherited from base classes?
For example:

class X {};

class A
{
public:
  typedef X type;
};

class B:
  public type, // should B find A::type?
  public A
{
};

> To be more specific, before the compiler parses the base-specifiers
> it should parse the body of the class for type identifiers (without
> regarding the definitions themselves).  If one of the base specifiers
> depends on a type in the class body, this type is determined before
> the base-classes --- of course under the condition that it does not
> depend on them.

Try this (with the definitions above):

class type {};

class C:
  public A
{
  typedef type Foo;
};

Now, Foo is dependent on A (since type is A::type). However,
not having identified A as base class, you won't see that - it
looks as if type were just ::type. That is, you cannot find out
if type depends on A, unless you know A.

Even worse:

typedef A type;

class D:
  public Foo
{
  typedef type Foo;
};

Now, resolving without base class finds Foo is just ::type,
which, again, is A. But A itself contains a type "type", which
is typedefed to X. Since A::type hides ::type, A::type
should obviously be used. But that means, D doesn't derive
from A, but from X, which doesn't have that typedef, therefore
the global typedef should be used, which says "type" is "A",
therefore D is derived from A...

A possible way out could be the following algorithm:

1. At first, find all typedefs inside the class definition,
   and try to resolve them. Some will remain unresolved.
   However, remember the names of all (resolved and unresolved)
   names.
2. Then, given the names, look at the base specifier list.
   For each base which is not a typedef from inside the class,
   include the type definitions from that class (which are all
   resolved) to your typedef list. If that class cannot be found,
   report an error.
3. With this extended list, try to resolve as many unresolved
   typedefs as possible.
4. If there's still an unresolved base class, go back to 2
5. If now any typedef is left unresolved, report an error.
6. With the final base class list, try to resolve all typedefs
   again, with taking the base class list as fixed (i.e.
   independant from typedefs). If this fails or gives a different
   result than before, report the error.
   Also try to resolve all typenames used in the base initializer
   list again. Again, this may not fail or change the meaning.
   This pass is to detect ambiguities like the following:

   struct E { typedef int type; };
   struct F { typedef E type; };
   struct G: E, Foo { typedef type Foo; };

   During the "resolving loop", the compiler would only
   find "typedef A foo", and therefore would fail to see the
   ambiguity. The "no change"-part is to avoid errors
   like my example class D.
7. Now all typedefs and base classes are determined; the rest
   of the class can be analysed as usual.

This would of course be a quite complex algorithm. While compilers
of course can implement it, I'm not sure if it would do any good
to programmers (except being able to produce even more cryptic
programs ;-))

And there may be problems with this still to discover.
Indeed, it's even likely.

>
> At present we can write
>
>     struct { void f() { i=1; } int i; };
>
> whereas the above is more in the spirit of
>
>     struct { my_int i; typedef int my_int; };
>
> That is, types may be evaluated in parallel within the class body, and
> be visible to the base-specifiers.

Another problem with this: How to treat inner classes?

Examples:

class A
{
  class B: public C {}; // Should this be allowed?
  typedef C some_type;  // and this?
  class C {};
};

This could cause changes of the meaning of legal code:

class A {};

class B
{
  typedef A outerA;
  class X: public A {};
  class A {};
  typedef A innerA;
  class Y: public A {};
};

Currently, outerA is ::A, and X derives from ::A, while
innerA is B::A, and Y derived from B::A.
With your proposed change, both outerA and innerA would
result in B::A, and both X and Y would derive from B::A.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Petter Urkedal <petter@matfys.lth.se>
Date: 1999/01/18
Raw View
Siemel Naran wrote:
>
> Also, which 'base' should be chosen here?
>
> class Base { };
> struct base { };
> class Final : public base { typedef base Base; };

In you example the typedef does not affect the base class, so
I assume you meant

  class Final : public base { typedef Base base; };

or vice versa.  The typedef is a local definition, which shadows
the global, and thus the derivation is from `base'.  However, I think
you just pointed out a backwards-compatibility problem, since the
behaviour in such cases would have to be changed from the present.
To bad...

> Maybe something like this would be nice.
>
> template <class T> class Base { };
> class Final : public base=Base<std::pair<int,int> > { };

Easy to parse, backwards compatible, looks like default template
parameters...  And yes, no `base' keyword...  Good!  (Does someone
with an influence see this :-))

Christopher Eltschka wrote:
>
> How would you handle typedefs which are inherited from base classes?

I wouldn't.  The scheme is to

  * parse for identifiers, and bind them to unparsed definitions

  * resolve the base class types (without considering any inherited
    identifiers) and _only_ those types and static constants which are
    needed in doing so.

  * resolve the rest of the class

  * if a base class now depends on an identifier (from an outer scope)
    which is shadowed by an identifier in a base class, the code is
    _ill-formed_.

The last point makes the language consistent with scoping rules. This
should clear up many of your following examples, though some questions
may remain.  However, the point was to investigate an alternative to a
somewhat limited `inherited' keyword, and probably Siemel Naran's
suggestion above is better.

 -petter.

--
[- http://matfys.lth.se/~petter/ -]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1999/01/19
Raw View
In article <199901151647.KAA01528@centurion.flash.net>,
  blargg@flash.net (Gargantua Blargg) wrote:
> In article <slrn79na49.rsi.sbnaran@localhost.localdomain>,
> sbnaran@uiuc.edu wrote:
>
> > On 12 Jan 1999 18:28:32 GMT, Petter Urkedal <petter@matfys.lth.se> wrote:
> > >Chris Minnoy wrote:
> ...
> > >> Ofcourse, when you have multiple inheritance, you can not typedef
> > >> Inherited, because what should that be?
> > >> Also, when there is no baseclass there shouldn't be a Inherited-typedef.
> > >
> > >And for that reason I wouldn't want an `inherited' (or `base')
> > >keyword.
> >
> > Nope.  The "__base" does not apply to multiple inherited classes.  In
> > this case, users should defined their own base typedefs.  This is a
> > good rule because multiple inheritance is rare.  The common case of
> > single inheritance would benefit greatly from this "__base" typedef.
> ...
>
> Why is this common misconception constantly propagated? Why can't multiple
> inheritance be handled? (except for base initializers, of course)

*WHAT* common misconception?

Does anyone that reads this newsgroup have the misconception that C++
compilers can't do multiple inheritance?

Mr. Minnoy and Mr. Naran were discussing the addition of a new keyword
to C++, and were discussing how it would work. Since it's job would be
to identify *THE* base class, and since MI has *MULTIPLE* base classes,
they stated that the (proposed, new, never been done before) keyword
wouldn't be useful in the presence of multiple inheritance.

Since the discussion was about a hypothetical (proposed, new, never
been done before) keyword, how could there be a COMMON MISCONCEPTION?

[SNIP: Demonstration of multiple inheritance, including an explanation
of what an ambiguous call is.]
> If it were built into the compiler, it should be handled as it is in these
> cases.

This IS built in to any conforming compiler, and it IS handled as in
those cases. Has nothing to do with the (proposed, new, never been
done before) keyword.

It seems as if you didn't read the article -- or even the section that
you quoted -- before you responded to that one out-of-context statement.

----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/01/19
Raw View
AllanW@my-dejanews.com writes:

>blargg@flash.net (Gargantua Blargg) wrote:
>> sbnaran@uiuc.edu wrote:
>> > Petter Urkedal <petter@matfys.lth.se> wrote:
>> > >Chris Minnoy wrote:
>> ...
>> > >> Of course, when you have multiple inheritance, you can not typedef
>> > >> Inherited, because what should that be?
...
>> > >And for that reason I wouldn't want an `inherited' (or `base')
>> > >keyword.
>> >
>> > Nope.  The "__base" does not apply to multiple inherited classes.  In
>> > this case, users should defined their own base typedefs.  This is a
>> > good rule because multiple inheritance is rare.
>> ...
>> Why is this common misconception constantly propagated? Why can't multiple
>> inheritance be handled? (except for base initializers, of course)
>
>*WHAT* common misconception?

The common misconception that if a compiler were to provide an
"Inherited" typedef (or "inherited" keyword, or a "super" keyword, etc.)
for accessing inherited members, it would have to throw up its hands in
the case of multiple inheritence.

>Mr. Minnoy and Mr. Naran were discussing the addition of a new keyword
>to C++, and were discussing how it would work. Since it's job would be
>to identify *THE* base class, and since MI has *MULTIPLE* base classes,
>they stated that the (proposed, new, never been done before) keyword
>wouldn't be useful in the presence of multiple inheritance.

This proposal is NOT new.  What the above posters are proposing is
basically the same thing that has been proposed before on MANY occaisions.
Indeed, a proposal basically identical to this one, bar the spelling,
was used by Bjarne Stroustrup as a canonical example of why not all
good proposals are accepted.

>Since the discussion was about a hypothetical (proposed, new, never
>been done before) keyword, how could there be a COMMON MISCONCEPTION?

Your mistake is to assume that this keyword has never been proposed before.
Try a DejaNews search.

>[SNIP: Demonstration of multiple inheritance, including an explanation
>of what an ambiguous call is.]

... and including an explanation of how a compiler should handle the
use of an "inherited" keyword in multiple inheritence situations,
contrary to <sbnaran@uiuc.edu>'s suggestion that the compiler just
give up in such cases.

As for Gargantua Blargg's question, "Why is this common misconception
constantly propagated?", I think the answer is just that it happens to
be the first thing that pops into a lot of people's minds when they
think about the problem.  The moral is that defenders of subtle truths
must be eternally vigilant!  ;-)

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "Binaries may die
WWW: <http://www.cs.mu.oz.au/~fjh>  |   but source code lives forever"
PGP: finger fjh@128.250.37.3        |     -- leaked Microsoft memo.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: blargg@flash.net (Gargantua Blargg)
Date: 1999/01/17
Raw View
In article <slrn79na49.rsi.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:

> On 12 Jan 1999 18:28:32 GMT, Petter Urkedal <petter@matfys.lth.se> wrote:
> >Chris Minnoy wrote:
...
> >> Ofcourse, when you have multiple inheritance, you can not typedef
> >> Inherited, because what should that be?
> >> Also, when there is no baseclass there shouldn't be a Inherited-typedef.
> >
> >And for that reason I wouldn't want an `inherited' (or `base')
> >keyword.
>
> Nope.  The "__base" does not apply to multiple inherited classes.  In
> this case, users should defined their own base typedefs.  This is a
> good rule because multiple inheritance is rare.  The common case of
> single inheritance would benefit greatly from this "__base" typedef.
...

Why is this common misconception constantly propagated? Why can't multiple
inheritance be handled? (except for base initializers, of course)

    struct Base1 {
        virtual void foo();
        void common();
    };

    struct Base2 {
        virtual void bar();
        void common();
    };

    struct Derived_ : Base1, Base2 {
        typedef Derived_ inherited;
    };

    struct Derived : Derived {
        virtual void foo() { inherited::foo(); } // un-ambiguous
        virtual void bar() { inherited::bar(); } // un-ambiguous
        void common()
        {
            inherited::common(); // ambiguous, flaged as compile-time error
            Base1::common(); // OK
            Base2::common(); // OK
        }
    };

If it were built into the compiler, it should be handled as it is in these
cases.

--
"I don't like my language watered down" - Ani DiFranco

Gargantua Blargg | blargg@flash.net | http://www.flash.net/~blargg/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/01/17
Raw View
On 15 Jan 1999 16:48:22 GMT, Petter Urkedal <petter@matfys.lth.se> wrote:

>    struct derived : inherited1, inherited2 {
> typedef ... inherited1;
> typedef ... inherited2;
> ...
>    };
>
>To be more specific, before the compiler parses the base-specifiers
>it should parse the body of the class for type identifiers (without
>regarding the definitions themselves).  If one of the base specifiers
>depends on a type in the class body, this type is determined before
>the base-classes --- of course under the condition that it does not
>depend on them.

Yes, this is better than making an automatic typedef "__base",
as it handles multiple inheritance well, and clients get to say
what the base class is called (ie, they can call it "base",
"base1", which are easier to type and read), and lets us decide
what accessibility we want for the typedef.

One can also use this typedef idea to make writing of functions
easier.  Eg, suppose you had this function

template <class Container>
typename Container::value_type
function
   (const Container& container, typename Container::value_type value)
{
   return *container.begin()+value;
}

With the pre-emptive typedefs, we could do this:

template <class Container>
Value function(const Container& container, Value value)
{
   typedef typename Container::value_type Value;
   return *container.begin()+value;
}


One problem with the typedef idea is that it complicates the
compilation of classes.  Instead of parsing typedefs and static
const integrals from top to bottom, the compiler has to parse
them at the same time, or rather in order of dependency.  Here's
a pathological example:

class Final : public base
{
   typedef Base<k> base;
   static const int k=3;
};


Also, which 'base' should be chosen here?

class Base { };
struct base { };
class Final : public base { typedef base Base; };


Maybe something like this would be nice.

template <class T> class Base { };
class Final : public base=Base<std::pair<int,int> > { };


--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Boris Schaefer <sbo@psy.med.uni-muenchen.de>
Date: 1999/01/14
Raw View
Petter Urkedal <petter@matfys.lth.se> writes:

| Now, this visibility of typedefs will give about the same gain in
| code-size that the new keyword `__base' would give.  In addition
| it also applies in cases of multiple inheritance.  E.g.
|
|     struct X : base1, base2 {
|  typedef typename
|      some<complex<expression>, which>::specifies base1;
|  typedef a_bit<simpler> base2;
|  // ...
|     };
|
| The C++ syntax stays the same.

And it will be hard to parse.  A way to account for this might be:

struct X, typedef A base0, typedef B base1 : base0, base1
{ };

This wouldn't break existing code and it would be easy to parse.  It's
also more consistent with the existing philosphy that types must be
defined before they can be used.

--
Boris Schaefer -- sbo@psy.med.uni-muenchen.de

Law of Continuity:
 Experiments should be reproducible.  They should all fail the same way.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Petter Urkedal <petter@matfys.lth.se>
Date: 1999/01/15
Raw View
Chris Minnoy wrote:
>
> Petter Urkedal wrote:
>
> >And for that reason I wouldn't want an `inherited' (or `base')
> >keyword.
>
> As you mentioned in your example, it's a nightmare typing and
> retyping very long names of baseclasses, especially if they
> are template based. That's why I do wanna a 'inherited' keyword.
> Also, because most editors show c++ keywords highlighted, so
> you would notice it better if you forgot to initialise your baseclass
> in a constructor. The keyword 'inherited' can also be found in
> Delphi, where they use it very frequently. In Delphi however there
> isn't multiple inheritence, so they do not have to consider when
> or not to use it.

Yes.  My point was, however, that the problem can also be resolved
without the new keyword, or any change of the syntax, and it would
work as well for multiple inheritance.

> Could you explain your proposal with those templates a bit more.
> It's not realy clear what you mean by that.

The template was only a present backdoor to the proposed added
functionality,

    template< typename inherited1 = ..., typename inherited2 = ...>
    struct derived : inherited1, inherited2 { ... };

and not recommended.  The proposed extension is to make code like
this legal:

    struct derived : inherited1, inherited2 {
 typedef ... inherited1;
 typedef ... inherited2;
 ...
    };

To be more specific, before the compiler parses the base-specifiers
it should parse the body of the class for type identifiers (without
regarding the definitions themselves).  If one of the base specifiers
depends on a type in the class body, this type is determined before
the base-classes --- of course under the condition that it does not
depend on them.

At present we can write

    struct { void f() { i=1; } int i; };

whereas the above is more in the spirit of

    struct { my_int i; typedef int my_int; };

That is, types may be evaluated in parallel within the class body, and
be visible to the base-specifiers.

 -petter.

--
[- http://matfys.lth.se/~petter/ -]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Petter Urkedal <petter@matfys.lth.se>
Date: 1999/01/15
Raw View
Boris Schaefer wrote:
>
> Petter Urkedal <petter@matfys.lth.se> writes:
>
> | Now, this visibility of typedefs will give about the same gain in
> | code-size that the new keyword `__base' would give.  In addition
> | it also applies in cases of multiple inheritance.  E.g.
> |
> |     struct X : base1, base2 {
> |       typedef typename
> |           some<complex<expression>, which>::specifies base1;
> |       typedef a_bit<simpler> base2;
> |       // ...
> |     };
> |
> | The C++ syntax stays the same.
>
> And it will be hard to parse.  A way to account for this might be:
>
> struct X, typedef A base0, typedef B base1 : base0, base1
> { };
>
> This wouldn't break existing code and it would be easy to parse.  It's
> also more consistent with the existing philosphy that types must be
> defined before they can be used.

I though about something of the kind, but couldn't find a good syntax.
Not bad, -- reminds me of the old K&R function prologs.

And I have comments on your criticism.

Ad. `existing philosophy':  I'm not so sure.  At present we can
roughtly summarize the condition that a term can be used in a
definition as

  ------------in namespace scope-----------in class scope-------------
  data        must be declared previously  must be declared in class
  function    must be declared previously  must be declared in class
  type        must be defined previously   must be defined previously

To complete the symmetry the bottom right line should say `in class'.
I.e. we must put the line between class-scope/namespace-scope, rather
than between type/non-type.

This is quite natural, since a namespace is `unbound' (definitions can
be distributed) whereas a class is `bound' (its complete definition
in terms of data/function declarations and type definitions, resides in
a single block.)

Thus a reordering makes sense within a class scope, but not within a
namespace scope.

Ad. `hard to parse':  Yes.  Notice, however, that at the present parsing
of in-class functions definitions must be posponed until the class
itself is parsed, so this is similar.  If we add an extra pass, we could

  * scan the class for type names and bind them to their yet unparsed
    definitions.  (Notice that the identifiers defined in a `typedef',
   `struct' or `class' are easy to extract without depth-parsing.)

  * Then each type definition is parsed, starting with the base classes,
    and recursively parsing dependent types when needed.

It depends, of course, on how the actual compiler is implemented, and I
shall not claim it's easy.

 -petter.

--
[- http://matfys.lth.se/~petter/ -]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/01/13
Raw View
On 12 Jan 1999 18:28:32 GMT, Petter Urkedal <petter@matfys.lth.se> wrote:
>Chris Minnoy wrote:

>In that case the keyword would be `self' rather than `Self'.  I like
>the idea.  But it breaks old code -- I guess a lot of people are
>already using `self' as an identifier, especially since the pratice
>you describe is rather sensible.  Notice also that the template
>parameters to the class being defined are not madatory, so the problem
>of long template class names is less here then for the inherited
>classes, which you also mention.

How about "__self"?  Names beginning with two underscores are reserved
anyway.


>> Ofcourse, when you have multiple inheritance, you can not typedef
>> Inherited, because what should that be?
>> Also, when there is no baseclass there shouldn't be a Inherited-typedef.
>
>And for that reason I wouldn't want an `inherited' (or `base')
>keyword.

Nope.  The "__base" does not apply to multiple inherited classes.  In
this case, users should defined their own base typedefs.  This is a
good rule because multiple inheritance is rare.  The common case of
single inheritance would benefit greatly from this "__base" typedef.


>This mechanism is already avaliable in the standard, since we
>could replace the above with
>
>    template< typename Placeholder1, typename Placeholder2,
>              typename Expr,
>       typename base =
>    binary_function< typename Placeholder1::result_type,
>                                   typename Placeholder2::result_type,
>                            typename Expr::result_type > > {
>    struct binary_lambda_function : base
>        // ...
>    };

But this may be confusing for maintainance.  Maintainers wonder
what the default template argument means.  Usually, default
template arguments specify policy.  So programmers think of the
third argument as a kind of policy argument, which only leads to
confusion.

Moreover, if we have a class that is not templated, then
templatizing it prevents as much code as possible from being
compiled at compile time.


>However, the `base' template argument is not protected from being
>specified by the user of the class.  Therefore, and because of easier
>syntax, it would be nice if typedefs in the class was visible in
>the base-specifiers, `as if' they appeared as template arguments with
>default values.


--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Chris Minnoy" <cminnoy@starlab.net>
Date: 1999/01/13
Raw View
Petter Urkedal wrote:

>Let me just add that (and I thing you also consider this)
>`A_Very_Long_Name' may also be `A< Very<Long, Template>, Class<Name> >',
>even with `typename in_order_to<Access, A>::dependent_type'.

Yes, I did mean  template classes to.

>In that case the keyword would be `self' rather than `Self'.

That's only a matter of taste. But to keep consistancy with the
rest of the standard, yes.

> But it breaks old code -- I guess a lot of people are
>already using `self' as an identifier,..

Can be, but that shouldn't keep us from changing things.
Having code changed that uses the keyword self can not be to
hard.

>And for that reason I wouldn't want an `inherited' (or `base')
>keyword.

As you mentioned in your example, it's a nightmare typing and
retyping very long names of baseclasses, especially if they
are template based. That's why I do wanna a 'inherited' keyword.
Also, because most editors show c++ keywords highlighted, so
you would notice it better if you forgot to initialise your baseclass
in a constructor. The keyword 'inherited' can also be found in
Delphi, where they use it very frequently. In Delphi however there
isn't multiple inheritence, so they do not have to consider when
or not to use it.
I prefer the keyword 'inherited' above 'base'. Inherited has more
the notion of a call to a function, which indeed is what you are
doing while initialising constructors. The base keyword can be
used to mean something else.
Ofcourse, in the case of calling a function out of the base class,
the difference between inherited and base becommes suptile.
eg.

inherited::f();
base::f();

Could you explain your proposal with those templates a bit more.
It's not realy clear what you mean by that.

Chris Minnoy
cminnoy@starlab.net
http://www.starlab.net





[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Petter Urkedal <petter@matfys.lth.se>
Date: 1999/01/13
Raw View
Siemel Naran wrote:
>
> How about "__self"?  Names beginning with two underscores are reserved
> anyway.
>
Good idea in some sense, but wouldn't the C++ syntax start to look
very ad-hoc?  Even if a `self' keyword was added, old code would
still compile if guarded with a `#define'-`#undef'-pair,

    #define self some_unique_name
    [...]
    #undef self

and all access from new programs must go through a the new identifier.
On the other hand, if `__self' was introduced, I guess the first thing
we would start to do is to

    #define self __self

in some header.  So the two possibilites mostly equivalent.  I don't
know if there is reason enough to introduce eighter keyword, though.
You can always drop the template arguments for the class being
defined.

However, instead of the new keywords `constructor' and `destructor'
suggested in `Designating constructors and destructors', `self' and
`~self' could be a better alternative, since it is closer to the
present syntax for ctors and dtors.  And it would have a double purpose.

> >> Ofcourse, when you have multiple inheritance, you can not typedef
> >> Inherited, because what should that be?
> >> Also, when there is no baseclass there shouldn't be a Inherited-typedef.
> >
> >And for that reason I wouldn't want an `inherited' (or `base')
> >keyword.
>
> Nope.  The "__base" does not apply to multiple inherited classes.  In
> this case, users should defined their own base typedefs.  This is a
> good rule because multiple inheritance is rare.  The common case of
> single inheritance would benefit greatly from this "__base" typedef.

Please, see this in relation to my alternative (see below).

> >This mechanism is already avaliable in the standard, since we
> >could replace the above with
> >
> >    template< typename Placeholder1, typename Placeholder2,
> >              typename Expr,
> >             typename base =
> >                 binary_function< typename Placeholder1::result_type,
> >                                   typename Placeholder2::result_type,
> >                                  typename Expr::result_type > > {
> >    struct binary_lambda_function : base
> >        // ...
> >    };
>
> But this may be confusing for maintainance.  Maintainers wonder
> what the default template argument means.  Usually, default
> template arguments specify policy.  So programmers think of the
> third argument as a kind of policy argument, which only leads to
> confusion.

I wouldn't advice this technique, eigther.  The example above was
included to show that the mechanism I was suggesting is already
available in the compiler.  The compiler only has to decide which
typedefs should be visible to the base specifiers, namely those
types which do not depend on the base classes.

> Moreover, if we have a class that is not templated, then
> templatizing it prevents as much code as possible from being
> compiled at compile time.

Visibility of typedefs to base-class specifiers will, however, not
affect the amount of code which can be pre-compiled.

Now, this visibility of typedefs will give about the same gain in
code-size that the new keyword `__base' would give.  In addition
it also applies in cases of multiple inheritance.  E.g.

    struct X : base1, base2 {
 typedef typename
     some<complex<expression>, which>::specifies base1;
 typedef a_bit<simpler> base2;
 // ...
    };

The C++ syntax stays the same.

 -petter.

--
[- http://matfys.lth.se/~petter/ -]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/01/14
Raw View
On 13 Jan 1999 17:32:26 GMT, Petter Urkedal <petter@matfys.lth.se> wrote:
>Siemel Naran wrote:

>> How about "__self"?  Names beginning with two underscores are reserved
>> anyway.
>>
>Good idea in some sense, but wouldn't the C++ syntax start to look
>very ad-hoc?  Even if a `self' keyword was added, old code would
>still compile if guarded with a `#define'-`#undef'-pair,

The C++ standard would say nothing about the use of "pair".  If
the class author wants to do this, that's their business.
Perhaps the typedefs "__self" and "__base" should be private.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Chris Minnoy" <cminnoy@starlab.net>
Date: 1999/01/12
Raw View
Proposal
=======

Ever written a template class with a huge name?
Sure you did, so you discovered the huss and fuss of writting
the classname over and over again.
Ever where wondering where you left your copy constructor?
Maybe you couldn't find it between all your init constructors.
A sollution to that problem is this.

class A_Very_Long_Name
{
    typedef A_Very_Long_Name Self;

public:
    A_Very_Long_Name();
    A_Very_Long_Name( const Self& );
    //...
};

Now you never have to write the name of your class over and over
again in parameter definitions. As you can see I made the typedef
private, so no confusion can excist between this Self and the Self's
defined in derived classes. Self is also NOT known outside the class!

If you inherit from a class and you redefine a copy constructor, you
have to call the copy constructor of the base class. That implies that
you have to write the name of base class. Again, a solution
to this problem could be.

class Derived : public A_Very_Long_Name
{
    typedef Derived Self;
    typedef Inherited A_Very_Long_Name;

public:
    Derived( const Self& );
};

Derived::Derived( const Self& rhs )
    : Inherited( rhs )
{
    // ...
}

Now, you don't have to bother with that long name again.
So, it would be nice if the compiler forsaw those typedefs by default
in classes. This doesn't conflict with any other C++-rule (as far as I
know).
Ofcourse, when you have multiple inheritance, you can not typedef
Inherited, because what should that be?
Also, when there is no baseclass there shouldn't be a Inherited-typedef.
Self can always be supplied.

Chris Minnoy
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Petter Urkedal <petter@matfys.lth.se>
Date: 1999/01/12
Raw View
Chris Minnoy wrote:

> class A_Very_Long_Name
> {
>     typedef A_Very_Long_Name Self;
>
> public:
>     A_Very_Long_Name();
>     A_Very_Long_Name( const Self& );
>     //...
> };

Let me just add that (and I thing you also consider this)
`A_Very_Long_Name' may also be `A< Very<Long, Template>, Class<Name> >',
even with `typename in_order_to<Access, A>::dependent_type'.

[...]
> So, it would be nice if the compiler forsaw those typedefs by default
> in classes. This doesn't conflict with any other C++-rule (as far as I
> know).

In that case the keyword would be `self' rather than `Self'.  I like
the idea.  But it breaks old code -- I guess a lot of people are
already using `self' as an identifier, especially since the pratice
you describe is rather sensible.  Notice also that the template
parameters to the class being defined are not madatory, so the problem
of long template class names is less here then for the inherited
classes, which you also mention.


> Ofcourse, when you have multiple inheritance, you can not typedef
> Inherited, because what should that be?
> Also, when there is no baseclass there shouldn't be a Inherited-typedef.

And for that reason I wouldn't want an `inherited' (or `base')
keyword.  However, I clearly see the problem with very long expressions
for inherited template classes with dependent template arguments, as in
this piece of code (I have worse examples):

    template< typename Placeholder1, typename Placeholder2,
              typename Expr >
    struct binary_lambda_function
        : binary_function< typename Placeholder1::result_type,
                           typename Placeholder2::result_type,
                           typename Expr::result_type > {
        typedef binary_function< typename Placeholder1::result_type,
                                 typename Placeholder2::result_type,
                                 typename Expr::result_type > base;
 // ...
    };

I would rather propose that a typedef inside the class is visible
when parsing the base class specifiers.  However, we would require
that the typedefs are treated as template parameters, so that
`typename' keyword is required where proper.  And also, they may
not depend upon types withing the base-class itself.  (Infinite
regress for types is already possible in C++, so this would not pose
a new problem.)

This mechanism is already avaliable in the standard, since we
could replace the above with

    template< typename Placeholder1, typename Placeholder2,
              typename Expr,
       typename base =
    binary_function< typename Placeholder1::result_type,
                                   typename Placeholder2::result_type,
                            typename Expr::result_type > > {
    struct binary_lambda_function : base
        // ...
    };

However, the `base' template argument is not protected from being
specified by the user of the class.  Therefore, and because of easier
syntax, it would be nice if typedefs in the class was visible in
the base-specifiers, `as if' they appeared as template arguments with
default values.

 -petter.

--
[- http://matfys.lth.se/~petter/ -]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]