Advertisement

Classes Vs. Straight Code

Started by June 26, 2000 01:30 PM
91 comments, last by farmersckn 24 years, 5 months ago
Uh, I thought DirectX was COM based... Isn''t it? I thought COM was done using classes... I could be dead wrong, cuz I''m new to COM, but I also thought they had everything done in C for compatibility with the C programmers. I doubt they did it in Visual Basic also, but that''s the other language it''s been released in (for the programmers, I mean).

Sometimes even chickens need to eat... Don't bang your head against a wall just to enjoy the good feeling when you stop.
Yesterday is the past, tomorrow is the future. Today is a gift, that is why we call it the present.
COM is only a standard for exporting interfaces, nothing to do with the language internally, I''ve only ever made COM objects in VB for example. Likewise any ms language can call COM, C,C++,VB, vbscript etc

But this is getting away from the nice argument.

Personally I''m of the opinion that if you''ve got time to have a rant that''s like, 20 pages long, then your obviously to blame for wasting all of your own time on something you didn''t like. No point blaming a language for you not liking it. I don''t like apples, doesn''t mean I''ll eat them for 7 years before deciding to have a big spit about how much they suck. If Sean thought C++ was such a heap of shit than he would have abandond it years ago and there would have been no reason for the rant. If it was a company decision than his issue lies with the tools that were chosen for him not the tool.

I have no interest in wether his points are correct, really, every language has bits you can''t conceive of the reason for. Simple example, for months I couldn''t grasp the reason why switch''s fall through, then one day I needed the feature to do something. The only way for me to get a programming language that''s exactly the way I want it is to code it up myself and I''m not so arrogant to think I''ll do a better either.

Any language is a huge set of compromises. No language is pure. They are tools to be used as they are. This discussion should be more to do with the applicability of C over C++ to games development. (rhetorical questions) Which tool set best matches the problem? Whats is the one true religion? Whats better, Red or Blue?

gimp

PS : Don''t get me wrong, I''m quite interesting in hearing about how the tools differ, just not when people use wooden mallets to chop down tree''s and not how crappy the mallet is because it took them so long.
Newbie alert : Don''t read things like that, the most valuable skill you can develop as a programmer is knowing when to use what tool.
Chris Brodie
Advertisement
quote: Original post by gimp

The most valuable skill you can develop as a programmer is knowing when to use what tool.



That''s it exactly, and what I''ve been trying to say forever




Give me one more medicated peaceful moment..
~ (V)^|) |<é!t|-| ~
ERROR: Your beta-version of Life1.0 has expired. Please upgrade to the full version. All important social functions will be disabled from now on.
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
well ... im just learning C++ ... i just finished my linked list class --> Ill never use C again -)

just my 2cp
maikgerth, for Germany, that''s 2 Eurocent ))


Give me one more medicated peaceful moment..
~ (V)^|) |<é!t|-| ~
ERROR: Your beta-version of Life1.0 has expired. Please upgrade to the full version. All important social functions will be disabled from now on.
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
hehe not yet
Advertisement
OK, I finally went over that article in great detail, and figured out all of the arguments. Whew! What a chore!!

Anyway, I hope you learn the facts about these (typical) arguments against C++. BTW, I'm prepared to back up all of my statements here with proof, so you're welcome to reply if you have any questions.

Enjoy!


quote: Article: Why C++ Sucks

C++ sucks because it is a mis-designed pile of crap.

All you have to do is read Bjarne Stroustrop's book on the design and evolution of C++ to understand why: C++ is the iMac of computing languages.

It was designed to have those features necessary to achieve popular success--not those features necessary to be a good programming language.

In the case of something like the iMac, much of the "prettiness" does not necessarily come at the expense of functionality--but this is not always the case. Reducing the iMac's expandability makes it simpler to use--but also potentially consigns it to a gutter market a few years down the road.


FACT: He wrote this article with a bad attitude regarding C++.
FACT: Writing an article in frustration is called a rant.
FACT: Rants are rarely based on sound evidence.

Sean Barrett doesn’t know squat about language design, or programming methodologies, for that matter.

quote: Article: Why C++ Sucks

In Stroustrop's mind, making C++ compatible with C was instrumental, crucial to its success.

I don't disagree. Plenty of other good object oriented languages are out there, and they've never found much success. Certainly the overhead of learning a brand new language is undoubtedly a significant barrier to acceptance.

I don't think it's any coincidence that Java chose to use C syntax for its core constructs, either.

But C++ went far further than Java in compatibility. C code works nearly unchanged in a C++ compiler. The model of how a C++ program can be separately compiled (i.e. split into multiple separate files) is identical to that of C.

But this introduces hosts of other problems, some which C++ addresses, some of which it addresses with problematic design, and some of which it simply falls down on.

This is not to laud Java--I do not have a particularly high opinions of that language. It does many good things, but owing to its history it also has some odd design elements. (Foremost amongst them being reliance on interpreters during its initial introduction.)


Well, that’s a hard argument to dispute. Of course, it’s kind of hard to dispute an argument that doesn’t make any points…I’ll take it as the (second) intro to this article. There are tidbits of truth in there, however.

FACT: C is a subset of C++.


quote: Article: Why C++ Sucks

C++'s biggest problem is its size. People will tell you that this is no big deal; just subset C++ down to whatever part of it you're willing to use; that can be a C subset or something a little larger, or the whole thing.

This logic can be used to justify an infinitely complex language, so one should hesitate to accept it at face value.

The biggest flaw with the argument is that it forces compiler writers to implement a larger language; correctness will be harder to get right, and optimization will suffer. In the case of C++, however, this no longer matters; there are essentially no "just C" compilers anymore to compare to, so any lowered performance of C++ is no doubt also seen by C.

Another significant problem is that it requires an investment of effort to select an appropriate subset. Moreover, you will have difficulty finding books that teach this subset; and, indeed, if you acquire a C++ algorithms book, the odds that the subset chosen for that book matches that of yours is low.

In other words, subsetting is the same as fragmenting the language into lots of separate dialects; it has all the same problems as that, with the added cost of none of those dialects having unique names. What does it mean to say "I've used C++ for six years" on a resume?

Similarly, learning a subset does you no good if you work with other people's code, and they do not use the subset you are expecting; you must be able to understand their subset, and even write it.

Finally, learning a subset doesn't guarantee that you won't avoid being bit by something that's not in the subset you've chosen. For example, you might choose (wisely, IMHO) to avoid using function overloading. You can't tell the compiler this, however, and thus you might unintentionally name two functions the same thing, and cause unimaginable problems thereby. Sure, you'll eventually figure it out, it'll just be another dumb bug, but why use a language that has any number of such gotchas lurking around every corner?


FACT: The C subset of C++ is the base language of C++.
FACT: Learning C syntax is required to learn any other subset of C++.

Thus, the C subset of C++ is the common subset that all C++ programmers must know.

I’ll now debate Sean’s arguments one at a time.


“C++’s biggest problem is its size.”

Bad argument. If C++ is truly the next iteration of C (as the term “C++” implies), then C++ is necessarily going to be bigger. Whining about it is a waste of both our time.


“The biggest flaw with the argument is that it forces compiler writers to implement a larger language; correctness will be harder to get right, and optimization will suffer. In the case of C++, however, this no longer matters; there are essentially no "just C" compilers anymore to compare to, so any lowered performance of C++ is no doubt also seen by C.”

CORRECTION: C performance isn’t going to be lowered.


“Another significant problem is that it requires an investment of effort to select an appropriate subset. Moreover, you will have difficulty finding books that teach this subset; and, indeed, if you acquire a C++ algorithms book, the odds that the subset chosen for that book matches that of yours is low.”

Yes, a more complex, more flexible, more powerful language (as I have proven in a previous post) is going to take more time to learn, and it’s going to require more effort. However, you neglect to mention that the availability of numerous subsets, each with their own specific strengths and weaknesses, will cut development time and execution time in the hands of an someone experienced enough to handle that language.

The argument about C++ algorithms is pointless. Any C algorithm with sufficient documentation (which any book will provide in abundance) can quite easily be adapted to C++ because of the necessity of the C++ programmer to understand the C subset, which you have questioned earlier.


“In other words, subsetting is the same as fragmenting the language into lots of separate dialects; it has all the same problems as that, with the added cost of none of those dialects having unique names. What does it mean to say "I've used C++ for six years" on a resume?”

CORRECTION: A language with multiple subsets requires the name of the subset to qualify your area of knowledge.

For example, I have been using templates for 1 year. I have been using C for 3 years. I have been using C++ for 2 years. And on and on…Sean, all you are doing is complaining that C++ isn’t one big homogenous bundle of code, which you disputed earlier with “C++’s biggest problem is its size.”

The dialects came about because people do not know the language, not because people know the language. Whenever you see someone using one language feature everywhere for everything (i.e., virtual functions) then you can rest assured he/she doesn’t understand the language.


“Similarly, learning a subset does you no good if you work with other people's code, and they do not use the subset you are expecting; you must be able to understand their subset, and even write it.”

FACT: Working with other people’s code is easier under C++.

I can prove that with another multi-page post, if you like.

I’ll start with the multiple subset argument. First, you can learn a subset well enough to use someone else’s code productively in an afternoon. Second, that’s a one-time thing for that particular subset (and there are only 3 subsets in the language, one of which is C). There is no reason to write anything but the most trivial declarations to use their code (see templates). The whole point of the separate subsets of C++ is so that you do NOT need to learn it completely in order to use someone else’s code, any more than you have to learn assembly to link in a DLL written in assembly.


“Finally, learning a subset doesn't guarantee that you won't avoid being bit by something that's not in the subset you've chosen. For example, you might choose (wisely, IMHO) to avoid using function overloading. You can't tell the compiler this, however, and thus you might unintentionally name two functions the same thing, and cause unimaginable problems thereby. Sure, you'll eventually figure it out, it'll just be another dumb bug, but why use a language that has any number of such gotchas lurking around every corner?”

CORRECTION: In C++, there are some (absolutely necessary, as I have proven in a previous post) changes to the C subset of C++.

FACT: Proper scoping eliminates both name collisions and unexpected function overloading in the C subset.

Scoping can be implemented with both classes and namespaces, which were a long-needed addition to C (which I have proven in a previous post).


quote: Article: Why C++ Sucks

Suppose you choose to just use the C subset of C++. One of the changes C++ makes to C rules is that you can no longer automatically cast from (void *) to other pointer types. The reason for this is clear; in C++, (void *) types are used sufficiently often that hidden bugs might occur. (There is a counter-argument to this even in a C++ context: C++ encourages you to typecast more often than necessary, possibly masking bugs because your typecast hides what would be a real warning.)

Is this a real problem for C? No, it's not, it just means you need to do some extra casting. The following code doesn't work:

x = malloc(sizeof(x[0]) * num_elements);

Instead you must code it as

x = (mytype *) malloc(sizeof(x[0]) * num_elements);

Of course, if you are familiar with the idiom found in the first example, you see the flaw in the second; the first version avoids a bug by not explicitly naming x's type; thus if that type changes, the code still (most likely) does the right thing. With the second code, if you change x's type, C++ will complain about the type error, so it won't introduce an error--just unnecessary typing to fix it.

If you're using C++ proper, you would just use the new operator to sidestep this... ignoring the fact that new requires the name of the type...


CORRECTION: void pointers are almost never used in C++. malloc() should only be used inside the new() operator. The only time you should use void pointers is when overloading the new() operator, which doesn’t require casting because the compiler does the type-checking for you.

CORRECTION: In any typed language (such as C) you allocate memory according to the type of object you wish to use. In C, this required an extra step – you had to use the sizeof() operator to get the size of the type in bytes to allocate raw memory, then an implicit cast had to occur (with the resulting temporary pointer) before the variable was actually assigned a value. In C++, the extra step is not required: you just give the type.

FACT: If the memory allocation isn’t type-safe, the language isn’t type-safe either.


quote: Article: Why C++ Sucks

I guess I'm just a whiner if many of my problems boil down to C++ requiring too much typing. Typing is such a tiny fraction of programming that it's not that big a deal. Yet it grates to see such extra 'accidental' (in the sense of Fred Brooks 'No Silver Bullet', i.e. in opposition to 'essential') work required for no good reason.


CORRECTION: Typing is one of the most important features of any language.

Obviously, you don’t understand why types exist. As you probably know, each data type stores its data in a slightly different format. If you tried to use the integer addition instruction on a CPU to add floating-point numbers, you would get invalid results. Pointer addition is different, too. Even C has data types; you aren’t working with raw bytes. C is simply poorly typed.

FACT: Strong typing prevents stupid mistakes and makes poor coding skills evident.

I already went over why strong typing is absolutely necessary to ANY language that works with data types. C has very bad typing – almost anything can be done implicitly, and that makes it that harder to find stupid mistakes.


quote: Article Why C++ Sucks

In C, I write a new function, and then add a prototype to the header file. Having to add that prototype is annoying 'accidental' effort; there is no reason this redundancy must be shoveled onto the programmer (it could easily be automatically generated, a la Java or Borland's Turbo Pascal). That something like a header file is needed for separate compilation is undeniable; but that I must maintain it by hand is largely silly.


Maintaining a header file automatically would be much sillier, I assure you. When you write a new function, if that function is then added to the header, then file any file including that header file can access that function. Obviously, having that automatic header-generation capability in an OOP language would be asinine.

(Of course, your entire argument here is pointless, because later on you spend a great deal of time discussing how to eliminate things from the header file.)


quote: Article: Why C++ Sucks

Still, it's not that much work. Cut and paste, put an 'extern' at the front of the line and a ';' at the end of the line, and you're done:

C file:
int myFooBar(Foo *foothing, Bar *barthing)
{
...
}

H file:
extern int myFooBar(Foo *foothing, Bar *barthing);


Thought question: How much work did this article require, Sean?


quote: Article: Why C++ Sucks

Consider the equivalent thing for a method in C++:
CPP file:

int Foo::myBar(Bar *barthing)
{
...
}

H file:
class Foo
{
...
int myBar(Bar *barthing);
...
};

Sure, in this example, the function declaration itself may be shorter, making C++ look better than C, but I'm comparing C++ to a similar, imaginary OO language that doesn't suck.


CORRECTION: You must give the scope of the function when you declare it, and when you define it. In the declaration, the scope is always implicit (whatever the current scope is), while in a definition you must state the scope. Without scope, languages would be reduced to little more than macro-ed (I forget the name for it, it’s the methodology before procedural). Class scope is necessary for classes to be a way to define new types.

Unfortunately, your imaginary OOP language doesn’t have to work. Just because you imagine something doesn’t mean it’s possible.


quote: Article: Why C++ Sucks

Worse yet, C++ makes this necessary in circumstances that it shouldn't be.

Suppose that class Foo in the example above inherits from Baz; and Baz includes as a member in its declaration virtual int myBar(Bar *barthing);. Now, when I want to go implement Foo, I choose to override the definition of myBar found in Baz.

C++ makes me spell out in the declaration of class Foo exactly which methods I'm going to override.
Even though the whole point of virtual functions is that the dispatch occurs at run-time--no compile-time support needed.

Pointless.

Oh, and did I mention that this sort of thing leads to extra unnecessary recompilation?


CORRECTION: Compile time support is needed to build the virtual function table (obviously) for each type.

FACT: Placing the virtual function declaration in the class declaration is the only way for the compiler to tell whether a class is abstract or not, which tells the compiler whether the class can be instantiated or not.

FACT: Besides, the memory usage of the class must be known before it can be instantiated.

Of course, Sean goes on to refute his own argument in his next paragraph…


quote: Article: Why C++ Sucks

I think I know why C++ does it this way. The thing is, if I subclass Foo to make, say, Biz, then if Biz doesn't define myBar for itself, it will need to store a pointer to Foo::myBar in its virtual function table. Thus, the compiler needs to know about everything that goes on under the hood with Foo to build Biz correctly. (Similarly if Biz defines it itself, but calls ::myBar.)

That means, of course, that everything 'under the hood' must be exposed in the class definition. The entire 'private' section must be exposed to subclasses (and also so that 'sizeof' works correctly).

You can try to work around the excess recompilation introduced by this by having multiple header files with differing levels of detail in them; the subclasses and the implementation of the class see the full description, whereas the rest of the world only sees the public definition, unless they need to sizeof... well, as you can imagine, I don't know anyone who actually tries to do that. (It would help if you could flag a class definition as 'incomplete' so inclusions of the wrong header file would fail to compile, instead of producing bugs.) I'm not actually sure that doing this is legal C++, anyway.

This all misses the point. Part of C++'s success is that it didn't require rewriting the linker (after all, initially it just was translated into C code). Separate compilation could be done without needing to see the innards of other classes if the virtual function tables were built up at link time. Even without rewriting the linker, the patching could be done at runtime, during startup. This does not need exposure. (The sizeof problem would still remain.)


CORRECTION: “::myBar” indicates a global function, and not a function in the current scope.

Obviously, everything under the hood must be exposed in the class definition, or you can’t allocate objects of that type. You could argue that C allows modules the same desired privacy (if you put the stuff in the .c file without declaring it in the .h file), but that would reduce the number of objects of that type that you could allocate to 1, which is stupid. Of course, you could then argue that there are workarounds for multiple module instances (like the article on gamedev), but I would argue the fact that those workarounds are VERY slow and have no language support.

(I have absolutely no idea why C programmers are paranoid about reading a section labeled “private:” when all they have to do is stop reading…what a pointless argument.)

(I also have absolutely no idea why C programmers think that their linked list code for instancing is going to be faster than the compiler’s C++ generated code. Go figure.)

His last paragraph doesn’t seem to make any sense (maybe it’s missing some words?), so I can’t refute it.


quote: Article: Why C++ Sucks

Yet another case is that of the C-style "static function". Suppose I decide I want to break Foo's implementation of myBar down into multiple smaller steps, using helper functions. Since the code is based around an object, I still want to make these be methods of the class so that I get a 'hidden this' and can refer to instance variables conveniently.

/* C code: */
static void myFooBarHelpFunction(Foo *foothing, int intermediate_value)
{
...
}

int myFooBar(Foo *foothing, Bar *barthing)
{
int value = computeSomething(foo,bar);
myFoobarHelpFunction(foo, value);
...
}

// C++ code:
void Foo::myBarHelpFunction(int intermediate_value)
{
...
}

int Foo::myBar(Bar *barthing)
{
int value = computeSomething(bar);
myBarHelpFunction(value);
...
}

The C++ example is incomplete. As you can see, it lacks the static keyword. This is because, to implement this in C++ like this, you have to add a declaration of this function to the class definition. That's right, to do a local, hidden modularization of this function, which cannot be seen or used by anybody else, including subclasses, you have to touch the class definition, which normally (as noted above) is exposed in the header file to anyone and everyone who interacts with the class. (At least this seems to be the case. Am I missing something?)

Oh, thanks.

And don't forget to delete Foo:: when you add it to the header file.

You can work around this by privately subclassing the type, thus allowing you to create a local class MySubClass type with local, non-exposed declarations. You still end up with a declaration and a definition, as opposed to C where you only need the definition if you put the functions in the right order. And you will have to downcast pointers that are passed in. But it avoids the header dependency.


Declare them private in the header file. Sorry, but to add an implicit this pointer, C++ must have the function declared in the class declaration. There can be only one class declaration, or else everybody and his uncle could add things to your classes.

FACT: your workaround is harder than simply adding a line to the class header.


quote: Article: Why C++ Sucks

Don't get me wrong. The above three examples aren't just pet peeves. I think of them as serious design flaws.


The only flaws are in your thinking, not the language.


quote: Article: Why C++ Sucks

Having to prefix every method definition with Foo:: is stupid. We should be able to wrap our definitions inside something like class Foo { ... } and not have to prefix with Foo:: inside it. Of course you could do exactly this, but you can only have one definition of a class, so you can't do this and also include a header file with the class declaration in it, so you need to include the full declaration locally. (Also, providing a mechanism like this would also make cutting and pasting into the header file easier.)


CORRECTION: Proper scoping is an indispensable organizational tool, and it is not “stupid.”

FACT: The class keyword followed by a code block indicates a class declaration.
FACT: There can only be one class declaration for each class.

(This is the only one of Sean’s arguments that has a valid point. However the solution is wrong.)


quote: Article: Why C++ Sucks

Constructors and deconstructors return void, even thought C++ denies it. Yes, removing the need for void from the parameter list and as a prefix on constructors/deconstructors can be seen as an opportune 'fix' to reduce typing, since C++ doesn't back-support K&R C the way ANSI/ISO C does. Sorry, I don't buy it; the amount of typing saved is irrelevent. (It's one thing to save lots of cut&paste editting motion; saving typing four characters while one is already in the middle of typing characters is saving me something like 5 seconds a week.) It introduces a pointless inconsistency.


CORRECTION: The function that is called when an object is de-allocated is called a destructor in C++.

FACT: void means “no type.”

CORRECTION: Constructors and destructors having no return value is not a pointless inconsistency. Constructors and destructors are not allowed to return values, so the removal of the redundant “void” is logical. The only difference between “void” and “no return type” is that “no return type” is implicitly “void.”


quote: Article: Why C++ Sucks

A relatively crucial element of object-oriented programming is the introduction of indirect function calls. Sure, imperative programming has them as well, but most OO languages make them ubiquitous; many people consider virtual the most important keyword distinguishing C++ and C--that is, if you never use virtual, you may be using classes, but you could just as easily be writing in C.


If most people consider virtual the most important keyword, then most people are wrong. It is important, but as I said before, taking one language feature and using it everywhere for everything is inexperience.

FACT: The virtual keyword is very useful, but it’s no cure-all.
FACT: The term “OOP language” explicitly states that the language must support polymorphism.
FACT: virtual is the C++ mechanism for polymorphism.


quote: Article: Why C++ Sucks

But more is not necessarily better. One can imagine a language in which a compiler makes these trade-offs automatically for you. You can imagine a language in which a single keyword changes the underlying implementation, with no syntactic or semantic variations visible.


(Now you are stating that the language should do things implicitly…)

FACT: Imagination != reality.


quote: Article: Why C++ Sucks

If we accept, though, that the constructor and destructor calls are there because that leads to better, more comprehensible semantics--that any object-oriented language is going to need something like constructors and destructors--we are only left with two syntaces to discuss: plain function calls and overloaded operators.


FACT: An Object-Oriented Programming language needs to support data encapsulation.

Obviously, that makes constructors and destructors necessary.


quote: Article: Why C++ Sucks

Many style guides strongly recommend disallowing overloaded operators. Some advocate allowing operator overloading for mathematical data structures, like bignums, complex numbers, vectors, matrices, and the like. (Care and handling of copy and assignment constructors is more complex, so I'll simply dispense with attempting to argue about them.)


FACT: Types require overloaded operators.

As I pointed out in a previous post, if your argument is true then no one should use the C language (or even assembly, for that matter), because they use operator overloading.


quote: Article: Why C++ Sucks

Clearly, one would like operator overloading to follow the principle of least suprise. Operators which normally are side-effect free should remain side-effect free. One would hope operators which are normally commutive remain commutative, and associative associative; but this is not always the case (e.g. matrix multiplication). [Of course, it is not a violation of these rules if operators test for errors and exit, or collect statistics, or do any number of other not-side-effect-free effects. The important issue is that they be side-effect-free in terms of the actual computations of the program, as opposed to the above meta-computations.]


FACT: Even in algebra, the rules are not the same for every type of number.
FACT: Properties like commutative and associative are only properties of certain types of numbers, not different types of operators.
FACT: Not all operators are valid for all data types, and the same operators will do different things on different data types.

That is why we have subsets of numbers, like whole numbers, real numbers, imaginary numbers (yes, that is an algebraic term), integers, etc. If you’ll read the wording in an algebra text, take note that your argument is based incorrectly on the idea that operators have properties and not types. Remember, the types have the properties; the operators are merely shorthand notation.

FACT: Types require overloaded operators.


quote: Article: Why C++ Sucks

The advantages of concise idiom are legion. I have an enormous number of C idioms I use without thought; idioms in the sense that if you are not familiar with them, the meaning of the code may not be immediately obvious. They are easy enough to figure out if you stop and think, but the power of the idiom comes from the lack of need to think; it is easier to understand a larger chunk of code all at once if the elements of it are idioms.


(That would make a good argument for the use of operator overloading…)


quote: Article: Why C++ Sucks

Idioms make operator overloading doubly tempting. One aspect is that it allows the use of familiar idioms in new contexts:

for(FooIter *i(foo); (bool) i; ++i) {
... *i ...
}

(Something like that--I'm not very familiar with C++ operator overloading.)


CORRECTION: Operator overloading is not tempting; it’s simply how math works.

CORRECTION: Declaring a pointer, and then casting it to bool will only give you a random result. Further, the iteration is the array-style pointer arithmetic, and will only give you an invalid pointer in your example.


quote: Article: Why C++ Sucks

Such idioms may be powerful, but they build on new, unrelated meanings of the underlying symbols.


CORRECTION: Data types have the properties that you are referring to as “unrelated meanings.”

FACT: When you define new types, you must define new operators for those types that obey the properties of that particular data type.


quote: Article: Why C++ Sucks

It is (I imagine) exactly this reasoning that introduced the ubiquitous operator overloading found in the C++ stream library.

Ask a C programmer what this code does:

a << b << c << d << e;

She will tell you "nothing". None of the operators have side-effects. In C.

Do they have side-effects in C++?

It depends on what functions they call.


FACT: Not all operators are valid for all data types, and the same operators will do different things on different data types.
FACT: When you define new types, you must define new operators for those types that obey the properties of that particular data type.


quote: Article: Why C++ Sucks

C++ programmers swiftly adjust to the use of <<. It seems natural and perfectly reasonable. But don't be fooled by it. Most style guides recommend against coining new forms of operator overloading. That supposed power of idiom is simply too fraught with peril.

Keep this in mind: the argument by analogy to C idioms is broken, because the C idiom is constructed of unambiguous items right there on the page. Comprehending an unfamiliar C idiom just requires parsing the code--an action the reader was already doing. There's no 'secrecy' at all--it just takes a little longer.


Then most style guides don’t understand the language.

CORRECTION: The argument by analogy to C idioms is not broken, because properties like commutative and associative are only properties of certain types of numbers, not different types of operators.

Thus your point is only that C++ is more complex than C, and making that the basis of your argument is indicative of laziness and ignorance, not intelligence.


quote: Article: Why C++ Sucks

As noted previously, there are two semantics for a plain C function call. Determining which semantic is in operation is as easy as searching back through the file for the name, and then grepping header files for the name.

Not so for C++. C++ has both run-time indirection and compile-time indirection. In fact, it has a number of flavors of the latter.


CORRECTION: The context unambiguously determines which call is being performed.
CORRECTION: Sean, your acceptance of function call semantics in C indicates that you agree with context unambiguously determining the call, and conflicts with your argument against C++ function call semantics.

Thus your point (again) is only that C++ is more complex than C, and making that the basis of your argument is indicative of laziness and ignorance, not intelligence.


quote: Article: Why C++ Sucks

Templates offer the best example of my core complaint. At their heart (ignoring the committee-driven creeping featurism), templates are there to allow you to do something like define a generic hash table class, but specialize it to be implemented "directly" for some specific class, instead of having to pay indirect dispatches at runtime.

However, I've stated previously, I find this approach flawed, because it introduces an entirely new syntax and semantics. I would much prefer if you just defined the hash table as taking some abstract base class, defined your elements to be hashed as deriving from that base class, and then used a magic 'specialize' keyword to 'instantiate the template'.


FACT: Templates are type-safe macros.
FACT: You cannot instantiate a template class, until it has been “specialized.”

Rather than introduce yet another complexity to classes (which earlier you were adamantly against…), templates are a macro language that allow regular classes and functions to be built for any type. The generated classes are normal C++ classes. Thus the behavior is much more apparent because templates obviously require compiler support. The syntax must be different. You also ignore the possibility of overloaded operators defined by the types and the necessity of the template-ed class/function to know exactly which types it is using.

Compounding the all the previous errors in your approach is the simple fact that you can’t make an intrinsic type like int a derived class of the abstract base class, which means that you couldn’t use templated classes or functions with any of the intrinsic types.

FACT: Polymorphism is quite different from generic programming.


quote: Article: Why C++ Sucks

Moreover, those lists are far too short, as they don't call attention to the bewildering variety of problems introduced by function name overloading.


CORRECTION: The bewildering array of problems comes from ignorance of the language, which would be found in using function name overloading everywhere for everything. Function name overloading is a useful paradigm in an amount equal to the number of times it is used, divided by the distinction between the overloads.


quote: Article: Why C++ Sucks

Far worse is the use of multiple names with the same number of parameters. You have to figure out the (compile-time) type of every parameter, exactly, before you can make the right call about which function is called. Go look up through the code to determine the type of any variable used; check in the header file to see what type is returned by this function; try to remember whether * means a dot product or a cross-product of two vectors.


FACT: Strong typing prevents stupid mistakes and makes poor coding skills evident.

If you don’t see the need for typing, you’re missing a fundamental understanding of the C++ language.


quote: Article: Why C++ Sucks

It's easy, in fact, to see how the specified rules underscore human intuition about best match. At least, each rule in isolation does so. I have my doubts about the combination.

Still, I find it a bit uncomfortable. I worry about the compiler's intuition not matching mine. I'd be more comfortable if the compiler only picked out a particular function for me if it was unambiguous; say, because every parameter was a better match for the "winner".


If you need to manually call a specific overload (which indicates a bad implementation of function overloading), use the cast operators.


quote: Article: Why C++ Sucks

Problem is, that would preclude having, say, all the matching functions sharing, say, a common first element that is the same type. Such functions would always match equally. It's easy to see why C++ uses the rule it does.

The above considerations were based on a programmer who was trying to intentionally leverage function name overloading. What about one who isn't?

Suppose in C I define a function "foobar" in one module, and a define another one with the same name in another module, but with different argument types. In draconian fashion, C will produce a linker error, and force me to rename one or the other.

Is this so bad?


(Now he refutes his own argument, saying that C++’s implementation is only possible way…)

All that is left is the same old unintentional function overloading argument, which we’ve already gone over:

CORRECTION: In C++, there are some (absolutely necessary, as I have proven in a previous post) changes to the C subset of C++.

FACT: Proper scoping eliminates both name collisions and unexpected function overloading in the C subset.

Scoping can be implemented with both classes and namespaces, which were a long-needed addition to C (which I have proven in a previous post).


quote: Article: Why C++ Sucks

Consider the alternative found in C++: these two functions may be totally unrelated, but through a commonness of the English language (e.g. the same word having two different meanings; consider simply the word 'heap' in the sense of a semi-ordered data structure versus a pool of memory) share an identical name. In C++, name-mangling means those two functions can happily live within the same namespace, and within the same project.

Is this a problem?

What happens if I'm calling foobar() somewhere in my code, and then someone introduces a new #include in my code which now brings the other foobar() into scope? What if I was relying on some automatic type conversions in my call to foobar(), and the new foobar() now matches "better"?

And think about this: is it good that the different functions could come via different semantic mechanisms? So if I grep for "foobar", thinking it is coming from one sort of place, I may miss that a "better match" is being introduced through a different compile-time indirection?

And think about this: is it good that I can add "default arguments" to functions declarations, thus messing up my attempt to cull out possible function calls based on the argument counts not matching?


(An obviously improper usage of scope…)


Well, that’s it. I found one good point in his article, but it has absolutely no impact on the performance or the readability of the C++ language; that point was merely about saving some typing.

Score
Sean Barrett: 1
C++: 35

Not bad, not bad at all.



- null_pointer
Sabre Multimedia


Edited by - null_pointer on July 4, 2000 4:09:48 PM
That has to be the longest post I''ve ever seen null_pointer

- Muzzafarath

Mad House Software
The Field Marshals
I'm reminded of the day my daughter came in, looked over my shoulder at some Perl 4 code, and said, "What is that, swearing?" - Larry Wall
God damn, null_pointer''s posts are long.

I''m a VB user myself, though I do have experience with C++ (I use it to speed up my code). Anyway, VB uses classes as well, so I thought I''d throw in my own two cents on the matter. I don''t recognize any particular speed issues with classes that you couldn''t just as easily have with regular code. I think it''s a bit more challenging writing classes, but their reusability more than makes up for this. In this respect, classes are almost a necessity if you plan to work on similar projects in the future.

For example, let''s say you''re making a 3D game. You build an object library that contains classes for several different types of objects. These classes have information like size, location, velocity, health, etc. Your 3D engine will load these classes and use them for game objects.

Later, let''s say you want to rewrite your 3D engine using faster algorithms. You can still reuse the old classes without having to reconstruct them, thus saving you a lot of time and hassle. In addition, you can add new features to your classes without having to worry about breaking old ones. (This is what I plan to do with my own project.) This makes classes very expandable.

GDNet+. It's only $5 a month. You know you want it.

quote:
quote:
--------------------------------------------------------------------------------
Article: Why C++ Sucks

I guess I'm just a whiner if many of my problems boil down to C++ requiring too much typing. Typing is such a tiny fraction of programming that it's not that big a deal. Yet it grates to see such extra 'accidental' (in the sense of Fred Brooks 'No Silver Bullet', i.e. in opposition to 'essential') work required for no good reason.



--------------------------------------------------------------------------------


CORRECTION: Typing is one of the most important features of any language.


Hehe, that's the way I first read it too, but I think he's actually talking about "typing" on the keyboard rather than data types.

BTW, there's a much more level-headed critique of C++ at http://www.elj.com/cppcv3/ for those of you who are interested.

Edited by - EvilTwin on July 4, 2000 5:00:25 PM

This topic is closed to new replies.

Advertisement