I don't have to tell you...

B

Bo Persson

Joshua said:
After reading more, I'm still not quite clear on what Howard Beale
want, so I ask again. More clearly: what is wrong with C++, its
order of construction and destruction, and how virtual calls
interact.

Let's first presuppose that constructors and destructors themselves
are not broken. Correct me if you think they are.

That leaves us with this heated, and quite unclear, discussion about
which function should be called when you call a virtual function in
a constructor or destructor. I think our options are:

1- Call function on uninitialized (or destroyed) derived class. This
will almost certainly be bad, and not what the programmer intended
(or the programmer is not familiar with the language and good code
design, and the design is bad).

2- What is currently done. It goes to the most derived currently
constructed object.

3- Disallow virtual function calls on objects under construction or
destruction.

I think I like #2 the most, though I can see some utility from #3.
Howard, I still think you are arguing for #1, and I strongly
disagree with that option on my knowledge and years of experience.

A agree with this, and believe that in the few cases where #1 might
actually work is where it just returns a fixed value to the caller. In
those rare cases, the value could just as well be a parameter to the
base class' constructor.


Bo Persson
 
P

Pavel

Alf said:
* Pavel:

class BT
{
private:
virtual void bar() { say( "BT" ); }
public:
void foo() { bar(); }
};

class T
: public BT
{
private:
virtual void bar() { say( "T" ); }
public:
T() { foo(); }
};

class D
: public T
{
private:
std::string myPavelonian;
virtual void bar() { say( myPavelonian.c_str(); }
public:
D(): myPavelonian( "D" ) {}
};

int main() { D(); }

Works well with C++ rules, calling T::bar as the T programmer intended.

Undefined behavior with Pavel/Howard rules.

Contrary to your claim there's no way to use explicit qualification in
class T or in class BT to make it call T::bar with Pavel/Howard rules.
T::T() { T::bar(); } /* "no way" puzzle solved in a one-liner; the
desired behavior achieved. BTW what was the purpose of foo() (other than
obscuring the question)? Reading or re-reading this
http://chalain.livejournal.com/39332.html may help you map requirements
to source code in a more straightforward way. */

BTW. If you believe your way of selecting variable names is funny, you
are fooling yourself. In me personally, it raises a doubt about a
possibility of impersonal technical conversation with you. I am not sure
know how much longer I will want to answer to posts obeying the like
"coding standard" or other personal references so don't get surprised or
too pleased by yourself for writing a smart post if you find it left
without a reply from me.
Yes, it would be bold to require undefined behavior.
Business requirements are well defined. The behavior of my code above is
well defined under the current Standard. It would be well defined under
the more reasonable standard that Howard and myself would like to see,
too. Your code's behavior would be undefined under such a Standard. This
would be your code's issue. Under the current Standard, it is possible
to write a lot of code with undefined behavior. Everybody knows this and
C++ is not judged by how easy it is to write code with undefined
behavior. Everyone would agree it is very easy to do. C++ is judged by
how easy it is to write the code that solves a particular problem and
how easy it is to read and understand the code.

Try to make the following code (that means to track the creation of
objects of classes derived from Object and that would work under "our"
rules), work under the current Standard's rules. Try to fairly estimate
the difference in the cost/complexity of the resulting code:

void say(const char *msg) { cout << msg << '\n'; }

class Object {
public:
Object() { say(name()); }
virtual const char *name() {return "Object";}
};

class Foo : public Object {
public:
const char *name() { return "Foo"; }
};

class Bar : public Object {
public:
const char *name() { return "Bar"; }
};

int main() { Foo o; Bar o1; return 0; }


Hth.,

- Alf

Cheers,
-Pavel
 
P

Pavel

Bo said:
You shouldn't always give people what they believe they want. :)

Calling a virtual function on a non-existing object is one of those
things. Here C++ avoids undefined behavior by defining that you can
only call the function for the object that actually exists at that
point.
Are we being completely honest here referring to the object as
"non-existing"? Under the current rules it does not exist but we are
discussing the quality of this very rules, aren't we? Under the proposed
(and time-tested) changed rules it would be existing, just not fully
initialized. Calling functions (virtual or not) on a
not-fully-initialized object is nothing new: a member function called
from the constructor is called on a not-fully-initialized object. What
is a point of discussing the conceptual correctness of letting people
call functions on a not-fully-initialized object when they already can
do it?
My impression is that C++ tries to avoid the shoot-in-the-foot
Not to avoid, but make it harder:
"In C++ it's harder to shoot yourself in the foot, but when you do, you
blow off your whole leg." — Bjarne Stroustrup.

It did not mean to make legitimate work harder, though. And the ability
to express useful ideas always comes at cost of danger. Remember
standard Pascal? It was clearly as safe as a language can get; so safe
that it was impossible to write anything useful in it (useful varieties
like Turbo Pascal introduced external modules, so they became useful but
lost the ability to statically proof the correctness). Certainly it is a
matter of personal choice where to draw the line and that's to try to
throw in some objectivity I refer to Java: From both my experience and
the prevalent opinion, Java is much safer language than C++ (and
respectively slightly less universal and capable). Therefore a litmus
test to me is: if something is safe enough for allowing it in Java, not
including that same capability in C++ for safety reasons is probably not
a good idea.
situation whenever possible (and without a run-time cost :). This
does leave some opportunities for blowing a leg off, for the
adventurous programmer.


For some definition of work. I'm no Java expert, but from what I
understand the cost you want to avoid in 2) now moves to a test for a
fully constructed object in every call to the function.
Nah, it just lets you slip (Java!); see
http://en.wikipedia.org/wiki/Virtual_function#Java_2.

BTW, I just found the reference to this article of Scott Meyers ibid in
Wikipedia: http://www.artima.com/cppsource/nevercall.html. I think
logically those who agree with this his opinion should agree to us
(Howard and myself) as well: what a point in having a "safety feature"
that is recommended to be used .. never?

I say "logically" because Scott himself would apparently disagree:

"... That's how every part of C++ will treat it, and the treatment makes
sense: the BuyTransaction-specific parts of the object haven't been
initialized yet, so it's safest to treat them as if they didn't exist".

I, on the other hand, cannot see a big difference between calling any
function within a constructor (where some parts of an object may not
have been initialized yet) and calling a virtual function ibid. I
believe that treating the derived-class object as "non-existing" before
entering its construction function is an arbitrary and not very useful
choice of the Standard.
My point is that the derived object should fully construct itself, and
not depend on the base object calling some function during its
construction. It is about the distribution of responsibilities.
See, if only purpose why constructors are used were the initialization
of the parts of the constructor's specific class I could agree to that.
In practice, however, there are other tasks that are hooked to the
constructors (because there is no other hooks in C++ for doing that in
general case). For example (the list is certainly incomplete):

1. To track creation of all objects in hierarchy where class-specific
information is necessary for tracking.
2. To complete the initialization of parallel bases.
3. To Register all created objects from hierarchy somewhere where the
registration data, registrar or registration algorithm is
derived-class-specific (that is, specific to static members of the
derived class or its state-independent behavior).

If C++ allowed an easy and inexpensive way of hooking in these (I am
aware of a wrapper/handler-based method but do not consider it easy
enough of inexpensive), a lion share of the current needs may have been
eliminated (I am not sure about all of them). As it is now, I see Java
behavior more beneficial.

-Pavel
 
A

Alf P. Steinbach

* Paavo Helde:
I think what he really wants is to define a function in derived class,
which can be called during construction and destruction of base class. As
such, this function cannot touch derived class data, neither call other
derived class functions which do this. This means that the function
effectively is a base class function, but defined in the derived class, and
presumably overrides some behavior of the base class function having the
samen name.

I just gave a C++ implementation example of such a function in another
post.

Uhm, this issue is covered in the FAQ.


Cheers & hth.,

- Alf
 
H

Howard Beale

Joshua said:
After reading more, I'm still not quite clear on what Howard Beale
want, so I ask again. More clearly: what is wrong with C++, its order
of construction and destruction, and how virtual calls interact.

I think it's pretty clear from his first handful of posts that Howard Beale
just doesn't care much for C++ or OOP in general.

Let's first presuppose that constructors and destructors themselves
are not broken. Correct me if you think they are.

Well, more explicit control might be nice. For example, have the compiler
only call the most-derived class's constructor/destructor and allow the
programmer to call bases classes' constructors/destructors if and when
needed, in whatever order is safe. Then any virtual methods involved in
the process could also safely resolve to the most-derived class. And it
would just be more consistent, in general, because then constructors and
destructors would work like any other virtual method: code in the base
classes is overridden (not executed) unless explicitly called or
duplicated.

That leaves us with this heated, and quite unclear, discussion about
which function should be called when you call a virtual function in a
constructor or destructor.

That was actually just one of the issues named, and everyone latched onto
that, specifically. Probably because it's fairly commonly a topic of
discussion here.
 
H

Howard Beale

Krice said:
There is no other problem than people who suck as
programmers. Some of them learn to become better programmers,
others blame the programming language/paradigm.


Well, there you have it. Krice has settled the issue for us all. C++ is
perfect and if you complain about it you are an ugly, lame, retarded loser
with no life and no girlfriend and bad breath and skid marks in your
underwear. Thank you, Krice. Sorry that the rest of us are taking up
valuable space in your discussion group. I have just killfiled all users
in this group other than Krice, including myself, so that I can get right
down to the good stuff.
 
J

Joshua Maurice

BTW, I just found the reference to this article of Scott Meyers ibid in
Wikipedia:http://www.artima.com/cppsource/nevercall.html. I think
logically those who agree with this his opinion should agree to us
(Howard and myself) as well: what a point in having a "safety feature"
that is recommended to be used .. never?

I say "logically" because Scott himself would apparently disagree:

"... That's how every part of C++ will treat it, and the treatment makes
sense: the BuyTransaction-specific parts of the object haven't been
initialized yet, so it's safest to treat them as if they didn't exist".

I, on the other hand, cannot see a big difference between calling any
function within a constructor (where some parts of an object may not
have been initialized yet) and calling a virtual function ibid. I
believe that treating the derived-class object as "non-existing" before
entering its construction function is an arbitrary and not very useful
choice of the Standard.

Simple example.

//
#include <string>

struct F
{
virtual std::string const& name() const =0;
};
struct G : F
{
std::string name_;
virtual std::string const& name() const { return name_; }
};
//

Now, if I wrote that sample correctly, let's look at F and G. Suppose
F's constructor calls name() for debugging purposes. If it were to go
to the most derived but not yet constructed object G, then it would
return a reference to the not yet construct string sub-object, and any
attempt to use it would probably crash because it's not initialized:
the internal pointer of std::string would point to garbage and
dereferencing it would crash or be equivalently bad. Moreover, if
instead of string you had an object with virtual functions, then
calling anything on it would be bad because it's virtual table has not
yet been set up, so calling any virtual function on the sub-object
would horribly fail.

To repeat your statement:
I
believe that treating the derived-class object as "non-existing" before
entering its construction function is an arbitrary and not very useful
choice of the Standard.

Generally speaking, calling any sort of member function on any
nontrivial class which has not been initialized will dereference an
uninitialized pointer or do some equally bad thing because of the
uninitialized data. That's the reasoning behind this decision by the
standard to make virtual calls not go to member functions of classes
which have not yet been initialized or started initialization. I would
claim that it's quite a rare class which it makes sense to call member
functions on it without basic initialization of the data. (Well,
unless that member function is a setter, aka that member function is
initialization.)

It's a very useful guarantee to know that in a constructor that all of
your sub-objects (base class sub-objects and member sub-objects) have
been constructed. It's part of the whole thrust of C++ to not (easily)
allow access to unconstructed or destroyed objects. Ex: The "new"
operator returns a fully constructed object, you can't access an
uninitialized object through virtual pointers, etc. The whole language
and standard are built around this idea. I like it. It works for 99%
of cases. I don't recall yet seeing a case which I would actually want
to define a different construction order, nor call functions on an
object which has not been initialized.
 
J

Joshua Maurice

I think it's pretty clear from his first handful of posts that Howard Beale
just doesn't care much for C++ or OOP in general.


Well, more explicit control might be nice.  For example, have the compiler
only call the most-derived class's constructor/destructor and allow the
programmer to call bases classes' constructors/destructors if and when
needed, in whatever order is safe.  Then any virtual methods involved in
the process could also safely resolve to the most-derived class.  And it
would just be more consistent, in general, because then constructors and
destructors would work like any other virtual method: code in the base
classes is overridden (not executed) unless explicitly called or
duplicated.

At this point, I think your opinions are rather irrelevant because
you're attacking all of OOP, not just this one small aspect of C++.
You're saying that X sucks because of some inherent quality of X. In
other words, I now see this as not really an attack on constructor
destructor order. Any sane OOP requires this constructor destructor
order. You just dislike OOP in general.

I still think you're wrong, but at least you're not longer acting as
if blatantly trolling. Your arguments have been much more civil and
reasonable.

To reply to this specific point:
For example, have the compiler
only call the most-derived class's constructor/destructor and allow the
programmer to call bases classes' constructors/destructors if and when
needed, in whatever order is safe.

My succinct reply is that I find automatic calling of sub-object
constructors to be a very useful syntactic sugar which saves typing
time and bugs (from not having to remember to construct my base class
sub-objects). In my years of programming I have never once found
myself wishing "If only I could delay construction of a sub-object for
just a little longer", or at least when I have wanted that, I just
change the member sub-object into a pointer and new and delete the
former sub-object whenever I need. (Maybe in a really crazy embedded
system this might come up, but then I really wouldn't be using such
OOP idioms anyway as I'm under different fundamental constraints.)
That was actually just one of the issues named, and everyone latched onto
that, specifically.  Probably because it's fairly commonly a topic of
discussion here.

So, do you really want to allow calling functions on uninitialized or
de-initialized objects? Again, it breaks all of the standard idioms
and practices of C++, those which say you're only allowed to operate
on a "live" object. You rarely need to do anything else, and in those
rare situations, OOP isn't really what you'd be doing anyway, and you
can still do that other stuff in C++. C++ doesn't restrict you to
this, but it offers it to you. The best of both worlds for the
programmer who knows what he's doing.
 
C

Chris M. Thomasson

Simple example.
//
#include <string>
struct F
{
virtual std::string const& name() const =0;
};
struct G : F
{
std::string name_;
virtual std::string const& name() const { return name_; }
};
//
Now, if I wrote that sample correctly, let's look at F and G. Suppose
F's constructor calls name() for debugging purposes. If it were to go
to the most derived but not yet constructed object G, then it would
return a reference to the not yet construct string sub-object, and any
attempt to use it would probably crash because it's not initialized:
the internal pointer of std::string would point to garbage and
dereferencing it would crash or be equivalently bad. Moreover, if
instead of string you had an object with virtual functions, then
calling anything on it would be bad because it's virtual table has not
yet been set up, so calling any virtual function on the sub-object
would horribly fail.


FWIW, I have seen this type of error quite a few times when I am looking at
thread wrapper's implemented as a base class. The base class run's the
thread from the damn constructor, which in turn calls a pure virtual
function to invoke the derived class thread entry point. This is a major
race-condition. If the thread runs and calls that virtual function BEFORE
the derived class is FULLY constructed, BOOOOM! You're dead!


Here is a quick example:
__________________________________________________________________
#include <sched.h>
#include <pthread.h>
#include <cstdio>


#define YIELD sched_yield(), sched_yield(), sched_yield


extern "C" void* thread_base_entry(void*);


class thread_base
{
pthread_t m_tid;
virtual void on_entry() = 0;
friend void* thread_base_entry(void*);


public:
thread_base()
{
pthread_create(&m_tid, NULL, thread_base_entry, this);
YIELD(); // LOL!
}


void join()
{
pthread_join(m_tid, NULL);
}
};


void* thread_base_entry(void* state)
{
thread_base& this_ = *static_cast<thread_base*>(state);
this_.on_entry();
return NULL;
}


class foo : public thread_base
{
void on_entry()
{
std::puts("Hello from foo!");
}


public:
foo()
{
std::puts("Hello from foo's CTOR!");
}
};


int
main()
{
{
foo f;

f.join();
}

return 0;
}
__________________________________________________________________



This will probably crash, then again it might not because the whole thing is
a giant race condition.



What a MESS!

:^o



[...]
 
K

Krice

C++ is perfect and if you complain about it

You can complain about it until the end of days, but it
will not make you a better programmer. When you work with
language X it's obvious that you need to adapt to what the
creators of the language thought. If you can't do that,
try some other language. I have no difficulties with
C++, but then again I'm a genius, far superior than
average people.
 
H

Howard Beale

Joshua said:
At this point, I think your opinions are rather irrelevant because
you're attacking all of OOP, not just this one small aspect of C++.
You're saying that X sucks because of some inherent quality of X.

What? Why would that make an argument irrelevant? Getting-shot-in-the-
face sucks because of the inherent quality of getting-shot-in-the-face
that it makes you dead. If something sucks, it sucks. I'm not the
first person in the world to think OOP sucks, and the arguments made
here (against it) are really some of the least original.

In other words, I now see this as not really an attack on constructor
destructor order. Any sane OOP requires this constructor destructor
order. You just dislike OOP in general.

I still think you're wrong, but at least you're not longer acting as
if blatantly trolling. Your arguments have been much more civil and
reasonable.

Well **** that. I won't let that happen again.

To reply to this specific point:


My succinct reply is that I find automatic calling of sub-object
constructors to be a very useful syntactic sugar which saves typing
time and bugs (from not having to remember to construct my base class
sub-objects).

It doesn't save much typing. And it encourages just as many bugs as it
prevents, probably more. And it's inconsistent -- with any other
virtual method, the programmer must choose to call the base class
version if he wants it to be executed, but constructors and destructors
get this special treatment.

In my years of programming I have never once found
myself wishing "If only I could delay construction of a sub-object for
just a little longer"

Yeah, I find it annoying far more often in destructors than in
constructors.

So, do you really want to allow calling functions on uninitialized or
de-initialized objects? Again, it breaks all of the standard idioms
and practices of C++, those which say you're only allowed to operate
on a "live" object.

Yes, because that's the spirit of C++. If the programmer wants to shoot
himself in the foot, then he should be allowed.

For example, I remember running into the oh-so-popular "OnInitDialog"
bug. For anyone who hasn't seen it before, it's a textbook example of
the behavior we're talking about. The function OnInitDialog() is a
method in the MFC's CDialog class. You're expected to override the
function and initialize your own dialog's controls there. And just
about everyone runs into this weird assertion that looks something like
this:

ASSERT:):IsWindow(m_hWnd))

I mean seriously, EVERY SINGLE newbie EVER hits this bug on their first
foray into MFC. The reason for the assertion is that you've done this:

BOOL MyDialogClass::OnInitDialog()
{
my_control_1.do_something();
my_contril_2.set_something("string");

return CDialog::OnInitDialog();
}

You need to call the base class version *before* doing anything with the
controls. But you're free to do other things (setup data structures, or
whatever) before. That's the nature of the beast. You need to
understand what the base class does before you go deriving your own
class from it. Constructors and destructors don't need to be any
different. Hitting an ASSERT() is good if it encourages the newbie to
understand what the code he's using is actually doing.
 
H

Howard Beale

Krice said:
try some other language. I have no difficulties with
C++, but then again I'm a genius, far superior than
average people.

I already know this well. I could tell instantly from the eloquence of
your posts that you are "far superior than average people." You are
preaching to the choir, my man. I also suspect that you ARE one of the
creators of C++, and probably many other languages. I have brought great
shame to myself and my entire family by speaking out against C++. But in
my defense, I did so only before I knew that YOU were the primary driving
force behind its creation. Please be merciful in your judgement of me.
 
B

Balog Pal

"Howard Beale"
For example, I remember running into the oh-so-popular "OnInitDialog"
bug. For anyone who hasn't seen it before, it's a textbook example of
the behavior we're talking about. The function OnInitDialog() is a
method in the MFC's CDialog class. You're expected to override the
function and initialize your own dialog's controls there. And just
about everyone runs into this weird assertion that looks something like
this:

ASSERT:):IsWindow(m_hWnd))

I mean seriously, EVERY SINGLE newbie EVER hits this bug on their first
foray into MFC. The reason for the assertion is that you've done this:

Ah, more lies. I was a newbie, I used MFC (a lot), never had a problem
wioth that.

Maybe I read the MFC dox? Maybe I used it as intended by creators: click the
message to create the handler -- then put my code where it said

//TODO: insert your code here

? That was certainly *after* the call of the original?
BOOL MyDialogClass::OnInitDialog()
{
my_control_1.do_something();
my_contril_2.set_something("string");

return CDialog::OnInitDialog();
}

Quite obviously your control objects are bound wo UI objects in that last
call. MFC uses two-phase setup for many things.

Guess saying

CFile file;
file.Read(....);

is as surprizing -- who woud think to Open the frelling file? By either
calling Open, or using the ctor version that does that.

Or newbie is defined as 'I never RTFM, and have the right to troll if
something will not work as I just hack around random code'?
You need to call the base class version *before* doing anything with the
controls.

More precisely, you have to Attach() or use some similar 2nd phase init call
on your controls, directly or indirectly. And in general, have a clue about
both windows and the framework to do anything sensible. If so, work can be
done -- and having the bonus of hitting sensible asserts in *debug* builds
is good, when you do some clear nonsense.

Dereference a NULL pointer or sending message to a unknown window qualifies
fine.
But you're free to do other things (setup data structures, or
whatever) before. That's the nature of the beast. You need to
understand what the base class does before you go deriving your own
class from it. Constructors and destructors don't need to be any
different.

And they aren't. Actually nothing fobids an implementation to add turn the
language into a kindergarten, and generate code with asserts on a whim...
Or generate warnings like that.

The mentioned VC does it too -- using this in the member init list triggers
a warning. One that would make sense to those trying to use it right away,
and annoying to those who just store it for later. Same could be done for
any other use case, maybe it would make the build time explode, or annoy
more users who actuallt did RTFM and know what they do -- or just use other
more straightforward means to detect traps as testing. TANSTAAFL. Decision
to just leave it can be is as reasonable, or more so.

There are open source compilers, you can do it yourself, or convince other
developers how cool your way would be -- real life compilers come with cool
extensions.

Sure actual work is hard, while whining is cheap.
 
C

Christopher Dearlove

Pavel said:
void say(const char *msg) { cout << msg << '\n'; }

class Object {
public:
Object() { say(name()); }
virtual const char *name() {return "Object";}
};

class Foo : public Object {
public:
const char *name() { return "Foo"; }
};

class Bar : public Object {
public:
const char *name() { return "Bar"; }
};

int main() { Foo o; Bar o1; return 0; }

class Object
{
public:
explicit Object(const char * name) { say(name); }
};

class Foo : public Object
{
public:
Foo() : Object("Foo") {}
};

class Bar : public Object
{
public:
Bar() : Object("Bar") {}
};

or if you prefer

class Foo : public Object
{
public:
Foo() : Object(name()) {}
static const char * name() { return "Foo"; }
};
 
C

Christopher Dearlove

Christopher Dearlove said:
class Object
{
public:
explicit Object(const char * name) { say(name); }
};

class Foo : public Object
{
public:
Foo() : Object("Foo") {}
};

class Bar : public Object
{
public:
Bar() : Object("Bar") {}
};

or if you prefer

class Foo : public Object
{
public:
Foo() : Object(name()) {}
static const char * name() { return "Foo"; }
};

Following myself up, or if you really want to:

typedef const char * (* Name)();

class Object
{
public:
explicit Object(Name name) { say(name()); }
};

class Foo : public Object
{
public:
Foo() : Object(name) {}
static const char * name() { return "Foo"; }
};
 
H

Howard Beale

Balog said:
Ah, more lies. I was a newbie, I used MFC (a lot), never had a
problem wioth that.

Well, that's because you (and Krice) are "a genius, far superior than
average people."

Maybe I read the MFC dox? Maybe I used it as intended by creators:
click the message to create the handler -- then put my code where
it said

//TODO: insert your code here

? That was certainly *after* the call of the original?

I'm sure it was, but most of us probably removed that comment once we
inserted some code. From there, it was fairly easy to forget when
changing the code later. But, like I said, you are clearly more evolved
and would not have such a problem, even when you were a newbie.

More importantly, I clearly wasn't complaining about the behavior of
OnInitDialog(). I was using it as an example to point out the
difference in the way that "regular" virtual methods behave, compared to
the way that constructors and destructors behave. If constructors and
destructors weren't chained, and it was up to the programmer to call the
base class versions, you'd see newbies running into the same issue as
they do in OnInitDialog(). My point was that it would be acceptable
because they ALREADY run into that behavior everywhere else. And this
entire discussion that we're having now -- which is apparently common
enough that it warrants a FAQ -- would be unnecessary.

And they aren't.

They aren't? Then I guess this whole discussion was based on a false
premise. I was under the impression that constructors and destructors,
unlike other virtual methods, were automatically "chained" for you by
the compiler. Apparently other posters in this thread were under the
same impression.

Actually nothing fobids an implementation to add turn the language
into a kindergarten, and generate code with asserts on a whim... Or
generate warnings like that.

I have no idea what this sentence means.

Sure actual work is hard, while whining is cheap.

I like to think that I take whining to a new level. Whining with my
astounding level of insight is actually quite hard. You seem to be
under the impression that I'm looking for a solution to this one little
issue with the "virtual" keyword. It was just one of a bunch of
complaints about C++. I can't really control which issues the rest of
comp.lang.c++ chooses to discuss -- this one just happened to be
popular.

As I've said elsewhere in this thread, I do have a solution to the
problem, as well as the other issues that weren't even addressed here.
So, it's fair to say that I've done equal parts "actual work" and
"whining." I am fine with that. I'm allowed to point out what I
dislike about C++, or OOP, regardless of whether or not I have a working
alternative.
 
J

Joshua Maurice

What?  Why would that make an argument irrelevant?  Getting-shot-in-the-
face sucks because of the inherent quality of getting-shot-in-the-face
that it makes you dead.  If something sucks, it sucks.  I'm not the
first person in the world to think OOP sucks, and the arguments made
here (against it) are really some of the least original.

Let me use an analogy. Suppose you go to a circus and declare that you
don't like the clown's hats. In actuality, you just don't like any
kind of clown, but their hats is one of your reasons, but not your
only reason, for not liking clowns. if your actual and only problem
was with the clown's hats, then maybe the owner would change their
hats for you. However, the owner will not care about your hat problem
as soon as he learns that you hate all kinds of clowns.

To go back from analogy. I might care more about your complaints on
constructor destructor order, and virtual calls going to the currently
constructed object vs not-constructed most-derived, if you actually
used objects at all. Even if I changed these things, presumably you
still wouldn't use them.
 
B

Balog Pal

Howard Beale said:
They aren't? Then I guess this whole discussion was based on a false
premise. I was under the impression that constructors and destructors,
unlike other virtual methods, were automatically "chained" for you by
the compiler. Apparently other posters in this thread were under the
same impression.



I have no idea what this sentence means.

From the original it seemed your problem is that there are no ASSERTs
provided when the ctor/dtor case is messed up.

Turns out it is chaining. Sure, there is a difference. But for a very good
reason. ctors/dtors must chain for correctness. In proper order too.

Normal virtuals can just replace the original entirely (and the original may
not even exist, unlike!). Or may call the original. As first tging, or the
last thing, or in the middle.
I like to think that I take whining to a new level. Whining with my
astounding level of insight is actually quite hard. You seem to be
under the impression that I'm looking for a solution to this one little
issue with the "virtual" keyword.

No, at your original post it looked like mindless trolling, I was only
dragged in by Alf's unfortunate claims.

After discussion it looks less trolling, but that you have pretty little
understanding of what's going on and why. But build an even stronger
opinion. I'd suggest read books like Design & Evolution of C++. Or Matthew
Wilson's Imperfect C++.

Guess if you did that with open mind, afterwards reading your own post would
just say OMG.
As I've said elsewhere in this thread, I do have a solution to the
problem, as well as the other issues that weren't even addressed here.

A solution that needs change of language, or one that accepts it in current
form, and is like a workaround?

For the first kind you're in the wrong place -- comp.std.c++ is ways better,
and you could have simply start with pointing to the proposals you
submitted, or put down your draft to discuss. It would probably drawn
some positive interest even if we know well that there is a feature-close
mode.

For the second, again, you could have started with the solution, if you
actually have them -- as the "problems" hardly worth a yawn, those who
work with the language did find workarounds for mush more realistic
things, or read about them in really elaborate books like just mentioned
Wilson's.
So, it's fair to say that I've done equal parts "actual work" and
"whining." I am fine with that.
I'm allowed to point out what I
dislike about C++, or OOP, regardless of whether or not I have a working
alternative.

You know the "law of assholes": everyone have one, and dont much care about
someone other's... Same goes for opinions.

I for example don;t like java, but never had the urge to go to a java forum
and start saying how much it sucks. Can find better things to spend time
on.
 
H

Howard Beale

Balog said:
A solution that needs change of language, or one that accepts it in
current form, and is like a workaround?

A solution that circumvents C++ entirely. In fact, it's so far from C++
that it's really not even appropriate to discuss here. However, it still
provides all the benefits of C++ (or any other OOP language), as well as a
few more perks that they don't offer. It is built on top of C, mostly.
The only reason I chose to attack C++ is that, despite how much I dislike
it, it really is currently the best choice that there is. One of the very
first posts in this thread summed it up nicely:

"C++ is bad. It's just that all of the reasonable alternatives
are worse." - James Kanze

I really expected the responses to be more along the lines of "**** off,
troll, C++ rules." If the religiously fanatical defenders of C++ aren't
lurking in this group, I don't know where they are...

You know the "law of assholes": everyone have one, and dont much care
about someone other's... Same goes for opinions.

I for example don;t like java, but never had the urge to go to a java
forum and start saying how much it sucks. Can find better things to
spend time on.

Hot damn, that is seriously a really good point. Maybe the best point in
this entire thread. I didn't expect to spawn such a huge discussion -- I
actually assumed that criticism of C++ was common enough that no one would
really even notice. I don't know, sometimes it's just fun to pick on an
easy target. The intense blowback that I got actually made me start to
think, "Hey, maybe there's really something to this."
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,059
Latest member
cryptoseoagencies

Latest Threads

Top