Topic: Ideas for new keywords and features
Author: scorp@btinternet.com (Dave Harris)
Date: 1999/08/02 Raw View
clamage@eng.sun.com (Steve Clamage) wrote:
> It is needed to allow a private section in structs, and to
> allow multiple private and public sections in classes.
In the context I think he meant, "Why are private sections useful if the
compiler is not required to enforce them?"
> Those are not cases of the compiler trusting the programmer.
> They are cases of the programmer writing code having undefined
> semantics in the hopes of fooling the compiler.
The point remains that you cannot generally rely on the compiler for
security guarantees. Ellis and Stroustrup put it well in ARM $11.1c:
Protection is provided by compile-time mechanisms, against
accident, not against fraud or explicit violation.
Where-as Java *is* intended to prevent fraud. The necessary kinds of
undefined semantics are generally not permitted by that language's spec.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
---
[ 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: David R Tribble <david@tribble.com>
Date: 1999/08/02 Raw View
Fergus Henderson wrote:
>
> David R Tribble <david@tribble.com> writes:
>
> >Francis Glassborow wrote:
> >>
> >> Scott McMahan <scott@aravis.softbase.com> writes
> >>> How about a new "microsoft_" namespace, so MS can extend
> >>> their compiler all they want?
> >>
> >> Actually that does not help with the kind of extension microsoft
> >> has. What they need is a #pragma NOTC++ which can be prefixed to
> >> all MFC declarations and definitions.
> >
> > Unfortunately, MS will probably not use a namespace for their
> > libraries, most notably their MFC libraries, for the simple reason
> > that they appear to maintain backwards compatibility at all costs.
>
> Are you talking about source compatibility, or binary compatibility?
Yes. Perhaps I should have said that they appear to maintain
backwardness at all costs.
> Source compatibility could be ensured using the same techniques
> as the standard uses for <stdio.h>. MS could define new header
> files, e.g. <ms/windows.h>, which declared all the symbols inside
> an namespace; the old header files such as <windows.h> file would
> then include the corresponding new one (e.g. <ms/windows.h>) and
> would also have using declarations for all the symbols declared
> therein, to import then into the global namespace.
>
> Binary compatibility could be ensured by putting a bunch of symbol
> aliases in the DLL.
Those would be logical approaches to the problems; we'll see if
Microsoft takes them. (Don't hold your breath. They didn't take
the logical approach of maintaining source code compatibility when
they invented Win32 DLLs.)
BTW, the IP name "ms.com" is registered to Morgan Stanley; guess
what class prefix Microsoft uses. Perhaps Morgan Stanley will feel
compelled to use "Microsoft::" for their library code; "DW::" (from
"Dean Witter") won't work because "dw.com" is registered to
DiamondWare, which sells software applets. Of course, I'm in the
habit of using "Drt::" for my personal code, but I just noticed
that "drt.com" is registered to DRT Systems (but which apparently
has been bought out by CGI Group). But I've got "david.tribble.com"
to fall back on. Oh, and "foo.com" and "xyzzy.com" are already
taken, too...
-- David R. Tribble, david@tribble.com --
[ moderator's note: discussion of who has registered what domain
names is likely to be off-topic for newsgroup comp.std.c++. To
the extent that it might illustrate standards-related problems
it is OK, however. -sdc ]
[ 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: David R Tribble <david@tribble.com>
Date: 1999/08/03 Raw View
David R Tribble wrote:
> BTW, the IP name "ms.com" is registered to Morgan Stanley; guess
> what class prefix Microsoft uses. Perhaps Morgan Stanley will feel
> compelled to use "Microsoft::" for their library code; "DW::" (from
> "Dean Witter") won't work because "dw.com" is registered to
> DiamondWare, which sells software applets. Of course, I'm in the
> habit of using "Drt::" for my personal code, but I just noticed
> that "drt.com" is registered to DRT Systems (but which apparently
> has been bought out by CGI Group). But I've got "david.tribble.com"
> to fall back on. Oh, and "foo.com" and "xyzzy.com" are already
> taken, too...
The moderator (sdc, Steve Clamage?) wrote:
> [ moderator's note: discussion of who has registered what domain
> names is likely to be off-topic for newsgroup comp.std.c++. To
> the extent that it might illustrate standards-related problems
> it is OK, however. -sdc ]
I disagree. Perhaps I blathered on too much about domain names,
but discussions about the naming of third-party libraries are of
interest to a standards newsgroup. Who decides whether a namespace
identifier (or even a class name prefix) is appropriate?
The Java approach is to derive package names from the vendors'
internet domain name, since such names are assigned by a single
international authority and thus guaranteed to be unique. C++
has no such guidelines (other than "don't use 'std'"). I have
suggested in the past that C++ vendors adopt a similar naming
strategy, with no success.
It stands to reason, then, that vendors will grab whatever names
they feel like, and we the users will gripe about the inevitable
name conflicts on newsgroups like news:comp.std.c++. Will it
then be considered a bona fide topic?
-- David R. Tribble, david@tribble.com --
[ 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: scorp@btinternet.com (Dave Harris)
Date: 1999/07/31 Raw View
msalters@lucent.com (Salters) wrote:
> Java is an interpreted language, unlike C++.
Java can be compiled. C++ can be interpreted. I don't know about C++, but
there are a great many Java compilers that produce ordinary native code
executables - I'm not talking about JITs here.
> Therefore, Java doesn't have a compiler. C++ has a compiler, and it
> can determine if a class is used asa final class.
A C++ compiler cannot determine this without seeing the entire program
source, which does not happen until link time. In fact, this is really a
linker issue, not a compiler issue. Further, C++ traditionally uses very
dumb linkers that don't do much global optimisation. Java defines its own
link format and its linkers are traditionally quite smart. In some ways,
C++ has more to gain from "final class" than Java.
Note: I'm not advocating a change to C++ here, just correcting some
reasoning about Java.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
---
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/08/02 Raw View
In article <memo.19990716173052.50899B@btinternet.com>, brangdon@cix.co.uk
wrote:
> msalters@lucent.com (Salters) wrote:
> > Java is an interpreted language, unlike C++.
>
> Java can be compiled. C++ can be interpreted. I don't know about C++, but
> there are a great many Java compilers that produce ordinary native code
> executables - I'm not talking about JITs here.
I can assure you that there are a great many C++ compilers that produce
ordinary native code executables - most definitely :-)
> > Therefore, Java doesn't have a compiler. C++ has a compiler, and it
> > can determine if a class is used asa final class.
>
> A C++ compiler cannot determine this without seeing the entire program
> source, which does not happen until link time. In fact, this is really a
> linker issue, not a compiler issue. Further, C++ traditionally uses very
> dumb linkers that don't do much global optimisation. Java defines its own
> link format and its linkers are traditionally quite smart. In some ways,
> C++ has more to gain from "final class" than Java.
As someone else pointed out, final in Java has very important security
implications (and uses). None are an issue in C++. In that light, I'd say
that final is *essential* in Java, while it isn't in C++. I couldn't
consider C++ having more to gain than Java, then.
In either language, without it, as you say, the only time a class can be
determined as never derived from in the complete program is at link time.
With operating systems that allow code to be dynamically linked in,
essentially "link time" is when the program itself is run by the user. In
general, that isn't a very good time to be going through finding final
classes and optimzing code :-)
> Note: I'm not advocating a change to C++ here, just correcting some
> reasoning about Java.
You may not be advocating a change, but we are (well, some of anyway) :-)
---
[ 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: pelliott@io.com (Paul Elliott)
Date: 1999/07/26 Raw View
My proposal for a C++ extension: nonvirtual.
In order to consider my proposal consider the following:
1) default construction is unnatural for a real object.
In the real world nothing appears from nothing. Ex-nilo
creation only happens in the bible.
Thus to the extent our objects have default constructors,
they do not model objects in the real world!
This is OK for abstraction classes like ABC's, but a class
with an implementation that models something in the real
world should not have a default constructor. (This is not
always practical, but it is an idea we should keep in the
back of our heads, especially when thinking expansively
about the future.)
Now consider the following situation:
class VirBase
{
...
public:
VirBase( ArbParam param );
...
};
class GoodClass : public [ a bunch of classes some of which derive virtually
from VirBase]
{
...
public:
GoodClass( ArbParam param ) : VirBase(param), [other ctors]
{
...
};
...
};
GoodClass is excellent and has been designed to solve all the problems
of the Universe. The virtualness of VirBase in GoodClass' hierarchy
is one of the reasons GoodClass could be constructed so easily.
Perhaps 'mixin' techniques were used to mixin orthogonal properties.
In any case, the virtualness of VirBase has served its purpose in
allowing GoodClass to be created. This virtualness is not needed
by classes further derived from GoodClass.
There is one problem though, VirBase must be properly
initialized as it is above, for GoodClass to work.
According to C++ rules the constructor of any class
derived from GoodClass must specify how VirBase is to be constructed
in a ctor.
Otherwise, VirBase's default constructor will be used, which maybe
does not exist, but in any case is not what we want.
This is a non-modular requirement on classes derived from GoodClass.
But this is bad, how VirBase is constructed is an implementation
detail of GoodClass that should be encapsulated away from the
writers of derived classes.
In order to solve this problem I propose nonvirtual.
One would declare GoodClass as follows:
class GoodClass : public nonvirtual VirBase, [ a bunch of classes
some of which derive virtually from VirBase]
...
This would cut off the 'virtualness' of VirBase with respect to any
classes derived from GoodClass. VirBase would still be virtual with
respect to GoodClass itself.
In classes derived from GoodClass, the ctor which is part of the
GoodClass constructor being used would control how VirBase is constructed.
VirBase's constructor would still run before any non virtual base classes
of GoodClass, but not necessarily before all non virtual base classes of
the class derived from GoodClass.
This solution would get us out of putting non-modular requirements
on classes derived from GoodClass.
Of course, there might be flaws in this proposal. What are they?
Can anyone think of better syntax for cutting off the 'virtualness'
of a base class with respect to further derived classes?
Thank You for thinking about this.
---------Cut here with a chain saw.------------------------------------------------
Paul Elliott Telephone: 1(512)837-9345
pelliott@io.com Address: PMB 181, 11900 Metric Blvd Suite J
http://www.io.com/~pelliott/pme/ Austin TX 78758-3117
---
[ 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: "Marco Manfredini" <marco@taris.de>
Date: 1999/07/26 Raw View
[Note to the Moderator: I want to clear up a grouser i've made through a
misunderstanding]
blargg!
Sorry for the muddle about muddled thinking. I misread you. :-)
M!
---
[ 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: "Rainer Deyke" <rainerd@earthlink.net>
Date: 1999/07/26 Raw View
Dave Harris <scorp@btinternet.com> wrote in message
news:memo.19990724180354.42331B@btinternet.com...
> However, this motive does not apply to C++. C++ does not try to give
> strong security guarantees; it generally trusts its programmers; it has
> user-defined value types which can avoid aliases. We can't reason from
> "Final is good for Java" to "Final would be good for C++". They are
> different languages.
Then why the need for the keyword "private"?
--
Rainer Deyke (rainerd@hotpop.com)
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor
[ 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: "Rainer Deyke" <rainerd@earthlink.net>
Date: 1999/07/26 Raw View
<sirwillard@my-deja.com> wrote in message
news:7na497$pep$1@nnrp1.deja.com...
> In article <7n3qcn$n9a$1@mulga.cs.mu.OZ.AU>,
> fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> > clamage@eng.sun.com (Steve Clamage) writes:
> > #1. The use of `final' on class definitions,
> > preventing derivation from that class.
> > #2. The use of `final' on method definitions,
> > preventing overriding of that method in derived classes.
> > #3. The use of `final' on object pointers and references,
> > preventing polymorphism.
>
> All three points can be achieved in C++ without a "final" keyword. I
> question the usefulness of any of them, however. 1 & 2 are simply
> mandates that no further derived class can modify virtual functions. I
> don't see how the compiler can use such information to do code
> optimizations, and without this benefit I find it awfully silly to
> believe I can predict all ways in which clients may want to use the
> ABC.
Aside from the optimization benefits (which are nice, but not strictly
necessary since a good compiler/linker can do these optimizations without
the "final" keyword), there is the issue of protecting classes from abuse.
If I write a class that is not intended to be used as a base class and has
no virtual destructor, I can prevent some idiot from trying to inherit from
it by declaring it as final.
final class A {
public:
A(void);
~A(); // destructor is not virtual, so no class may be dervived from A.
};
> 3 is simply dangerous. Example:
>
> void func(obj* p) // void func(final obj* p)
> {
> p->obj::mfunc(); // emulate final call
> }
>
> The problem here is that if we use a class derived from obj that has
> overriden mfunc, the above code (emulated or compiler enforced through
> a "final" keyword) will not call the derived class's mfunc and can
> there by leave the pointed to object in an undefined state. Usually
> when you override a virtual function it's to insure that the semantics
> enforce the derived class's new internal state. This is NOT something
> I'd care to code into my projects, even if I felt there'd be a
> TREMENDOUS speed improvement (which could very well not be true in any
> event). Even if I knew the sematics would be held for all obj* types
> available to me, there could still be a day in which this would not be
> true and you'd be left with a dangerous and hard to find bug.
Actually, this usage is not only safe, but more safe than the absence of the
"final" keyword. Consider the following:
class A {
public:
A(const A&);
// ...
}
class B : public A {
// ...
};
B b;
A a(b);
I create an object of class A from an object of class B. This is not safe,
since it just cuts off the members of B that are not members of A. If the
copy constructor of A was declared as "A::A(final const A&)", "A a(b);"
would have given a compile time error.
--
Rainer Deyke (rainerd@hotpop.com)
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/26 Raw View
In article <slrn7p9uvd.17.pelliott@io.com>, pelliott@io.com wrote:
> My proposal for a C++ extension: nonvirtual.
>
> In order to consider my proposal consider the following:
> 1) default construction is unnatural for a real object.
Then don't provide it. I do that all the time.
> In the real world nothing appears from nothing.
Ambiguous statement.
> Ex-nilo creation only happens in the bible.
>
> Thus to the extent our objects have default constructors,
> they do not model objects in the real world!
>
> This is OK for abstraction classes like ABC's, but a class
> with an implementation that models something in the real
> world should not have a default constructor.
Is someone holding a gun to your head demanding you implement that default
constructor?
> (This is not
> always practical, but it is an idea we should keep in the
> back of our heads, especially when thinking expansively
> about the future.)
>
> Now consider the following situation:
>
> class VirBase
> {
> ...
> public:
> VirBase( ArbParam param );
> ...
> };
>
> class GoodClass : public [ a bunch of classes some of which derive virtually
> from VirBase]
> {
> ...
> public:
> GoodClass( ArbParam param ) : VirBase(param), [other ctors]
> {
> ...
> };
> ...
> };
>
> GoodClass is excellent and has been designed to solve all the problems
> of the Universe. The virtualness of VirBase in GoodClass' hierarchy
> is one of the reasons GoodClass could be constructed so easily.
> Perhaps 'mixin' techniques were used to mixin orthogonal properties.
> In any case, the virtualness of VirBase has served its purpose in
> allowing GoodClass to be created. This virtualness is not needed
> by classes further derived from GoodClass.
I don't like virtual bases, so note my bias. Make a wrapper for GoodClass,
with possible forwarding if classes derived from GoodClass must also
override virtual functions inherited from GoodClass' bases. If derived
classes are only overriding virtuals introduced in GoodClass, then no
forwarding is necessary.
(struct used for simplicity, and names changed to protect the innocent)
struct VB {
VB( int );
};
struct A : virtual VB {
virtual void f() = 0;
};
struct B : virtual VB {
};
struct Good;
struct Good_ : A, B {
private:
Good& good; // can forward
Good_( Good& wrapper, int i ) : VB( i ), good( wrapper ) { }
friend class Good;
virtual void f(); // overrides A::f
};
struct Good {
private:
Good_ good;
Good( int i ) : good( *this, i ) { }
// ^^^^^
// is this strictly conforming, assuming it isn't accessed
// before Good's ctor body is entered?
virtual void vfunc() = 0;
};
struct Derived : Good {
Derived( int i ) : Good( i ) { } // no problem-o!
};
void Good_::f() { // override for A::f
good.vfunc(); // call virtual func in wrapper class
// ...
}
It's a little extra work, but it is possible.
You could also just drop the virtual base (or work out some way other than
its ctor to get the param to it).
> There is one problem though, VirBase must be properly
> initialized as it is above, for GoodClass to work.
>
> According to C++ rules the constructor of any class
> derived from GoodClass must specify how VirBase is to be constructed
> in a ctor.
> Otherwise, VirBase's default constructor will be used, which maybe
> does not exist, but in any case is not what we want.
>
> This is a non-modular requirement on classes derived from GoodClass.
This is one reason I don't like virtual bases. I think they are most
useful to prevent multiple copies of shared data in "diamong" inheritance
hierarchies. I don't think I've ever used a virtual base in actual code,
though.
> But this is bad, how VirBase is constructed is an implementation
> detail of GoodClass that should be encapsulated away from the
> writers of derived classes.
>
> In order to solve this problem I propose nonvirtual.
With every addition to the language, I like it less and less. As I
mentioned in another message, I want a language that's much simpler at its
core, allowing libraries to give it rich semantics. One big advantage of
this is that the compiler (often system-specific) is small, thus easier to
write, while the libraries can be used with all compilers, without
changes.
This featurism isn't healthy.
> One would declare GoodClass as follows:
>
> class GoodClass : public nonvirtual VirBase, [ a bunch of classes
> some of which derive virtually from VirBase]
> ...
>
> This would cut off the 'virtualness' of VirBase with respect to any
> classes derived from GoodClass. VirBase would still be virtual with
> respect to GoodClass itself.
>
> In classes derived from GoodClass, the ctor which is part of the
> GoodClass constructor being used would control how VirBase is constructed.
>
> VirBase's constructor would still run before any non virtual base classes
> of GoodClass, but not necessarily before all non virtual base classes of
> the class derived from GoodClass.
>
> This solution would get us out of putting non-modular requirements
> on classes derived from GoodClass.
And then someone would want to be able to re-enable it in a derived class,
so we'd add yet another feature to the core language. Ugh.
> Of course, there might be flaws in this proposal. What are they?
> Can anyone think of better syntax for cutting off the 'virtualness'
> of a base class with respect to further derived classes?
>
> Thank You for thinking about this.
Thanks for the opportunity.
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/27 Raw View
In article <slrn7p9uvd.17.pelliott@io.com>, pelliott@io.com wrote:
> My proposal for a C++ extension: nonvirtual.
>
> In order to consider my proposal consider the following:
> 1) default construction is unnatural for a real object.
Then don't provide it. I do that all the time.
> In the real world nothing appears from nothing.
Ambiguous statement.
> Ex-nilo creation only happens in the bible.
>
> Thus to the extent our objects have default constructors,
> they do not model objects in the real world!
>
> This is OK for abstraction classes like ABC's, but a class
> with an implementation that models something in the real
> world should not have a default constructor.
Is someone holding a gun to your head demanding you implement that default
constructor?
> (This is not
> always practical, but it is an idea we should keep in the
> back of our heads, especially when thinking expansively
> about the future.)
>
> Now consider the following situation:
>
> class VirBase
> {
> ...
> public:
> VirBase( ArbParam param );
> ...
> };
>
> class GoodClass : public [ a bunch of classes some of which derive virtually
> from VirBase]
> {
> ...
> public:
> GoodClass( ArbParam param ) : VirBase(param), [other ctors]
> {
> ...
> };
> ...
> };
>
> GoodClass is excellent and has been designed to solve all the problems
> of the Universe. The virtualness of VirBase in GoodClass' hierarchy
> is one of the reasons GoodClass could be constructed so easily.
> Perhaps 'mixin' techniques were used to mixin orthogonal properties.
> In any case, the virtualness of VirBase has served its purpose in
> allowing GoodClass to be created. This virtualness is not needed
> by classes further derived from GoodClass.
I don't like virtual bases, so note my bias. Make a wrapper for GoodClass,
with possible forwarding if classes derived from GoodClass must also
override virtual functions inherited from GoodClass' bases. If derived
classes are only overriding virtuals introduced in GoodClass, then no
forwarding is necessary.
(struct used for simplicity, and names changed to protect the innocent)
struct VB {
VB( int );
};
struct A : virtual VB {
virtual void f() = 0;
};
struct B : virtual VB {
};
struct Good;
struct Good_ : A, B {
private:
Good& good; // can forward
Good_( Good& wrapper, int i ) : VB( i ), good( wrapper ) { }
friend class Good;
virtual void f(); // overrides A::f
};
struct Good {
private:
Good_ good;
Good( int i ) : good( *this, i ) { }
// ^^^^^
// is this strictly conforming, assuming it isn't accessed
// before Good's ctor body is entered?
virtual void vfunc() = 0;
};
struct Derived : Good {
Derived( int i ) : Good( i ) { } // no problem-o!
};
void Good_::f() { // override for A::f
good.vfunc(); // call virtual func in wrapper class
// ...
}
It's a little extra work, but it is possible.
You could also just drop the virtual base (or work out some way other than
its ctor to get the param to it).
> There is one problem though, VirBase must be properly
> initialized as it is above, for GoodClass to work.
>
> According to C++ rules the constructor of any class
> derived from GoodClass must specify how VirBase is to be constructed
> in a ctor.
> Otherwise, VirBase's default constructor will be used, which maybe
> does not exist, but in any case is not what we want.
>
> This is a non-modular requirement on classes derived from GoodClass.
This is one reason I don't like virtual bases. I think they are most
useful to prevent multiple copies of shared data in "diamong" inheritance
hierarchies. I don't think I've ever used a virtual base in actual code,
though.
> But this is bad, how VirBase is constructed is an implementation
> detail of GoodClass that should be encapsulated away from the
> writers of derived classes.
>
> In order to solve this problem I propose nonvirtual.
With every addition to the language, I like it less and less. As I
mentioned in another message, I want a language that's much simpler at its
core, allowing libraries to give it rich semantics. One big advantage of
this is that the compiler (often system-specific) is small, thus easier to
write, while the libraries can be used with all compilers, without
changes.
This featurism isn't healthy.
> One would declare GoodClass as follows:
>
> class GoodClass : public nonvirtual VirBase, [ a bunch of classes
> some of which derive virtually from VirBase]
> ...
>
> This would cut off the 'virtualness' of VirBase with respect to any
> classes derived from GoodClass. VirBase would still be virtual with
> respect to GoodClass itself.
>
> In classes derived from GoodClass, the ctor which is part of the
> GoodClass constructor being used would control how VirBase is constructed.
>
> VirBase's constructor would still run before any non virtual base classes
> of GoodClass, but not necessarily before all non virtual base classes of
> the class derived from GoodClass.
>
> This solution would get us out of putting non-modular requirements
> on classes derived from GoodClass.
And then someone would want to be able to re-enable it in a derived class,
so we'd add yet another feature to the core language. Ugh.
> Of course, there might be flaws in this proposal. What are they?
> Can anyone think of better syntax for cutting off the 'virtualness'
> of a base class with respect to further derived classes?
>
> Thank You for thinking about this.
Thanks for the opportunity.
---
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/07/27 Raw View
In article <slrn7p9uvd.17.pelliott@io.com>, Paul Elliott
<pelliott@io.com> writes
>In the real world nothing appears from nothing. Ex-nilo
>creation only happens in the bible.
Check out:
1) Dr Conway's surreal number system
2) Modern cosmogony's theory for the start of the universe.
3) Modern Physics re virtual particles and a vacuum.
:)
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: scorp@btinternet.com (Dave Harris)
Date: 1999/07/27 Raw View
rainerd@earthlink.net (Rainer Deyke) wrote:
> Then why the need for the keyword "private"?
To help programmers avoid making mistakes in good faith. To document
intended usage. Etcetera.
Most C++ implementations will allow "private" to be broken through casts,
pointer arithmetic, "#define private public", or the like. Generally the
compiler trusts its programmers.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
---
[ 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: scott@aravis.softbase.com (Scott McMahan)
Date: 1999/07/27 Raw View
How about a new "microsoft_" namespace, so MS can extend
their compiler all they want?
Scott
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/27 Raw View
I have written a simple page about this "final" construct (along with a
related "override" construct). Hopefully they will make the idea clearer
(though I've already posted similar code examples a couple of times to
this thread and still had misunderstandings...).
http://www.slack.net/~ant/cpp/final.html
Please e-mail me if you find any dumb errors I made. Thanks.
[ 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/07/30 Raw View
i_am_jimbo@my-deja.com writes:
>By declaring a member to be virtual the designer of a base class
>intended for that member to be replaced or refined. This is a design
>choice that leaves the implementation open for refinement. OOP in C++
>provides this capability with the goal of software reuse (a primary
>goal of OOD). "Final" significantly changes the original design goals
>of the base class by saying that this member or class can no longer be
>refined or extended.
No. Using "final" in a derived class does not change the original design
goals of the base class. It specifies the design goals of the derived class.
It does not prevent programmers from refining or extending the base class
in other derived classes.
>"Even in well-designed, structured systems, enhancements often require
>modifications to significant portions of existing design and code. In
>OO, we achieve flexibility by (1) allowing the past to make use of the
>future, and (2) designing for comprehensibility.
>
>"The past can make use of the future when old user code (the past) can
>reliably and predictably call new server code (the future) without any
>modifications to the old user code. "
>-- C++ FAQs by Cline and Lomow: FAQ 17
>
>Finalized members and classes can be an OO design limitation more than
>a feature because it limits the way software can be reused.
Allowing further derivation from a derived class, where the design
of the derived class was not intended to support this, goes against
the principles embodied in the quote above, because this kind of use
is not reliable or predictable, for reasons that I explained in a
previous post in this thread.
>Because the code is final, one is more tempted to go back to the base design
>and start tweaking. This usually ends up breaking other dependant code
>in the process and causing a general maintenance nightmare.
In cases like that, a much better solution, surely, would be to leave the
base class unchanged and to derive a new class from it that meets your
requirements.
Or, alternatively, the programmer could do the design work necessary to ensure
that the original derived class is suitable for further derivation, including
careful documentation of the invariants that it relies on, and then simply
delete the `final' keyword.
>"For the sake of optimization," can encourage premature efforts to
>optimize code that doesn't need it and often leads to interfaces that
>reek of their underlying implementation (poor abstraction).
>Optimization certainly should be in the back of your mind during design
>but should for the most part be done later in development when
>bottlenecks can be more easily identified.
This is true. But I think `final' would be most useful for design and
documentation purposes. The efficiency benefits are a nice bonus, but
they are not the most important reason for wanting `final'.
The original post in this thread certainly over-emphasized the efficiency
aspects and under-emphasized the benefits in terms of compiler support
for documenting and checking your designs.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: clamage@eng.sun.com (Steve Clamage)
Date: 1999/07/31 Raw View
scorp@btinternet.com (Dave Harris) writes:
>rainerd@earthlink.net (Rainer Deyke) wrote:
>> Then why the need for the keyword "private"?
>To help programmers avoid making mistakes in good faith. To document
>intended usage. Etcetera.
It is needed to allow a private section in structs, and to
allow multiple private and public sections in classes.
>Most C++ implementations will allow "private" to be broken through casts,
>pointer arithmetic, "#define private public", or the like. Generally the
>compiler trusts its programmers.
Those are not cases of the compiler trusting the programmer.
They are cases of the programmer writing code having undefined
semantics in the hopes of fooling the compiler.
(The one exception I can think of is getting access to a private
base class using an old-style cast. But that is still not the
compiler trusting the programmer; the language is defined that way.)
--
Steve Clamage, stephen.clamage@sun.com
---
[ 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: i_am_jimbo@my-deja.com
Date: 1999/07/27 Raw View
By declaring a member to be virtual the designer of a base class
intended for that member to be replaced or refined. This is a design
choice that leaves the implementation open for refinement. OOP in C++
provides this capability with the goal of software reuse (a primary
goal of OOD). "Final" significantly changes the original design goals
of the base class by saying that this member or class can no longer be
refined or extended.
"Even in well-designed, structured systems, enhancements often require
modifications to significant portions of existing design and code. In
OO, we achieve flexibility by (1) allowing the past to make use of the
future, and (2) designing for comprehensibility.
"The past can make use of the future when old user code (the past) can
reliably and predictably call new server code (the future) without any
modifications to the old user code. "
-- C++ FAQs by Cline and Lomow: FAQ 17
Finalized members and classes can be an OO design limitation more than
a feature because it limits the way software can be reused. Because
the code is final, one is more tempted to go back to the base design
and start tweaking. This usually ends up breaking other dependant code
in the process and causing a general maintenance nightmare.
"For the sake of optimization," can encourage premature efforts to
optimize code that doesn t need it and often leads to interfaces that
reek of their underlying implementation (poor abstraction).
Optimization certainly should be in the back of your mind during design
but should for the most part be done later in development when
bottlenecks can be more easily identified.
Weather or not function calls are a significant bottleneck in a given
system is a question I'm not really sure about. I would guess,
however, that most of your time is spent in functions not in calling
functions.
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/07/28 Raw View
In article <ochn3.9$k34.1514@newshog.newsread.com>, Scott McMahan
<scott@aravis.softbase.com> writes
>How about a new "microsoft_" namespace, so MS can extend
>their compiler all they want?
Actually that does not help with the kind of extension microsoft has.
What they need is a #pragma NOTC++ which can be prefixed to all MFC
declarations and definitions.
Putting everything in a namespace wouldn't fix the problems though it
would mean that we did not have to know about quite so many of the
bizarre identifiers used my MS. Even then we still have the problem of
their unconventional use of typedef and their very unfriendly use of the
pre-processor. Note that I am not complaining about the compiler but
the claim that their MFC library is written in C++ and is an example of
programming that is worth any form of emulation.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/28 Raw View
In article <7n5kks$bb7$1@nnrp1.deja.com>, i_am_jimbo@my-deja.com wrote:
[snip]
> Finalized members and classes can be an OO design limitation more than
> a feature because it limits the way software can be reused. Because
> the code is final, one is more tempted to go back to the base design
> and start tweaking. This usually ends up breaking other dependant code
> in the process and causing a general maintenance nightmare.
You could say that any form of static type restriction is a limitation
with regards to flexibility. The reality is that we make mistakes in our
programs, and we offset some flexibility for ease of correcting defects.
Static type checking helps in this regard. Final would allow some checking
too. It's not just about performance.
[snipped good comments about premature optimization]
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/28 Raw View
In article <ochn3.9$k34.1514@newshog.newsread.com>,
scott@aravis.softbase.com (Scott McMahan) wrote:
> How about a new "microsoft_" namespace, so MS can extend
> their compiler all they want?
And it would be defined like this:
namespace microsoft_ = dev_slash_null;
(or alternatively, bit_bucket)
:-)
[ 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: pelliott@io.com (Paul Elliott)
Date: 1999/07/29 Raw View
In article <postmast.root.admi.gov-2607991238300001@as1-dialup-84.io.com>, blargg wrote:
>
>I don't like virtual bases, so note my bias.
Virtual base classes are one of those features that are not often
needed.
But when they are, they are needed alot.
> Make a wrapper for GoodClass,
>with possible forwarding if classes derived from GoodClass must also
>override virtual functions inherited from GoodClass' bases. If derived
>classes are only overriding virtuals introduced in GoodClass, then no
>forwarding is necessary.
>It's a little extra work, but it is possible.
We could also toggle in a programs one bit at a time to a Turning machine--
but it is not convenient.
Not doing S**t like this is why computer languages that support inheritance
were invented in the first place! Everytime someone makes a public change
to the virtual base, the wrapper class will have to be modified. Keep in mind
that the Virtual base class and the wrapper class are probably owned by seperate
organizations that don't talk to each other!
>
>This is one reason I don't like virtual bases. I think they are most
>useful to prevent multiple copies of shared data in "diamong" inheritance
>hierarchies. I don't think I've ever used a virtual base in actual code,
>though.
Try looking at the IOSTREAMs family of classes. This family was designed
by smart people, if there were a better way to do it, they would have
done it that way.
>
>With every addition to the language, I like it less and less. As I
>mentioned in another message, I want a language that's much simpler at its
>core, allowing libraries to give it rich semantics. One big advantage of
>this is that the compiler (often system-specific) is small, thus easier to
>write, while the libraries can be used with all compilers, without
>changes.
>
>This featurism isn't healthy.
Try Java or any other SOL (Suit Oriented Languange).
The basic philosophy of a SOL is that software implementors are not
to be trusted, and that languange designers must prevent them from
making mistakes by disallowing the mistake in the syntax of the
languange.
C++ on the other hand trusts the software implementor and has the philosophy
that annoying languange designer/implementor is preferable to annoying
the languange user.
>
>And then someone would want to be able to re-enable it in a derived class,
>so we'd add yet another feature to the core language. Ugh.
>
No, this is a straw-man arguement.
The nonvirtual proposal allows the class designer to hide (encapsulate)
how a class is implemented, removing responsibilities from derived
classes. Undoing nonvirtual would be un-encapsulation and would
be against the principles of modular programming. It therefore
would not be proposed. Sort of like a not-private declaration.
----------------Cut here with a chain saw.---------------------Paul Elliott Telephone: 1(512)837-9345
pelliott@io.com Address: PMB 181, 11900 Metric Blvd Suite J
http://www.io.com/~pelliott/pme/ Austin TX 78758-3117
---
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/07/29 Raw View
In article <slrn7pvo1b.1a.pelliott@io.com>, Paul Elliott
<pelliott@io.com> writes
>Try looking at the IOSTREAMs family of classes. This family was designed
>by smart people, if there were a better way to do it, they would have
>done it that way.
I am not sure I would have quite that much faith. rephrase it as "if
they had known of a better way early enough ..." No I am not saying
that there is a better way, just that even smart people are limited by
their experience so far.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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: David R Tribble <david@tribble.com>
Date: 1999/07/29 Raw View
Francis Glassborow wrote:
>
> Scott McMahan <scott@aravis.softbase.com> writes
>> How about a new "microsoft_" namespace, so MS can extend
>> their compiler all they want?
>
> Actually that does not help with the kind of extension microsoft has.
> What they need is a #pragma NOTC++ which can be prefixed to all MFC
> declarations and definitions.
Unfortunately, MS will probably not use a namespace for their
libraries, most notably their MFC libraries, for the simple reason
that they appear to maintain backwards compatibility at all costs.
Thus in order to support all those users who currently use
MFC, they will probably continue to place all of their symbols into
the global namespace. It would be nice, though, if they eventually
used namespace MS:: or MS::MFC:: for the MFC classes. We will see.
As far as #pragma, it would be (would have been) wise for compiler
vendors to reserve their own "pragma namespace", e.g.,
'#pragma MS xxx' (ISO C9X reserves '#pragma STDC xxx'). As it is
now, most vendors simply take the whole '#pragma xxx' space.
Of course, nothing can get around the ugliness of MS's __declspec()
gibberish. Replacing it with a #pragma won't help because it's
still required in every header file (that you wish to use to
make DLLs).
BTW, what namespace does MS reserve for its Java classes? I would
expect something like 'import Com.Microsoft.Xxx'.
-- David R. Tribble, david@tribble.com --
[ 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/07/30 Raw View
David R Tribble <david@tribble.com> writes:
>Francis Glassborow wrote:
>>
>> Scott McMahan <scott@aravis.softbase.com> writes
>>> How about a new "microsoft_" namespace, so MS can extend
>>> their compiler all they want?
>>
>> Actually that does not help with the kind of extension microsoft has.
>> What they need is a #pragma NOTC++ which can be prefixed to all MFC
>> declarations and definitions.
>
>Unfortunately, MS will probably not use a namespace for their
>libraries, most notably their MFC libraries, for the simple reason
>that they appear to maintain backwards compatibility at all costs.
Are you talking about source compatibility, or binary compatibility?
Source compatibility could be ensured using the same techniques
as the standard uses for <stdio.h>. MS could define new header
files, e.g. <ms/windows.h>, which declared all the symbols inside
an namespace; the old header files such as <windows.h> file would
then include the corresponding new one (e.g. <ms/windows.h>) and
would also have using declarations for all the symbols declared therein,
to import then into the global namespace.
Binary compatibility could be ensured by putting a bunch of symbol
aliases in the DLL.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: Tom.Horsley@worldnet.att.net (Thomas A. Horsley)
Date: 1999/07/22 Raw View
For a completely different new feature: How about a post-constructor?
I constantly find myself wanting to write objects that do complex
initializations in the constructor (which is intended for initialization
right?), but I want to call virtual functions which can be overridden
by derived classes, but during the constructor, it *isn't* the derived
class yet, so none of the virtual functions have been overridden yet.
For random syntax invented on the spur of the moment, how about following
the normal constructor body with :: { <statment list> }, so any constructor
could have an associated post constructor and the same arguments would be
visible in it as in the constructor.
For semantics, the compiler would first run the entire heirarchy of
constructors (just like it does now), then it would run the post
constructors (if any) in the exact same order.
(Of course, then you'd want virtual pos-constructors so derived classes
could override them as well - I'll be going now... :-).
--
>>==>> The *Best* political site <URL:http://www.vote-smart.org/> >>==+
email: Tom.Horsley@worldnet.att.net icbm: Delray Beach, FL |
<URL:http://home.att.net/~Tom.Horsley> Free Software and Politics <<==+
---
[ 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: "Marco Manfredini" <marco@taris.de>
Date: 1999/07/23 Raw View
I see. Declaring a class or a virtual member final effectively turns virtual
off.
class A { virtual void m1(); virtual ~A(); }
final class B : A { virtual void m1(); virtual ~B();} // B::m1 overrides
A::m1
class C : B { virtual void m1(); virtual ~C();} // C::m1 cannot override
B::m1 since it is final
class D : C { virtual void m1(); virtual ~D();} // D::m1 overrides C::m1
D *d=new D;
A *a=&d; a->m1(); calls B::m1();
C *c=&d; c->m1(); calls D::m1();
what will "delete a" do?
> > delete af; should call the (virtual) destructor final (rule#2), or not?
This
> > means the destructor of the overriding class is not called? who's
cleaning
> > up?
>
> Of course not. The type of af has the requirement that it point to a
> complete object of type A - nothing derived. That's the purpose, to allow
> optimizations (as well as express constraints - a previous message caused
> me to realize this would be good to prevent accidental slicing).
>
> > calling with a final A *af; means "call the originally defined methods
of a".
> > What if A* af comes from an B that derived vom A public?
>
> You mean what if af is initialized with a derived type? Then it is a
> programming error. It is similar to initializing a non-const reference to
> a const value - it requires a typecast, and can be dangerous because the
> static information is wrong.
>
In the above example, how can I get a pointer to (final) B from D without
cast?
B b*=&d; // b cannot point to a final?
final B bf*=&d; // bf * cannot converted from &d ?
I can hardly see sense in the clause that finals are made overridable.
So let's see if I understand the example towards the end of the orginal post
"For example, you
might want to write a function that receives an std::list<> of
objects
to operate on. But, what if the person calling the function happens
to
need to store the objects in a std::vector<> or std::set<>.
Wouldn't
it be nice if there were an std::iterable<> base class? And,
wouldn't
it be nice if the stl used virtual member functions to dispatch to
the
actual type? And, wouldn't it be nice if it could do all this,
without
sacrificing any efficiency when you know the actual type?"
Author: Steve Horne <steve.horne1@bridge.bst.bls.com>
Date: 1999/07/23 Raw View
"Thomas A. Horsley" wrote:
>
> For a completely different new feature: How about a post-constructor?
Hey! I need this, especially where pure virtual functions need to be
called around construction time:
Base ctor()
Derv ctor()
Base post-ctor()
Derv post-ctor()
...
Derv dtor()
Base dtor()
-Steve
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/23 Raw View
(seems this didn't go through the first time I sent it)
I have written a simple page about this "final" construct (along with a
related "override" construct). Hopefully they will make the idea clearer
(though I've already posted similar code examples a couple of times to
this thread and still had misunderstandings...).
http://www.slack.net/~ant/cpp/final.html
Please e-mail me if you find any dumb errors I made. Thanks.
---
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/23 Raw View
In article <7n8d8f$2ej$1@iradj.is-bremen.de>, "Marco Manfredini"
<marco@taris.de> wrote:
> I see. Declaring a class or a virtual member final effectively turns virtual
> off.
Please read a page I wrote about this before continuing. Note that it just
explains my view on the construct, and what would be the most useful
semantics for it. Others may have different ideas (though I think I have
captured what is most common among those who have thought carefully about
it).
http://www.slack.net/~ant/cpp/final.html
Your post does cause me to consider the possibility of having a way to
specify a class that can be derived from, but no virtual functions can be
overridden, this allowing the optimizations final would allow on the class
(i.e. can't be derived from, so virtual calls through references to
objects of that type don't need to use the virtual call mechanism), but
still allowing derivation (which wouldn't break anything in the class.
Anyway, I'm just rambling.
> class A { virtual void m1(); virtual ~A(); }
> final class B : A { virtual void m1(); virtual ~B();} // B::m1 overrides
> A::m1
> class C : B { virtual void m1(); virtual ~C();} // C::m1 cannot override
> B::m1 since it is final
> class D : C { virtual void m1(); virtual ~D();} // D::m1 overrides C::m1
First, please use more whitespace. This mess is very hard to read, and I
doubt I'm alone on this.
Anyway, with the semantics I describe on the web page above, the
declaration of class C above would be illegal, because a final class
cannot be derived from, and this your example doesn't compile. End of
story :-)
[snip]
[final when applied as cv-qualifier to ref/ptr type]
> In the above example, how can I get a pointer to (final) B from D without
> cast?
>
> B b*=&d; // b cannot point to a final?
> final B bf*=&d; // bf * cannot converted from &d ?
>
> I can hardly see sense in the clause that finals are made overridable.
You mean like this? (posting incomplete code is hard to understand)
struct B { };
struct D : B { };
void f() {
D d;
B* b = &d;
B final* bf = b; // illegal
}
The reason this is illegal is simple - b can (and in fact *does*) point to
something derived from B, whereas bf cannot. It would be a hole in this
(hypothetical) type system if it were allowed, and this a cast (I like
Valentin's suggested name of exact_cast<> better than final_cast<> :-) If
you want to tell the compiler you know better, you can use the cast:
B final* bf = exact_cast<B final*> (b);
// compiler "OK, I hope you know what you're doing, since I see that b
// really points to a D above..."
> So let's see if I understand the example towards the end of the orginal post
That seemed to be some of the muddled dreamy thinking that I tend to
ignore, which I'll do now...
[snIPP!]
---
[ 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: Herschel <allehman@magnus.math.uwaterloo.ca>
Date: 1999/07/23 Raw View
On 21 Jul 1999, Steve Clamage wrote:
> In particular, I wonder about a designer who insists that a
> polymorphic class not be further adapted. Is he really so smart
> and so far-seeing that there is no possibility that any competent
> programmer would ever want or need to derive from the class?
Upon mentioning this, I realize that C++ provides another challenge to
designers. Namely that a programmer has to see so far into the future,
that when he designs a class, he must know which functions need to be
virtual. I've always thought of this as a sever limition to the language.
Alas, this is off topic, and probably not contributing too much to any
worldly causes :)
Andrew
------
WARNING: This poster reserves the right to be incorrect on occasion.
---
[ 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: sirwillard@my-deja.com
Date: 1999/07/23 Raw View
In article <7n3qcn$n9a$1@mulga.cs.mu.OZ.AU>,
fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> clamage@eng.sun.com (Steve Clamage) writes:
> #1. The use of `final' on class definitions,
> preventing derivation from that class.
> #2. The use of `final' on method definitions,
> preventing overriding of that method in derived classes.
> #3. The use of `final' on object pointers and references,
> preventing polymorphism.
All three points can be achieved in C++ without a "final" keyword. I
question the usefulness of any of them, however. 1 & 2 are simply
mandates that no further derived class can modify virtual functions. I
don't see how the compiler can use such information to do code
optimizations, and without this benefit I find it awfully silly to
believe I can predict all ways in which clients may want to use the
ABC. 3 is simply dangerous. Example:
void func(obj* p) // void func(final obj* p)
{
p->obj::mfunc(); // emulate final call
}
The problem here is that if we use a class derived from obj that has
overriden mfunc, the above code (emulated or compiler enforced through
a "final" keyword) will not call the derived class's mfunc and can
there by leave the pointed to object in an undefined state. Usually
when you override a virtual function it's to insure that the semantics
enforce the derived class's new internal state. This is NOT something
I'd care to code into my projects, even if I felt there'd be a
TREMENDOUS speed improvement (which could very well not be true in any
event). Even if I knew the sematics would be held for all obj* types
available to me, there could still be a day in which this would not be
true and you'd be left with a dangerous and hard to find bug.
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ 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: David Crowley <davidc@msi.com>
Date: 1999/07/23 Raw View
Salters wrote:
>
> Java is an interpreted language, unlike C++. Therefore, Java doesn't
> have a compiler.
Uhhhh... huhuhuhu.... Java *IS NOT* an interpreted language. It *HAS* a
compiler. Java is *COMPILED* into byte code. How this byte code is executed
is an implementation detail. There are some implementations that run Java byte
code in silicon (Dallas Semiconductor). Some implementations convert the byte
code into native instructions that are executed in CPU (JVM w/ JIT). Some
implementations "interpret" the byte code (JVM w/o JIT). Just because Java
isn't compiled into native code does not mean it's not compiled. Perl is a
compiled language also, not interpreted.
http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html
---
[ 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: "Marco Manfredini" <marco@taris.de>
Date: 1999/07/23 Raw View
Sorry for the nuisance, but:
[snip]
>
> http://www.slack.net/~ant/cpp/final.html
>
[snip]
> Anyway, with the semantics I describe on the web page above, the
> declaration of class C above would be illegal, because a final class
> cannot be derived from, and this your example doesn't compile. End of
> story :-)
[snip]
I wasn't talking about the semantics you give in this webpage. I haven't had
any idea about your conception until you gave me this pointer to your web
page. What you state there is much clearer and a different matter.
I was talking about the semantics given in the *initial* post
7mglbv$32o$1@nnrp1.deja.com from <farve@my-deja.com>. They leave open what
an override of a final member function can be. And my critics went into
this direction: allowing the override to be virtual is unclear and
dangerous. We don't argue about that, do we?
[snip]
> > So let's see if I understand the example towards the end of the orginal
post
>
> That seemed to be some of the muddled dreamy thinking that I tend to
> ignore, which I'll do now...
>
[snip]
please accept, that misunderstandings could arose from the fact that english
is not my primary language, but I think that honestly considering the
various ways final could/should work and determining the significance of
such a construct under the proposed circumstances, does not expose muddly
dreamy thinking.
The *initial* post proposed 'final' *primarily* as an compiler hint to
overcome the overhead that involves a vtable somtimes, and invited us to
imagine how the final keyword could make the standard objects more useful.
It gave an example and the I was trying to imagine how using the standard
objects would look like with a final vector<> under a iterable base class. I
cite the original post once again:
"I've been working on a standard set of objects, and would like to use
polymorphism, but incurring the overhead of a vtable is a big waste of
my meticulously efficient and highly optimizable coding. Using
the "final" keyword in this way would be incredibly useful. And, would
make fundamental standard object much more useful. For example, you
might want to write a function that receives an std::list<> of objects
to operate on. But, what if the person calling the function happens to
need to store the objects in a std::vector<> or std::set<>. Wouldn't
it be nice if there were an std::iterable<> base class? And, wouldn't
it be nice if the stl used virtual member functions to dispatch to the
actual type? And, wouldn't it be nice if it could do all this, without
sacrificing any efficiency when you know the actual type?"
I tried and came up with these findings:
1. Having a common base for the container classes would mean, that we can
use a container via its base class. ( why should I have a common base class
then, if not? )
2. Having a common base, means that we need an iterator with virtual
members, eg with a size depending on the actual (final) type. Such an
iterator cannot live on the stack then and must be allocated. Right?
3. Using the derived (vector<>) shall be direct, fast, inlined. We sure
don't want to memory allocate the iterator, just to iterate through a vector
("with sacrificing the efficiency").
4. But that means, that we have to use the final derived differently from
the base: the base through a memory allocated pointer to an iterator, the
derived through a stack allocated non-pointer iterator. So the derived has
to offer a second interface to the achieve the desired efficiency.
5. The goal of final however is to offer optimized access to a interface
through bypassing the virtual table, thereby retaining the interface. This
does not work here and results in a kludge.
(There is another point here: virtual member functions can't be templates
and hence final can't - another limitation
for finals about their efficiency)
My point is: final can help to overcome *some* of the performance
limitations in polymorphic designs. But the generic approach (using
templates and non-related classes and generic algotihms) is much more
powerful and final will never let the polymorphic classes keep up. The
final/overwrite semantics for derivation control should work if implemented
as described by you, but..they are an extended form of the corresponding
java constructs, surely have been considered by the comitee, and and somehow
"boring" . I guess it would be much more interesting to think about the
template-system and to compare C++ with other languages which have a
generic/different apporoach (I think of Haskell here and its approach to
type-classes and how it can be compared to the usage of the "not object
oriented" non-polymorphic classes C++)
how is that?
---
[ 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: Andrei Alexandrescu <andrewalex@hotmail.com>
Date: 1999/07/23 Raw View
In article <7mqpa6$in7$1@nnrp1.deja.com>,
farve@my-deja.com wrote:
[see below]
Wow, what a tough answer. Actually it was so tough that I went back and
reviewed the whole thread.
Your initial posting seemed to me "yet another feature proposal for
C++", which wasn't very interesting to me as it addresses an obscure
optimization problem. At the end you added was what I think it is a
misunderstanding of what generic programming and object-oriented
programming try to address, but I might be wrong.
> Frankly, I'm surprised people are having so much trouble understanding
> this, and seeing the obvious merits of it.
On the contrary, I've noticed that many people understood your idea.
Some did, some not, and some did to a certain extent. As it always
happens.
I wouldn't be so sanguine about the "obvious merits" of it, though.
> I've worked in the
compiler
> industry most of my career, so cut the patronizing, and use your
> brains, will ya?
Expertise is like wisdom: the more you have it, the less you feel urged
to say you have it.
Frankly, I find the key of your posting unusually high. It reminds me of
some unmoderated newsgroups, where often a highly opinionated tone is
seen as a substitute for expertise.
You even mention the "egos", but I can't help noticing yours in
statements starting with your speaking about your "meticulously
efficient and highly optimizable coding" (wow! you got to be the
uncrowned king of coding!) and ending with your mentioning of the
"merit" of your idea.
> I don't know about you, but I spend the
> majority of my time making things more intuitive, so other programmers
> don't screw things up, because of their own bizarre conceptions about
> how things should be done.
I don't know about you, but to me the way you built the statement above
doesn't say much else than how good you are compared to both the poster
to whom you make the honor of answering, and the happy users of your
code.
> Looks like things went to hell when C++
> was turned over to committee.
What exactly was the horrible thing the commitee did to C++? Bjarne said
"Standard C++ is the best approximation of C++ as I envisioned it, and
better than all its pre-standard specifications".
> Why is it so hard for people to accept that someone could know what
> they're talking about?
The problem is that you ask people here for a leap of faith instead of
proving them something. What is the basis? Your proposal? Is it really
that bright? I find it rather minor and obscure. It doesn't seem to
address a problem that I or the other participants here are having. I've
seen much, much better proposals. So what's the point?
> Face it, C++ sucks. Too many cooks have made it into something most
of
> the cooks don't like the taste of.
The problem is, even though you say this, you just proposed yet another
addition to a rather large language. You want to add your spice to it.
An addition that wouldn't clean the language a lot - it would only allow
some optimizations is rare cases.
> We need a new language, similar to
> Java and C++, with the benefits of both; interpretable and compilable,
> able to generate very efficient assembly, and intuitive to use. Yes,
> it is possible. And, I know how to do it. Only, I don't have 5+
years
> of free time.
Thanks for letting me know what a bright individual you are, though.
Colen, I don't understand you. If you know you won't ever create that
language, why do you need to tell us you *could* create it? What's the
point?
> Oddly, I use little else than tempaltes.
I think you can do what you want with template functions. They
establish implicit requirements for their arguments. You don't have to
take a base class as an argument - only a template argument. Anyone
who's implementing your requirements will be able to use your template
functions.
[Note to moderators: please don't reject this post. The above is C++
related stuff :o).]
[Moderator note: I don't see how I could reject this article,
given the approval of the article you are talking about.
Articles ranting about the opinions people have about themselves
and without discussions about the merit of the proposal will be
rejected. --vb]
> So, go patronize someone
> else. Perhaps someone who hasn't worked with compilers for Symantec,
> Metrowerks, and Microsoft. Frankly, I'm appalled at the attitude and
> ignorance here. I was hoping for constructive intelligent
conversation
> of an idea with merit.
You may want to change your key. I don't have anything against the fact
that you think good of yourself - you might do this for a good reason,
although I personally doubt it. However, combining this with insulting
other people, however good or bad they are, is no good in this and any
newsgroup. Prove your value by sheer technical excellence, not by
telling us how good you are.
Andrei
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ 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: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/07/23 Raw View
sirwillard@my-deja.com wrote in message <7na497$pep$1@nnrp1.deja.com>...
>In article <7n3qcn$n9a$1@mulga.cs.mu.OZ.AU>,
> fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
>> clamage@eng.sun.com (Steve Clamage) writes:
>> #1. The use of `final' on class definitions,
>> preventing derivation from that class.
>> #2. The use of `final' on method definitions,
>> preventing overriding of that method in derived classes.
>> #3. The use of `final' on object pointers and references,
>> preventing polymorphism.
>
>1 & 2 are simply
>mandates that no further derived class can modify virtual functions. I
>don't see how the compiler can use such information to do code
>optimizations
final can allow code written to a polymorphic interface to have the
performance of inline functions, in appropriate contexts.
template<class T> class RandomAccessContainer
{
public:
virtual T& operator[](size_t index) = 0;
};
template<class T> class MyVector: public RandomAccessContainer<T>
{
T* data;
public:
final T& operator[](size_t index){ return data[index]; }
...
};
In contexts where I need speed, I would use the MyVector interface, which is
as fast as an STL vector (operator [] can be inlined). In contexts where I
need flexibility (I want to operate on containers that I don't have the
source for) I use the RandomAccessContainer interface.
[ 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/07/23 Raw View
sirwillard@my-deja.com writes:
>fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
>> #1. The use of `final' on class definitions,
>> preventing derivation from that class.
>> #2. The use of `final' on method definitions,
>> preventing overriding of that method in derived classes.
>> #3. The use of `final' on object pointers and references,
>> preventing polymorphism.
>
>All three points can be achieved in C++ without a "final" keyword.
Anything you can do in C++ can be done in assembler, with sufficient
programmer effort. But would you want to?
>I question the usefulness of any of them, however. 1 & 2 are simply
>mandates that no further derived class can modify virtual functions. I
>don't see how the compiler can use such information to do code
>optimizations,
That should be obvious. But let me give an example:
struct Base { virtual void foo(); }
struct Der1 : Base { final virtual void foo(); }
final struct Der2 : Base { void foo(); }
void foo(Der1 *p1, Der2 *p2) {
p1->foo(); // calls Der1::foo()
p2->foo(); // calls Der2::foo()
}
Here the presence of the keyword "final" in the definition of Der1
and Der2 would allow the compiler to generate direct calls
to Der1::foo() and Der2::foo(), whereas without "final" the compiler
would have to use the virtual call mechanism.
>and without this benefit I find it awfully silly to
>believe I can predict all ways in which clients may want to use the
>ABC.
If you declare a class as final, then it must be a concrete class,
not an ABC (abstract base class). Declaring a derived class as final
doesn't restrict the ways in which clients can use the base class,
it only restricts the ways in which clients can use the derived class.
Anyway, this argument -- that if you can't predict what your clients will
want to do you should therefore let them do anything -- has surely been
sufficiently discredited by now.
>3 is simply dangerous. Example:
>
>void func(obj* p) // void func(final obj* p)
>{
> p->obj::mfunc(); // emulate final call
>}
>
>The problem here is that if we use a class derived from obj that has
>overriden mfunc, the above code (emulated or compiler enforced through
>a "final" keyword) will not call the derived class's mfunc and can
>there by leave the pointed to object in an undefined state.
No, you misunderstand the proposal. If you write
struct obj { virtual void mfunc(); }
struct derived : obj { void mfunc(); }
void func(final obj *p);
int main() {
derived d;
func(&d); // ouch
}
then the result would be a compile error, not unexpected behaviour
at runtime.
The static checking is a crucial part of the proposal. Without this
static checking, "final" on pointers and references would indeed be
dangerous. But with the appropriate static checking, it would be
quite safe.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/24 Raw View
In article <7nale3$u7c$1@iradj.is-bremen.de>, "Marco Manfredini"
<marco@taris.de> wrote:
[snip]
> I was talking about the semantics given in the *initial* post
> 7mglbv$32o$1@nnrp1.deja.com from <farve@my-deja.com>.
As I said, I tend to ignore muddled thinking, because trying to reason
with it just mucks things up more.
> They leave open what
> an override of a final member function can be. And my critics went into
> this direction: allowing the override to be virtual is unclear and
> dangerous. We don't argue about that, do we?
Ahhh, yes, it is. I noticed this too, with your example. In effect, there
would be two different virtual functions, but both with the same name. It
would be equivalent of this, except with both functions named f!
struct B {
virtual void f();
};
struct D : B {
final void f(); // overrides B::f
};
struct X : D {
virtual void g();
};
struct Y : X {
void g();
};
(put the string "f" in place of "g") That would be confusing.
>
> [snip]
> > > So let's see if I understand the example towards the end of the orginal
> post
> >
> > That seemed to be some of the muddled dreamy thinking that I tend to
> > ignore, which I'll do now...
> >
> [snip]
>
> please accept, that misunderstandings could arose from the fact that english
> is not my primary language, but I think that honestly considering the
> various ways final could/should work and determining the significance of
> such a construct under the proposed circumstances, does not expose muddly
> dreamy thinking.
Sorry, I was talking about the one you quoted, the one in the tone of
"what if the compiler just wrote your code for you!". It sounded like an
advertisement :-)
I agree with what you say - it should be considered in other ways.
> The *initial* post proposed 'final' *primarily* as an compiler hint to
> overcome the overhead that involves a vtable somtimes, and invited us to
> imagine how the final keyword could make the standard objects more useful.
Right. I think templates can be used here under the current language
standard - just make a module that automatically generates a polymorphic
wrapper (adaptor) to a concrete type.
> It gave an example and the I was trying to imagine how using the standard
> objects would look like with a final vector<> under a iterable base class. I
> cite the original post once again:
>
> "I've been working on a standard set of objects, and would like to use
> polymorphism, but incurring the overhead of a vtable is a big waste of
> my meticulously efficient and highly optimizable coding. Using
> the "final" keyword in this way would be incredibly useful. And, would
> make fundamental standard object much more useful. For example, you
> might want to write a function that receives an std::list<> of objects
> to operate on. But, what if the person calling the function happens to
> need to store the objects in a std::vector<> or std::set<>. Wouldn't
> it be nice if there were an std::iterable<> base class? And, wouldn't
> it be nice if the stl used virtual member functions to dispatch to the
> actual type? And, wouldn't it be nice if it could do all this, without
> sacrificing any efficiency when you know the actual type?"
>
> I tried and came up with these findings:
> 1. Having a common base for the container classes would mean, that we can
> use a container via its base class. ( why should I have a common base class
> then, if not? )
> 2. Having a common base, means that we need an iterator with virtual
> members, eg with a size depending on the actual (final) type. Such an
> iterator cannot live on the stack then and must be allocated. Right?
> 3. Using the derived (vector<>) shall be direct, fast, inlined. We sure
> don't want to memory allocate the iterator, just to iterate through a vector
> ("with sacrificing the efficiency").
> 4. But that means, that we have to use the final derived differently from
> the base: the base through a memory allocated pointer to an iterator, the
> derived through a stack allocated non-pointer iterator. So the derived has
> to offer a second interface to the achieve the desired efficiency.
> 5. The goal of final however is to offer optimized access to a interface
> through bypassing the virtual table, thereby retaining the interface. This
> does not work here and results in a kludge.
Agreed. This is why I called the origianl thinking muddled.
> (There is another point here: virtual member functions can't be templates
> and hence final can't - another limitation for finals about their efficiency)
Put another way, template member functions can't be virtual. Template
classes can certainly have virtual member functions, and those could be
final too.
> My point is: final can help to overcome *some* of the performance
> limitations in polymorphic designs. But the generic approach (using
> templates and non-related classes and generic algotihms) is much more
> powerful and final will never let the polymorphic classes keep up. The
> final/overwrite semantics for derivation control should work if implemented
> as described by you, but..they are an extended form of the corresponding
> java constructs, surely have been considered by the comitee, and and somehow
> "boring" . I guess it would be much more interesting to think about the
> template-system and to compare C++ with other languages which have a
> generic/different apporoach (I think of Haskell here and its approach to
> type-classes and how it can be compared to the usage of the "not object
> oriented" non-polymorphic classes C++)
I am most interested in "final" as a compilation safety device (and of
course "override", as that's all it's for). The efficiency is just a
benefit. Of the two, "override" would provide all the safety in this
regard, since one couldn't accidentally override a virtual function
without knowing it.
---
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/24 Raw View
In article
<Pine.SOL.3.96.990720220140.22809B-100000@magnus.math.uwaterloo.ca>,
Herschel <allehman@magnus.math.uwaterloo.ca> wrote:
> On 21 Jul 1999, Steve Clamage wrote:
>
> > In particular, I wonder about a designer who insists that a
> > polymorphic class not be further adapted. Is he really so smart
> > and so far-seeing that there is no possibility that any competent
> > programmer would ever want or need to derive from the class?
>
> Upon mentioning this, I realize that C++ provides another challenge to
> designers. Namely that a programmer has to see so far into the future,
> that when he designs a class, he must know which functions need to be
> virtual. I've always thought of this as a sever limition to the language.
Nope, this is not C++-specific - it's part of basic decision making. Take
anything people design, and consider those bad designs where the designer
just thought about here and now, and not the future. Even short-term
versus long-term thinking has the same issues.
I think I can sum up why I hate the design idea that everything should be
virtual in case it needs to be overridden - it leads to hacked systems.
You override not to fulfill a the contract for a derived class, but to get
a hook into the base object at some point, usually with the idea of where
the functions are called (a "come-from" mentality). This doesn't lead to
good design. You are, in effect, telling the base class to partially "get
lost!" and using at as an abstract interface class. If it doesn't have a
clearly-defined contract for derived classes to override, it shouldn't be
overridable.
---
[ 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: scorp@btinternet.com (Dave Harris)
Date: 1999/07/24 Raw View
farve@my-deja.com () wrote:
> I've been working on a standard set of objects, and would like to use
> polymorphism, but incurring the overhead of a vtable is a big waste of
> my meticulously efficient and highly optimizable coding. Using
> the "final" keyword in this way would be incredibly useful.
It's worth noting that in Java, "final" is part of the security model. It
is not just for optimisation.
For example, sometimes the security manager assumes that a String will not
change after it has been checked. It's not enough to make String itself
immutable, we also have to ensure that a mutable subclass cannot be
substituted for it. Recall that Java is designed to run untrusted code
safely, is multi-threaded, and that String is necessarily a reference type
so aliases can't be avoided. It's fairly hard to give strong security
guarantees in these conditions. "Final" is how the Java designers chose to
manage it.
Security is enormously important to Java - the language doesn't make sense
unless you grasp that. It's a moot point whether Java would have "final"
for efficiency alone. Security demanded it. That was sufficient reason.
However, this motive does not apply to C++. C++ does not try to give
strong security guarantees; it generally trusts its programmers; it has
user-defined value types which can avoid aliases. We can't reason from
"Final is good for Java" to "Final would be good for C++". They are
different languages.
(Incidently, we can't go the other way either. We shouldn't take all the
various criticisms of "final" in C++ to be criticisms of Java.)
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
---
[ 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: farve@my-deja.com
Date: 1999/07/20 Raw View
Frankly, I'm surprised people are having so much trouble understanding
this, and seeing the obvious merits of it. I've worked in the compiler
industry most of my career, so cut the patronizing, and use your
brains, will ya?
I'm working on a pre-compiler to add these features to the language.
I'll post it when I'm done.
>>>
As a semantic device, I agree that final would be nice. But for
bypassing the vtable, there are other approaches, e.g.
foo_pointer->foo::func()
<<<
That may allow the caller to bypass the vtable on an individual
function basis, but it doesn't allow the class author to define the
behavior. I'm writing classes for other people to use. I can't assume
they know what they're doing. I don't know about you, but I spend the
majority of my time making things more intuitive, so other programmers
don't screw things up, because of their own bizarre conceptions about
how things should be done. Bjarne's own original (some poor) decisions
about language features were based on making it more difficult for
people do things incorrectly. Looks like things went to hell when C++
was turned over to committee. I'm trying to identify fundamentals.
And, frankly, C++ is a mess.
>>>>
Java is an interpreted language, unlike C++. Therefore, Java doesn't
have a compiler. C++ has a compiler, and it can determine if a class is
used asa final class
<<<<
And, there's no reason why Java can't be compiled, and no reason why
C++ can't be interpreted. What's your point? In fact, what I'm
suggesting is entirely possible to do with C++ at compile time.
Nothing need be done at runtime.
Why is it so hard for people to accept that someone could know what
they're talking about? Is the state of programming really that
fragile? Why all the egos?
>>>>
Again, if you don't want a virtual call then use a non-virtual call,
and let the compiler do as much as possible. You'll be suprised at much
better a compiler is at optimizing
<<<<
I don't know what compiler you're using, but I've worked with dozens of
compilers, and looked very closely at the assembly output of all of
them, and you'd be surprised just how POORLY your compiler is
optimizing. Especially when you keep feeding it hacks, because the
semantics of the language don't actually let you do what you want to do
intuitively.
Specifically, if a function is virtual, it WILL NOT be eligible for
inlining. I've never seen a compiler that will do this. The semantics
I'm suggesting would make this possible.
>>>>
I do fail to see how a final BaseClass* construct would work. Will
g(final BaseClass* pbc) {}
f(BaseClass* pbc) {g(pbc);}
int main(){
f(Derived*);
}
compile?
Why should new return final types? new returns pointers, not objects.
And since pointers don't have vtables, you don't gain a lot.
<<<<
No, hypothetically that would not compile. It would generate a compile
time error, when you tried to pass a BaseClass* to a final BaseClass*,
just like it would complain when you try to pass a const BaseClass* to
a BaseClass*. With final as part of the pointer or reference type, the
compiler would have a compile-time hint that a pointer or reference is
not a pointer or reference to a base class, it's actually a pointer or
reference to the most derived (actual) type. And no vtable dispatching
would be necessary for any function calls, implicitly.
Face it, C++ sucks. Too many cooks have made it into something most of
the cooks don't like the taste of. We need a new language, similar to
Java and C++, with the benefits of both; interpretable and compilable,
able to generate very efficient assembly, and intuitive to use. Yes,
it is possible. And, I know how to do it. Only, I don't have 5+ years
of free time.
>>>>
Polymorphism in the classical sense occurs when you operate on a
pointer for which the static type pointed is a base class of the
dynamic class, or the static class is identical to the dynamic class.
This gives two possibilities, and they must be distinguished, something
that can only happen when the dynamic type is known, i.e. at runtime.
<<<<
In C++, when you have a pointer or reference to an object, you don't
have any choice about whether or not polymorphism is used. I'm
suggesting that it would be nice to have a type keyword that specifies
that a pointer or reference to an object is known to be a pointer or
reference to exactly that actual type, so polymorphism could be
circumvented for the sake of efficiency, and virtual functions declared
in a class could be eligible for inlining, and thus optimization.
I have some very fundamental classes, with member functions that could
resolve into almost no code what-so-ever, especially if the default
argument values are used, in which case some comparisons could resolve
into constants, and be optimized out. It would sure be nice to inline
all of this code, YET also be able to use polymorphism. If you still
don't understand the fundamental usefulness of this, I don't know what
to tell you. Go back to school, and try to avoid being brainwashed by
specifics.
>>>>
And wouldn't it be nice if somebody told you about templates?
<<<<
Excuse me? I've been using templates almost since inception. The
classes that lead me to this suggestion are template. All of them.
Oddly, I use little else than tempaltes. So, go patronize someone
else. Perhaps someone who hasn't worked with compilers for Symantec,
Metrowerks, and Microsoft. Frankly, I'm appalled at the attitude and
ignorance here. I was hoping for constructive intelligent conversation
of an idea with merit.
Question your religion.
- Colen Garoutte-Carson
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ 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: clamage@eng.sun.com (Steve Clamage)
Date: 1999/07/21 Raw View
farve@my-deja.com writes:
>Frankly, I'm surprised people are having so much trouble understanding
>this, and seeing the obvious merits of it.
If people disagree with you, it doesn't automatically mean they
are stupid, or even wrong. I agree that some replies in this
thread have completely missed your point. But let's not tar
everyone with the same brush. Isn't it also possible that you
haven't thought of everything?
>Why is it so hard for people to accept that someone could know what
>they're talking about? Is the state of programming really that
>fragile? Why all the egos?
Aren't those questions equally valid when turned around?
>Specifically, if a function is virtual, it WILL NOT be eligible for
>inlining.
If the function is qualified with a class name, or if it is
called from a constructor or destructor of its own or a derived
type, it can be inlined. It is common for compilers to do so.
But probably you meant this statement in the case where the
function was called from other contexts. Even then, in principle,
a compiler doing whole-program analysis could determine in
some cases the true type of the object pointed to and inline
the function call.
That may be a dream for the future, but I wanted to point out
that your statement is too general to be valid. Only in SOME
cases is it impossible to inline a virtual function call.
>In C++, when you have a pointer or reference to an object, you don't
>have any choice about whether or not polymorphism is used.
Of course you do.
A value type is unlikely to be polymorphic, won't have virtual
functions, and you don't get polymorphism when calling functions
via a pointer.
An object type might be polymorphic, in which case you should
want to get polymorphism when calling functions via a pointer,
and indeed you will. If for some reason you know the types
involved and want to bypass the polymorphic behavior, you
can do so by qualifying the function being called.
There is one thing you don't get: In the specific case where
you want to prevent derivation from a class, and thereby
get automatic bypass of the virtual mechanism when calling
functions via a pointer to that class, you get no language
support. You can work around the limitation, but you lose
flexibility and maintainaibility of the code if you do.
In other words, I agree that C++ does not support the
functionality of "final" in Java.
But it seems to me that needing "final" is unusual, and
its lack does not justify so much heat and name-calling.
In particular, I wonder about a designer who insists that a
polymorphic class not be further adapted. Is he really so smart
and so far-seeing that there is no possibility that any competent
programmer would ever want or need to derive from the class?
My experience has been the opposite. Mostly I curse the designer
who didn't allow for simple flexibilty when the extra flexibility
had little cost. Sometimes the designer is my earlier self,
of course. :-)
--
Steve Clamage, stephen.clamage@sun.com
---
[ 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/07/21 Raw View
clamage@eng.sun.com (Steve Clamage) writes:
>farve@my-deja.com writes:
>
>>In C++, when you have a pointer or reference to an object, you don't
>>have any choice about whether or not polymorphism is used.
>
>Of course you do.
>
>A value type is unlikely to be polymorphic, won't have virtual
>functions, and you don't get polymorphism when calling functions
>via a pointer.
>
>An object type might be polymorphic, in which case you should
>want to get polymorphism when calling functions via a pointer,
>and indeed you will.
That gives you a choice at the time the type is defined,
but it doesn't give you a choice when you're writing the code
which uses a pointer or reference to that type.
You may well want to use the same type polymorphically in some
places and monomorphically in other places.
>If for some reason you know the types
>involved and want to bypass the polymorphic behavior, you
>can do so by qualifying the function being called.
Yes, but as I remarked in another post, that would lead to unmaintainable
code, because the compiler won't perform the appropriate compile-time
semantic checks to ensure that this optimization is safe.
So I don't see that as a realistic alternative.
>There is one thing you don't get: In the specific case where
>you want to prevent derivation from a class, and thereby
>get automatic bypass of the virtual mechanism when calling
>functions via a pointer to that class, you get no language
>support. You can work around the limitation, but you lose
>flexibility and maintainaibility of the code if you do.
>
>In other words, I agree that C++ does not support the
>functionality of "final" in Java.
The original poster discussed several different constructs:
#1. The use of `final' on class definitions,
preventing derivation from that class.
#2. The use of `final' on method definitions,
preventing overriding of that method in derived classes.
#3. The use of `final' on object pointers and references,
preventing polymorphism.
#1 and #2 correspond to `final' in Java. But as far as I know, Java
doesn't have anything similar to #3. #3 corresponds more closely
with Ada 95, which distinguishes between
p : access Foo'class;
-- p points to a value of type Foo or of any type derived
-- from Foo
-- analagous to `Foo *p;' in C++.
and
p : access Foo;
-- p points to a value of type Foo
-- analagous to `final Foo *p;' in C++ with extension #3 above.
>But it seems to me that needing "final" is unusual
I think it would be rare to *need* these extensions, but I think
that code which could *benefit* from these extensions would not be uncommon.
Would the benefits would outweigh the costs of the additional language
complexity? I'm not sure. But I do think it is worth considering.
With regard to #3, pointers and references are often used in C++ even
when no polymorphism is involved. For example, unlike e.g. Ada and
Mercury, C++ doesn't have `out' mode parameters, so if a function needs
to return multiple values, C++ programmers often use
pass-by-reference. There are many other examples where pointers are
used even though they always point to the specific type, not to any
derived type. In such cases, I think it would make sense for C++ to
provide, as does Ada 95, a way for the programmer to indicate this to
the compiler, and for the compiler to check that the programmer's
intentions are followed.
>In particular, I wonder about a designer who insists that a
>polymorphic class not be further adapted. Is he really so smart
>and so far-seeing that there is no possibility that any competent
>programmer would ever want or need to derive from the class?
The same argument has been used by fans of Smalltalk and other OOP
languages to argue that member functions should always be `virtual'.
But it's important to distinguish between deliberate reuse and unplanned
reuse. Deliberate reuse occurs when the code which is reused was designed
to be reused in that way. It tends to work well. Unplanned reuse is when
code is reused in ways that the designer did not intend. Unplanned reuse
does not work so well -- it can cause maintenance difficulties. In
particular, future modifications to the implementation of the base class
which preserve the public interface can nevertheless break derived
classes. For example, the precondition of some method in the base
class might be weakened, or the postcondition might be strengthened.
These kinds of changes will have no effect on client code which just uses
the base class, but can easily break derived classes. And with unplanned
reuse, the exact preconditions and postconditions that the base class is
relying on are rarely documented.
The rationale for `final' on method definitions is the same as the
rationale for having non-virtual method definitions in the first place.
The fact that a method is virtual in the base class does not imply
that it should be virtual in a derived class.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: "Marco Manfredini" <marco@taris.de>
Date: 1999/07/21 Raw View
Did I get it right?
<farve@my-deja.com> schrieb in im Newsbeitrag:
7mglbv$32o$1@nnrp1.deja.com...
>
> 1. Borrow "final" keyword from Java for virtual member functions.
#1
> - A call to a final virtual member function would be direct, and
> not dispatched through the vtable.
> - final virtual member functions defined in the class declaration
> would be eligible for inlining and optimization.
#2
> - Unlike Java, final virtual functions should be allowed to be
> overridden, but should short circuit the vtable when called on a
> type that defines it as final.
> - Not applicable to non-virtual functions.
>
> 2. Also allow "final" to be used as part of a type (like "const").
> - The compiler could avoid using the vtable for any virtual
> calls on that type.
> - All automatic object could be assumed final.
> - Any virtual functions defined in class declaration would be
> eligible for inlining, and optimization.
> - Type checking could be performed to enforce actual-type
> compatibility (i.e. If a function expects a "final BaseClass*",
> it would not accept a "DerivedClass*".)
> - Any type returned by operator new would be "final"
> - If a final object is never cast down to a base class, inline
> construction and destruction could be optimized to omit the
> vtable entirely.
class A
{
final virtual void m1() {}
void virtual m2() {}
};
... A::m1() and A::m2() overriden later from a class B
A*a;
a->m1(); // always call or inline m1 (according to #1)
a->m2(); // call the overide (normal behaviour)
final A* af;
af->m1(); // always call or inline m1 (according to #1 and #2)
af->m2(); // always call or inline m2 (according to #2)
How can I call the overide of m1, if a->m1() must call A::m1 according to #1
and af->m1() must call A::m1() either?
delete af; should call the (virtual) destructor final (rule#2), or not? This
means the destructor of the overriding class is not called? who's cleaning
up?
calling with a final A *af; means "call the originally defined methods of a".
What if A* af comes from an B that derived vom A public?
B can modify A's members then, change structures, delete memory etc. because
B overrides A's behaviour.
Now calling through "af" means "call the original members of A", but they do
not know, that someone modified their protected members.
Setting one member function of A "final" and overriding it later, is
dangerous, unless you can assure, that calling the unmodified member is
secure, no matter whatever is derived from A.
But using A through a final-pointer means that ALL members of A must be
secure.
Take for example a string-class S. S has a member set(const char* x), which
deletes the string that is managed by S, copies x and sets it as the new
string.
final S*s;
s->set("final");
this will "finalize S", because s in fact points to a derived T, which
changed the behaviour of S insofar as T -uses a different memory allocator-.
so using a final s pointer deletes the string in S through another memory
allocator, which in turn will crash instantly.
I can do that with standard C++ too:
s->S::set("final");
But qualifying is a "i know what i do". It's explicit.
I might oversee, that my pointer is declared final. Or I might give the
pointer as an argument to a template-function, which calls things from my
pointer, without knowing that it is a final.
If I use a B, i will probably have no idea about the internal workings of S
or T and will have no clue, why i must not declare a final S *s!
setting a member of S 'final' on the other hand, makes this member
practically unusable for derivation. If i derive from S i might not have an
idea about its internals (because somebody else made it) and can't tell, if
using the final from S will crash T. This is a problem with "normal"
derivations anyway, but i don't have bother that somebody inexplicitly calls
an unmodified overridden.
So I think, overriding finals is dangerous and introducing "final" as an
optimizer hint is not enough reason for a new keyword. "final" as flag to
protect a class from derivations is useful, but this can be done in C++
without a "final" keyword.
[ 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: christian.bau@isltd.insignia.com (Christian Bau)
Date: 1999/07/21 Raw View
In article <7n2bvi$1qc$1@engnews1.eng.sun.com>, clamage@eng.sun.com (Steve
Clamage) wrote:
> In particular, I wonder about a designer who insists that a
> polymorphic class not be further adapted. Is he really so smart
> and so far-seeing that there is no possibility that any competent
> programmer would ever want or need to derive from the class?
>
> My experience has been the opposite. Mostly I curse the designer
> who didn't allow for simple flexibilty when the extra flexibility
> had little cost. Sometimes the designer is my earlier self,
> of course. :-)
I think the situation can be quite different: I write a class, and
everything has been tested and known to work. I sure know that someone
might want to derive further, but I cannot guarantee that my baseclass
code will work properly if you override things in ways I didn't foresee.
In other words, before you derive from my class, I would want you to
discuss this with me. Or you change my class yourself (making it
non-final), and take responsibility for it.
It is also a matter of documentation. As long as you don't derive from the
class, its behavior is documented completely by the source code. If you
derive from it, that is not true anymore.
[ 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: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/07/21 Raw View
Fergus Henderson wrote in message >The original poster discussed several
different constructs:
>
> #1. The use of `final' on class definitions,
> preventing derivation from that class.
There is a well known way to do this in C++ (via virtual base class). In
principle a compiler could recognize the use of the pattern and perform
'final' optimizations.
> #2. The use of `final' on method definitions,
> preventing overriding of that method in derived classes.
In rare circumstances there is a way to do this in C++ also.
class BResult{ public: virtual ~BResult(); };
class Base
{
public:
virtual BResult* foo();
};
class Der: public Base
{
class DResult: public BResult{};
public:
DResult* foo(); // Overrides Base::foo(), cannot be overriden
};
No class derived from Der can override Der::foo(). Any such attempt would
have to declare a return type of Der::DResult* (or pointer to something
derived from DResult), but DResult is a private type, so the child class
can't use the name.
In principle a compiler could detect this and do 'final' optimizations.
> #3. The use of `final' on object pointers and references,
> preventing polymorphism.
This could mean two things:
3a: An assertion that the dynamic type of the pointer matches the static
type.
3b: A request that all calls through the pointer use the static type of the
pointer, not the dynamic type.
Note that 3b is a reasonable optimization once 3a has occured. A programmer
could write code that does a test and results in undefined behavior (say
division by zero after a typeid comparison) if 3a were false. In principle
a compiler could avoid doing the test (if the test fails the compiler is
allowed to do anything it wants), and assume 3b is in effect below the point
of the test.
I can't see any compact method to express 3b in the absence of 3a.
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/07/22 Raw View
In article <7n2bvi$1qc$1@engnews1.eng.sun.com>, Steve Clamage
<clamage@eng.sun.com> writes
>>Specifically, if a function is virtual, it WILL NOT be eligible for
>>inlining.
>
>If the function is qualified with a class name, or if it is
>called from a constructor or destructor of its own or a derived
>type, it can be inlined. It is common for compilers to do so.
>
>But probably you meant this statement in the case where the
>function was called from other contexts. Even then, in principle,
>a compiler doing whole-program analysis could determine in
>some cases the true type of the object pointed to and inline
>the function call.
And of course when you have the object rather than a pointer or
reference the compiler can (should) ignore the virtuality of the member
function.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/22 Raw View
In article <7n2dqg$ndd$1@iradj.is-bremen.de>, "Marco Manfredini"
<marco@taris.de> wrote:
> Did I get it right?
>
> <farve@my-deja.com> schrieb in im Newsbeitrag:
> 7mglbv$32o$1@nnrp1.deja.com...
> >
> > 1. Borrow "final" keyword from Java for virtual member functions.
> #1
> > - A call to a final virtual member function would be direct, and
> > not dispatched through the vtable.
> > - final virtual member functions defined in the class declaration
> > would be eligible for inlining and optimization.
> #2
> > - Unlike Java, final virtual functions should be allowed to be
> > overridden, but should short circuit the vtable when called on a
> > type that defines it as final.
> > - Not applicable to non-virtual functions.
> >
> > 2. Also allow "final" to be used as part of a type (like "const").
> > - The compiler could avoid using the vtable for any virtual
> > calls on that type.
> > - All automatic object could be assumed final.
> > - Any virtual functions defined in class declaration would be
> > eligible for inlining, and optimization.
> > - Type checking could be performed to enforce actual-type
> > compatibility (i.e. If a function expects a "final BaseClass*",
> > it would not accept a "DerivedClass*".)
> > - Any type returned by operator new would be "final"
> > - If a final object is never cast down to a base class, inline
> > construction and destruction could be optimized to omit the
> > vtable entirely.
>
> class A
> {
> final virtual void m1() {}
> void virtual m2() {}
> };
>
> ... A::m1() and A::m2() overriden later from a class B
If you're writing it in code, WRITE IT IN CODE! :-)
> A*a;
> a->m1(); // always call or inline m1 (according to #1)
> a->m2(); // call the overide (normal behaviour)
> final A* af;
> af->m1(); // always call or inline m1 (according to #1 and #2)
> af->m2(); // always call or inline m2 (according to #2)
>
> How can I call the overide of m1, if a->m1() must call A::m1 according to #1
> and af->m1() must call A::m1() either?
It cannot be overridden - any derived class that defines a member function
with the same signature and name as A::m1 just hides A::m1. In effect, m1
is not virtual in derived classes. So, this is equivalent to A::m1 not
even being virtual.
> delete af; should call the (virtual) destructor final (rule#2), or not? This
> means the destructor of the overriding class is not called? who's cleaning
> up?
Of course not. The type of af has the requirement that it point to a
complete object of type A - nothing derived. That's the purpose, to allow
optimizations (as well as express constraints - a previous message caused
me to realize this would be good to prevent accidental slicing).
> calling with a final A *af; means "call the originally defined methods of a".
> What if A* af comes from an B that derived vom A public?
You mean what if af is initialized with a derived type? Then it is a
programming error. It is similar to initializing a non-const reference to
a const value - it requires a typecast, and can be dangerous because the
static information is wrong.
[snip]
> Take for example a string-class S. S has a member set(const char* x), which
> deletes the string that is managed by S, copies x and sets it as the new
> string.
>
> final S*s;
> s->set("final");
>
> this will "finalize S", because s in fact points to a derived T, which
> changed the behaviour of S insofar as T -uses a different memory allocator-.
> so using a final s pointer deletes the string in S through another memory
> allocator, which in turn will crash instantly.
I don't think final has anything to do with it. What if we initialize S as
follows:
// C++ (no use of hypothetical "final" construct)
S ss;
S* s = &ss;
s->set( "final" );
Or we could initialize s with an S allocated with ::new, etc.
[snip]
> setting a member of S 'final' on the other hand, makes this member
> practically unusable for derivation.
Duh. That's the point. Making a function non-virtual means it can't be
overridden. That's the point too.
> If i derive from S i might not have an
> idea about its internals (because somebody else made it) and can't tell, if
> using the final from S will crash T.
You can't (hypothetically) create a pointer to a "final" type in a
non-typesafe way without a cast. Creating one has similar issues as using
scoped calls (i.e. s->S::set( "final" )), only it can be done, in many
cases, without casts therefore in a completely typesafe way.
> This is a problem with "normal"
> derivations anyway, but i don't have bother that somebody inexplicitly calls
> an unmodified overridden.
>
> So I think, overriding finals is dangerous and introducing "final" as an
> optimizer hint is not enough reason for a new keyword. "final" as flag to
> protect a class from derivations is useful, but this can be done in C++
> without a "final" keyword.
It's not just an optimizer hint, though. Like making member functions
non-virtual, it has uses in the design space too. As someone else
mentioned, "out" parameters (function returns implemented through
non-const reference arguments) would likely be declared "final" so slicing
didn't occur:
void f( Foo final& out ); // just sets Foo
void g() {
Foo foo;
f( foo ); // OK
DerivedFromFoo der;
f( der ); // error
}
A class deriving from a mixin and overriding virtuals could declare the
overrides virtual:
class Mixin {
virtual void hook() = 0;
virtual void optional_hook();
};
class Foo : Mixin { // private detail
final void hook();
};
class Bar : Foo {
void hook(); // no possibility of accidental override
};
I just realized another possible final construct - deriving from a base
class and making all virtual functions "final" in the derived class. In
the above example, optional_hook() is still virtual in Foo, and this Bar
could accidentally override it. We could make the Mixin final when
deriving from it:
class Foo : final Mixin { // "the buck stops here"
void hook(); // final anyway
};
class Bar : Foo {
void hook(); // no overriding of Foo::hook
void optional_hook(); // no overriding of Mixin::optional_hook
};
Deriving privately from a Mixin shouldn't expose these details to derived
classes.
Of course, I think there should be an explicit "override" keyword for
virtual overrides, this making Bar OK to begin with, or an error (because
it was overriding, but didn't say so).
---
[ 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: "Dave Abrahams" <abrahams@mediaone.net>
Date: 1999/07/22 Raw View
In article <7n2bvi$1qc$1@engnews1.eng.sun.com> , clamage@eng.sun.com (Steve
Clamage) wrote:
> In particular, I wonder about a designer who insists that a
> polymorphic class not be further adapted. Is he really so smart
> and so far-seeing that there is no possibility that any competent
> programmer would ever want or need to derive from the class?
>
> My experience has been the opposite. Mostly I curse the designer
> who didn't allow for simple flexibilty when the extra flexibility
> had little cost. Sometimes the designer is my earlier self,
> of course. :-)
Of course, I've never used final to prevent derivation, so I can't be sure
that I wouldn't find myself cursing its use, but doesn't this argument fall
into the same category as "all data members should be protected, so that
some day somebody might derive a new class which fondles them"? Hasn't that
argument been sufficiently discredited?
I like to carefully define my class' interfaces to the outside world. The
outside includes both the world at large (public interface) and derivers
(public+protected interface). This care helps promote proper use. It seems
in keeping to prevent derivation where appropriate.
-Dave
---
[ 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: scampi@dial.pipex.com (Mathew Hendry)
Date: 1999/07/15 Raw View
On 14 Jul 1999 16:03:46 GMT, farve@my-deja.com wrote:
>
>1. Borrow "final" keyword from Java for virtual member functions.
> - A call to a final virtual member function would be direct, and
> not dispatched through the vtable.
As a semantic device, I agree that final would be nice. But for
bypassing the vtable, there are other approaches, e.g.
foo_pointer->foo::func();
>2. Also allow "final" to be used as part of a type (like "const").
> - The compiler could avoid using the vtable for any virtual
> calls on that type.
class foo_nonvirtual {
// data and non-virtual functions only
};
class foo : public foo_nonvirtual {
// virtual and forwarding functions go here
};
When you want "final foo", use "foo_nonvirtual". Not perfect, but it
would work in many cases. A clever compiler might spot the trick and
lay out the two classes identically (thus avoiding messy copies).
---
[ 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: gbush@my-deja.com
Date: 1999/07/15 Raw View
In article <7mglbv$32o$1@nnrp1.deja.com>,
farve@my-deja.com wrote:
>
> 1. Borrow "final" keyword from Java for virtual member functions.
> - A call to a final virtual member function would be direct, and
> not dispatched through the vtable.
Why is there a problem? Use fully qualified name and compiler will call
that virtual function directly.
e.g.
struct Base { virtual void f(){ShowMessage("Base");}};
struct Inherited:Base { virtual void f(){ShowMessage("Inherited");}};
void foo()
{
Base* b = new Inherited;
b->f(); // "Inherited"
b->Base::f(); // "Base"
delete b;
Inherited* i = new Inherited;
i->f(); // "Inherited" thru v-table
i->Inherited::f(); // "Inherited" directly
delete i;
}
Gene.
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ 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: Steve Horne <steve.horne1@bridge.bst.bls.com>
Date: 1999/07/15 Raw View
Fergus Henderson wrote:
>
>
> struct Parent { virtual void foo(); }
> struct Child : Parent { final void foo(); }
> struct GrandChild : Child { /* ... */ }
>
> void bar(Child *p) { p->foo(); }
>
But what about:
void bar(Parent *p) { p->foo(); }
Given a pointer to the base class how do you compile-time bind to your
"final" method?
-Steve
[ 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: Salters <msalters@lucent.com>
Date: 1999/07/16 Raw View
farve@my-deja.com wrote:
>
> 1. Borrow "final" keyword from Java for virtual member functions.
> - A call to a final virtual member function would be direct, and
> not dispatched through the vtable.
> - final virtual member functions defined in the class declaration
> would be eligible for inlining and optimization.
> - Unlike Java, final virtual functions should be allowed to be
> overridden, but should short circuit the vtable when called on a
> type that defines it as final.
> - Not applicable to non-virtual functions.
Java is an interpreted language, unlike C++. Therefore, Java doesn't
have a compiler. C++ has a compiler, and it can determine if a class
is used asa final class. There is no need to force an optimalization
at coding time if the compiler can determine it at compile time.
Furthermore, as others have noted, non-virtual calls can already be
forced.
> 2. Also allow "final" to be used as part of a type (like "const").
> - The compiler could avoid using the vtable for any virtual
> calls on that type.
> - All automatic object could be assumed final.
> - Any virtual functions defined in class declaration would be
> eligible for inlining, and optimization.
> - Type checking could be performed to enforce actual-type
> compatibility (i.e. If a function expects a "final BaseClass*",
> it would not accept a "DerivedClass*".)
> - Any type returned by operator new would be "final"
> - If a final object is never cast down to a base class, inline
> construction and destruction could be optimized to omit the
> vtable entirely.
Again, if you don't want a virtual call then use a non-virtual call,
and let the compiler do as much as possible. You'll be suprised at
much better a compiler is at optimizing
I do fail to see how a final BaseClass* construct would work. Will
g(final BaseClass* pbc) {}
f(BaseClass* pbc) {g(pbc);}
int main(){
f(Derived*);
}
compile?
Why should new return final types? new returns pointers, not objects.
And since pointers don't have vtables, you don't gain a lot.
The only reason for this would be so (new X)->virtualfunc(); wouldn't
need a vtable access. But the compiler sees that the vtable lookup
is a constant expression, and can be elimated (elimination of constant
expressions is a common optimization). Also, this lloks like it leaks
memory.
> I've been working on a standard set of objects, and would like to use
> polymorphism, but incurring the overhead of a vtable is a big waste of
> my meticulously efficient and highly optimizable coding. Using
> the "final" keyword in this way would be incredibly useful. And, would
> make fundamental standard object much more useful.
I don't get it. If you know which functions will be called, it can't be
polymorphism. Polymorphism in the classical sense occurs when you operate
on a pointer for which the static type pointed is a base class of the
dynamic class, or the static class is identical to the dynamic class. This
gives two possibilities, and they must be distinguished, something that can
only happen when the dynamic type is known, i.e. at runtime.
> For example, you
> might want to write a function that receives an std::list<> of objects
> to operate on. But, what if the person calling the function happens to
> need to store the objects in a std::vector<> or std::set<>. Wouldn't
> it be nice if there were an std::iterable<> base class? And, wouldn't
> it be nice if the stl used virtual member functions to dispatch to the
> actual type? And, wouldn't it be nice if it could do all this, without
> sacrificing any efficiency when you know the actual type?
And wouldn't it be nice if somebody told you about templates?
Michiel Salters
---
[ 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: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/07/18 Raw View
In article <378D978D.376A6436@lucent.com>, Salters <msalters@lucent.com> wrote:
> farve@my-deja.com wrote:
> >
> > 1. Borrow "final" keyword from Java for virtual member functions.
> > - A call to a final virtual member function would be direct, and
> > not dispatched through the vtable.
> > - final virtual member functions defined in the class declaration
> > would be eligible for inlining and optimization.
> > - Unlike Java, final virtual functions should be allowed to be
> > overridden, but should short circuit the vtable when called on a
> > type that defines it as final.
> > - Not applicable to non-virtual functions.
>
> Java is an interpreted language, unlike C++.
Not from what I understand. Java is compiled, just like C++. It just uses
a different run-time execution model.
> Therefore, Java doesn't
> have a compiler. C++ has a compiler, and it can determine if a class
> is used asa final class.
Nope. In cases where it is a closed system (i.e. no code linked into the
system at run-time), it can determine that, but in many systems code can
be loaded in at run-time (dynamic link libraries), so the compiler cannot
determine that.
> There is no need to force an optimalization
> at coding time if the compiler can determine it at compile time.
Yes, but the compiler cannot determine that. Furthermore, final wouldn't
just be an optimization - it would also be a static constraint to catch
code that would invalidate assumptions made by code that was aware of the
final attribute of something (i.e. it assumes that nothing is derived from
it).
> Furthermore, as others have noted, non-virtual calls can already be
> forced.
>
> > 2. Also allow "final" to be used as part of a type (like "const").
> > - The compiler could avoid using the vtable for any virtual
> > calls on that type.
> > - All automatic object could be assumed final.
> > - Any virtual functions defined in class declaration would be
> > eligible for inlining, and optimization.
> > - Type checking could be performed to enforce actual-type
> > compatibility (i.e. If a function expects a "final BaseClass*",
> > it would not accept a "DerivedClass*".)
> > - Any type returned by operator new would be "final"
> > - If a final object is never cast down to a base class, inline
> > construction and destruction could be optimized to omit the
> > vtable entirely.
>
> Again, if you don't want a virtual call then use a non-virtual call,
> and let the compiler do as much as possible. You'll be suprised at
> much better a compiler is at optimizing
>
> I do fail to see how a final BaseClass* construct would work. Will
>
> g(final BaseClass* pbc) {}
> f(BaseClass* pbc) {g(pbc);}
> int main(){
> f(Derived*);
> }
>
> compile?
As I posted, it shouldn't. Final would be similar to the opposite of const
- something can be converted implicitly from final to normal, but not the
other way around. This insures that, in the absence of explicit casts to a
final type (or reference/pointer to one), the assumptions made based on
final cannot be violated, and thus the feature is completely type-safe.
> Why should new return final types?
That should be "returns pointer to final type". It is known at
compile-time that the object that the pointer returned by new points to
has the same complete type as the static type the pointer points to.
> new returns pointers, not objects.
> And since pointers don't have vtables, you don't gain a lot.
Don't act dumb :-)
> The only reason for this would be so (new X)->virtualfunc(); wouldn't
> need a vtable access. But the compiler sees that the vtable lookup
> is a constant expression, and can be elimated (elimination of constant
> expressions is a common optimization).
Since the pointer type would point to a type with the final attribute,
this information could be passed around in a type-safe way:
void f( Foo final* foo ) {
foo->virtual_func(); // can statically determine function to call
}
void g( Foo* foo ) { // foo could point to some type derived from Foo
foo->virtual_func(); // function called determined at run-time
f( foo ); // illegal - foo may not point to class derived from Foo
f( final_cast<Foo final*> (foo) );
// safe iff foo points to object of complete type Foo
// similar to making a const_cast<> to a non-const type -
// as long as the type really is non-const, then it is safe
}
void bar() {
Foo final* foo = new Foo;
f( foo );
g( foo );
}
[snip comments about specific design where this feature would be useful]
[ 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/07/18 Raw View
gbush@my-deja.com writes:
>In article <7mglbv$32o$1@nnrp1.deja.com>,
> farve@my-deja.com wrote:
>>
>> 1. Borrow "final" keyword from Java for virtual member functions.
>> - A call to a final virtual member function would be direct, and
>> not dispatched through the vtable.
>
>Why is there a problem? Use fully qualified name and compiler will call
>that virtual function directly.
Using fully qualified names in calls for optimization purposes would
lead to maintenance problems. You'd have to have such annotations
scattered around the program, and if someone adds a new derived class
which does override that function, then the program will break.
In constrast, with `final' on the function declaration, the annotation is
only in one place, rather than scattered around the program, and the compiler
will report an error if any derived class tries to override that function.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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/07/18 Raw View
Salters <msalters@lucent.com> writes:
>farve@my-deja.com wrote:
>>
>> 1. Borrow "final" keyword from Java for virtual member functions.
>> - A call to a final virtual member function would be direct, and
>> not dispatched through the vtable.
>> - final virtual member functions defined in the class declaration
>> would be eligible for inlining and optimization.
>> - Unlike Java, final virtual functions should be allowed to be
>> overridden, but should short circuit the vtable when called on a
>> type that defines it as final.
>> - Not applicable to non-virtual functions.
>
>Java is an interpreted language, unlike C++. Therefore, Java doesn't
>have a compiler.
These statements are incorrect. There are many compilers for Java.
Some of them compile to bytecode, which is then interpreted,
but others compile to native code.
>C++ has a compiler, and it can determine if a class
>is used asa final class.
Not if you have separate compilation or dynamic loading.
>There is no need to force an optimalization
>at coding time if the compiler can determine it at compile time.
The optimizations that you would like to perform for final classes
(e.g. inlining of statically bound method calls) need to be done at
code generation time. Determining whether a class is a final class can
only be done at link time, because any compilation unit could contain a
definition of a derived class. So in order to perform these optimizations
without some kind of source code annotation like `final', you need to
abandon separate compilation, e.g. by delaying code generation until link
time. And if you allow dynamic linking, then it can't be done at all.
Separate compilation and dynamic linking are a very important features,
with many systems making increasing use of shared libraries, DLLs,
and dynamic loading.
>Furthermore, as others have noted, non-virtual calls can already be
>forced.
But only in a way that significant major maintenance problems.
>> 2. Also allow "final" to be used as part of a type (like "const").
>> - The compiler could avoid using the vtable for any virtual
>> calls on that type.
>> - All automatic object could be assumed final.
>> - Any virtual functions defined in class declaration would be
>> eligible for inlining, and optimization.
>> - Type checking could be performed to enforce actual-type
>> compatibility (i.e. If a function expects a "final BaseClass*",
>> it would not accept a "DerivedClass*".)
>> - Any type returned by operator new would be "final"
>> - If a final object is never cast down to a base class, inline
>> construction and destruction could be optimized to omit the
>> vtable entirely.
>
>Again, if you don't want a virtual call then use a non-virtual call,
>and let the compiler do as much as possible. You'll be suprised at
>much better a compiler is at optimizing
>
>I do fail to see how a final BaseClass* construct would work. Will
>
>g(final BaseClass* pbc) {}
>f(BaseClass* pbc) {g(pbc);}
>int main(){
>f(Derived*);
>}
>
>compile?
No. You should get a compile error in f().
>Why should new return final types?
`new T' should return a pointer of type `final T *' because the pointer
that it returns can only point to an object of type T, not to an object
of some class derived from T. Without this, `final Foo* p = new Foo;'
would get a compile error.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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/07/19 Raw View
Steve Horne <steve.horne1@bridge.bst.bls.com> writes:
>Fergus Henderson wrote:
>>
>>
>> struct Parent { virtual void foo(); }
>> struct Child : Parent { final void foo(); }
>> struct GrandChild : Child { /* ... */ }
>>
>> void bar(Child *p) { p->foo(); }
>>
>
>But what about:
>
>void bar(Parent *p) { p->foo(); }
In that case you _want_ dynamic binding.
That's why you made the method virtual in the first place!
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: clamage@eng.sun.com (Steve Clamage)
Date: 1999/07/19 Raw View
Salters <msalters@lucent.com> writes:
>Java is an interpreted language, unlike C++. Therefore, Java doesn't
>have a compiler.
Java most certainly requires a compiler.
Java is compiled into "byte codes", representing the instruction
set of an abstract machine. The byte codes are then interpreted
by software and/or hardware on a real machine. (Machines exist
which execute some of the byte codes directly, interpreting in
software only the more complicated instructions.)
Any language, including C++, could be implemented as interpreted
byte codes in some form. The most famous example probably is
UCSD Pascal. Indeed, the instruction set of any machine could be
thought of as byte codes, although the idea behind byte codes is
that they can be easily interpreted by a wide variety of machines.
>C++ has a compiler, and it can determine if a class
>is used asa final class.
You are thinking of the difference between a language which
supports object type determined at run time, like Java or
Smalltalk, and a language which is statically typed. C++
is mostly statically typed, although a limited form of
run-time typing is supported via virtual functions.
--
Steve Clamage, stephen.clamage@sun.com
---
[ 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: farve@my-deja.com
Date: 1999/07/14 Raw View
1. Borrow "final" keyword from Java for virtual member functions.
- A call to a final virtual member function would be direct, and
not dispatched through the vtable.
- final virtual member functions defined in the class declaration
would be eligible for inlining and optimization.
- Unlike Java, final virtual functions should be allowed to be
overridden, but should short circuit the vtable when called on a
type that defines it as final.
- Not applicable to non-virtual functions.
2. Also allow "final" to be used as part of a type (like "const").
- The compiler could avoid using the vtable for any virtual
calls on that type.
- All automatic object could be assumed final.
- Any virtual functions defined in class declaration would be
eligible for inlining, and optimization.
- Type checking could be performed to enforce actual-type
compatibility (i.e. If a function expects a "final BaseClass*",
it would not accept a "DerivedClass*".)
- Any type returned by operator new would be "final"
- If a final object is never cast down to a base class, inline
construction and destruction could be optimized to omit the
vtable entirely.
I've been working on a standard set of objects, and would like to use
polymorphism, but incurring the overhead of a vtable is a big waste of
my meticulously efficient and highly optimizable coding. Using
the "final" keyword in this way would be incredibly useful. And, would
make fundamental standard object much more useful. For example, you
might want to write a function that receives an std::list<> of objects
to operate on. But, what if the person calling the function happens to
need to store the objects in a std::vector<> or std::set<>. Wouldn't
it be nice if there were an std::iterable<> base class? And, wouldn't
it be nice if the stl used virtual member functions to dispatch to the
actual type? And, wouldn't it be nice if it could do all this, without
sacrificing any efficiency when you know the actual type?
Any thoughts?
- Colen Garoutte-Carson, colen@seanet.com
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ 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: Steve Horne <steve.horne1@bridge.bst.bls.com>
Date: 1999/07/15 Raw View
farve@my-deja.com wrote:
> - A call to a final virtual member function would be direct, and
> not dispatched through the vtable.
I don't think so. The only way a call to a member function can be
resolved at compile time (which is what you are asking for), is that the
exact type of object is known at compile time, which won't work. If you
don't need polymorphism, don't use "virtual".
-Steve
---
[ 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: nospam@slack.net (ant)
Date: 1999/07/15 Raw View
In article <7mglbv$32o$1@nnrp1.deja.com>, farve@my-deja.com wrote:
> 1. Borrow "final" keyword from Java for virtual member functions.
> - A call to a final virtual member function would be direct, and
> not dispatched through the vtable.
> - final virtual member functions defined in the class declaration
> would be eligible for inlining and optimization.
> - Unlike Java, final virtual functions should be allowed to be
> overridden, but should short circuit the vtable when called on a
> type that defines it as final.
Noooo! This introduces the possibility of subtle type errors.
Final would be good for private virtual functions that override from a mixin:
class mixin {
virtual void f() = 0;
};
class Foo : private mixin {
virtual void f(); // final
};
This would prevent derived clients from accidentally overriding these
functions. Considering that Foo could be a distant base class, with a
short name from a mixin, this could easily happen accidentally (yes, you
can override private virtual functions - access control only affects
access to names).
> - Not applicable to non-virtual functions.
>
> 2. Also allow "final" to be used as part of a type (like "const").
> - The compiler could avoid using the vtable for any virtual
> calls on that type.
This seems unnecessary, as it is just an optimization that can currently
be performed anyway:
// not C++
void f( Foo final* foo ) { // foo points to an object of complete type Foo
foo->func(); // statically-resolves
}
// C++ solution
void f( Foo* foo ) {
foo->Foo::func();
}
> - All automatic object could be assumed final.
They can be assumed such anyway (and are, in any decent compiler), so this
would be redundant.
> - Any virtual functions defined in [a final] class declaration would be
> eligible for inlining, and optimization.
Yep.
> - Type checking could be performed to enforce actual-type
> compatibility (i.e. If a function expects a "final BaseClass*",
> it would not accept a "DerivedClass*".)
This doesn't sound very useful for real programs, and is very incomplete.
One could write a helper class to enforce this, anyway:
template<class T>
class only_accept_t {
template<typename X>
only_accept_t( X ); // not defined
T value;
public:
only_accept_t( T t ) : value( t ) { }
operator T () const { return value; }
};
void f( only_accept_t<Foo*> );
void f2( final Foo* );
// neither can take Derived* directly, but can of course take a
// Dervied* that has been converted to a Foo* - not much of a guarantee
Perhaps there wouldn't be an implicit conversion from a non-final type ref
to a final type ref, but there would be an implicit conversion the other
way around. This would allow finality to be preserved:
Foo foo;
Foo final& r = foo; // legal - complete objects have "final" type
Foo& r2 = r; // illegal
Foo& r3 = final_cast<Foo&> (r); // explicit cast - heh heh
You can write a helper class, perhaps, that implements these semantics
(or, during debugging, use the preprocessor to replace "final" with
"volatile", which gives the intended semantics, sort of). Just for
research purposes, of course.
> - Any type returned by operator new would be "final"
And any auto/static/member objects too (as I show above).
> - If a final object is never cast down to a base class, inline
> construction and destruction could be optimized to omit the
> vtable entirely.
I don't see any new opportunities for optimization that the final
attribute would permit in this regard. This analysis can already be
performed by a compiler.
> I've been working on a standard set of objects, and would like to use
> polymorphism, but incurring the overhead of a vtable is a big waste of
> my meticulously efficient and highly optimizable coding.
Well, you can't have your cake and eat it too! If you are using
polymorphism in non-trivial ways, it's non-trivial for a compiler not to
use a vtable.
> Using
> the "final" keyword in this way would be incredibly useful.
I'm sure there are workable alternatives to waiting 4 or so years to see
if this keyword can be added to the language :-)
> And, would
> make fundamental standard object much more useful. For example, you
> might want to write a function that receives an std::list<> of objects
> to operate on. But, what if the person calling the function happens to
> need to store the objects in a std::vector<> or std::set<>. Wouldn't
> it be nice if there were an std::iterable<> base class? And, wouldn't
> it be nice if the stl used virtual member functions to dispatch to the
> actual type? And, wouldn't it be nice if it could do all this, without
> sacrificing any efficiency when you know the actual type?
Wouldn't it be nice if you just told the computer what to do, and it did it?
> Any thoughts?
Show us some real uses of this construct, and alternatives. Figure out how
to hack some form of it into your environment (whether through a simple
template class, preprocessor macros, compiler modifications, magic powers)
and use it. You're bound to improve the idea, or find that it isn't as
useful as you imagined.
---
[ 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/07/15 Raw View
Steve Horne <steve.horne1@bridge.bst.bls.com> writes:
>farve@my-deja.com wrote:
>> - A call to a final virtual member function would be direct, and
>> not dispatched through the vtable.
>
>I don't think so. The only way a call to a member function can be
>resolved at compile time (which is what you are asking for), is that the
>exact type of object is known at compile time, which won't work.
No, that's not the only way. If the virtual member function is declared
"final", and the compiler ensures that "final" member functions cannot
be overridden, then given the code
struct Parent { virtual void foo(); }
struct Child : Parent { final void foo(); }
struct GrandChild : Child { /* ... */ }
void bar(Child *p) { p->foo(); }
the compiler can safely resolve the call to Child::foo,
as if it had been written like so,
void bar(Child *p) { p->Child::foo(); }
even though the actual argument passed could be a pointer to an object
of type `GrandChild'. This optimization is safe because the GrandChild
class cannot override the definition of foo() in Child.
>If you don't need polymorphism, don't use "virtual".
What if you need polymorphism at the root of your object hierarchy,
but you don't need it at some point further down the hierarchy?
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
[ 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 ]