Posted Mar 28, 2011 18:33 UTC (Mon) by daglwn (subscriber, #65432)
In reply to: GCC 4.6.0 released by cmccabe
Parent article: GCC 4.6.0 released
You're demonstrating exactly what mcm talked about in the comment above. The C++FQA is a load of garbage, written by someone who doesn't actually understand C++.
C++ has plenty of warts. No C++ user or designer will tell you otherwise. But the C++ inheritance model is not broken. Java did take out all the good parts of C++. That's why it feels like an incomplete language.
Posted Mar 28, 2011 19:52 UTC (Mon) by cmccabe (guest, #60281)
[Link]
If you think Yossi Kreinin "doesn't understand C++," then can you point out an actual factual error he makes?
What "good parts" of C++ did Java take out?
I seem to be no more knowledgeable after reading your post than before.
GCC 4.6.0 released
Posted Mar 28, 2011 21:10 UTC (Mon) by mpr22 (subscriber, #60784)
[Link]
C++'s operator overloading lets me write arithmetic on ordered pairs of numbers in a civilized fashion. The fact that other idiots do strange, idiotic, crack-addled things with it is not, and will never be, sufficient to persuade me that it is not a good and valuable feature which improves the language of which it is a part.
Also, what is this C++ FAQ that Yossi keeps ranting about? I've never read it, it has never occurred to me to look for a C++ FAQ, and I can't imagine why one would look for a C++ FAQ.
GCC 4.6.0 released
Posted Mar 28, 2011 21:11 UTC (Mon) by Trelane (subscriber, #56877)
[Link]
> If you think Yossi Kreinin "doesn't understand C++," then can you point
> out an actual factual error he makes?
Ok, here's one chosen at random:
> Templates are mostly applicable to containers or smart pointers, which
> can contain or point to almost anything. When the constraints on the
> input are less trivial, most of the time you either don't really need
> polymorphism, or you are better off with dynamic polymorphism
This is completely wrong. In fact one often wants to favor static polymorphism over dynamic polymorphism. Of course, one has to
understand the tools to make the proper decision.
GCC 4.6.0 released
Posted Mar 28, 2011 21:55 UTC (Mon) by cmccabe (guest, #60281)
[Link]
> > What "good parts" of C++ did Java take out?
> Multiple inheritance
Java classes can implement multiple Interfaces. This effectively accomplishes the same thing as multiple inheritance without the big problems of MI in C++.
By the way, most experts recommend that you never use C++'s multiple inheritance support (unless you are inheriting from abstract base classes).
> Fully generic templates
Java has generics. They're not implemented quite the same as C++ templates, but they accomplish the same thing.
> Operator overloading
Frankly, I think operator overloading is confusing and ugly. It's a Perl-style "let's save 5 seconds of typing now, but spend 50 minutes scratching our heads a few months later over what this code REALLY does."
> > Templates are mostly applicable to containers or smart pointers, which
> > can contain or point to almost anything. When the constraints on the
> > input are less trivial, most of the time you either don't really need
> > polymorphism, or you are better off with dynamic polymorphism
> This is completely wrong. In fact one often wants to favor static
> polymorphism over dynamic polymorphism. Of course, one has to
> understand the tools to make the proper decision.
I am looking at some C++ code right now. I can tell you that 90% of the uses of templates are STL containers and smart pointers! I don't know what your definition of "mostly" is, but 90% meets my definition.
Let's take the next sentence. "Most of the time you are better off with dynamic polymorphism." I think if you look at most C++ programs, you would see more use of classes and virtual functions (dynamic polymorphism) than templates (static polymorphism). So this sentence seems to be true as well.
I think your brain translated what Yossi said into "templates suck, don't use them." But that's really not what he said at all. He just said other methods are, and should be, used more often than templates. Templates have their place. I've said this before and I'll say it again-- templates are really the only improvement C++ made over C.
GCC 4.6.0 released
Posted Mar 29, 2011 1:05 UTC (Tue) by mtall12 (guest, #73924)
[Link]
Frankly, I think operator overloading is confusing and ugly. It's a Perl-style "let's save 5 seconds of typing now, but spend 50 minutes scratching our heads a few months later over what this code REALLY does."
Sorry, that's a non-argument. Using the same logic I could say that using the "traditional" function call of foo(a,b) is confusing and ugly, because I'll need to spend 50 minutes deciphering what foo() does.
Operator overloading is a very useful shorthand for function calls that can make the code far more readable and hence easier to maintain (translation: less bugs). This is especially true when writing scientific applications (though certainly not limited to them). With a decent matrix library (eg. Armadillo or ITPP), C++ allows things like:
matrix A, B, C, D;
A = (0.1*B + C) * D;
while in Java you have to resort to:
A = B;
A.scalar_multiply(0.1);
A.add(C);
A.matrix_multiply(D);
or
A = matrix_multiply(add(scalar_multiply(0.1, B), C), D);
Now imagine the above style for a far more complicated expression.
Let's also not forget that through C++ templates one can implement expression optimization, where operations like (0.1*B + C) can be turned into one loop, thereby providing execution speeds generally not doable in Java (ie. without specialized functions).
GCC 4.6.0 released
Posted Mar 29, 2011 1:11 UTC (Tue) by HelloWorld (guest, #56129)
[Link]
> Java classes can implement multiple Interfaces. This effectively accomplishes the same thing as multiple inheritance without the big problems of MI in C++.
What "big problems" are you talking about? I suspect these "problems" are merely something that is being made up by Java fanboys in order to defend their emasculated language, because I've never seen an actual problem that is fixed with Java's interface approach.
> Java has generics. They're not implemented quite the same as C++ templates, but they accomplish the same thing.
Except that they don't, as the introduction of generics broke the casting operator. You can cast something to ArrayList<Foo>, and even if that succeeds, what is returned from its get method may not be a Foo. This kind of fuckup is typical for Java.
> Frankly, I think operator overloading is confusing and ugly. It's a Perl-style "let's save 5 seconds of typing now, but spend 50 minutes scratching our heads a few months later over what this code REALLY does."
In all languages with operator overloading I know of, applying an overloaded operator is nothing else than a simple function or method call. If this actually makes you scratch your head 50 minutes, you just shouldn't be programming at all.
GCC 4.6.0 released
Posted Apr 3, 2011 22:34 UTC (Sun) by cmccabe (guest, #60281)
[Link]
> Except that they don't, as the introduction of generics broke the casting
> operator. You can cast something to ArrayList<Foo>, and even if that
> succeeds, what is returned from its get method may not be a Foo. This kind
> of fuckup is typical for Java.
Java's generics do have a lot of weird corner cases. Things that, as a C++ coder, I would expect to succeed, do not. One example is trying to make a copy of an arbitrary type T using a copy constructor.
Java's generics are flawed. Java itself is flawed. But then, so are many other languages.
> What "big problems" are you talking about? I suspect these "problems" are
> merely something that is being made up by Java fanboys in order to defend
> their emasculated language, because I've never seen an actual problem that
> is fixed with Java's interface approach.
Honestly, I am just going to stop commenting or offering advice on programming languages at all. Even the most simple and basic advice always seems to touch off a flamewar.
Recently I advised someone to stop throwing raw "int"s as exceptions. Result: 15 minute discussion about maintainability, code clarity, stuff experts said, the difficulty of adding all the catch blocks you need to client code, etc. At the end of it: "well, I'm going to keep doing it anyway." Luckily I will never have to maintain, or even see, that code because it's closed source and I don't work at that organization.
GCC 4.6.0 released
Posted Apr 4, 2011 19:10 UTC (Mon) by daglwn (subscriber, #65432)
[Link]
That's a problem for a very specific case and even then it's not always a problem. It's more something to be aware of. It does not invalidate the utility of multiple inheritance. The mixin pattern is a primary example of how useful MI can be. It use it all the time.
> Honestly, I am just going to stop commenting or offering advice on
> programming languages at all.
Advice is fine as long as it is relevant to the task at hand. General
advice should not be used as a weapon or stocks.
GCC 4.6.0 released
Posted Apr 5, 2011 10:47 UTC (Tue) by HelloWorld (guest, #56129)
[Link]
> http://en.wikipedia.org/wiki/Diamond_problem
C++ solved this problem a long time ago. You can either use virtual inheritance or say explicitly if you want to use B's or C's method (using the class identifiers from the wikipedia article). And your assertion that interfaces effectively accomplish the same thing as multiple inheritance is just wrong, you can't do mixins with Java interfaces. So, the way I see it, Java didn't actually solve any problem (like C++ did with virtual inheritance), but it just disallowed multiple inheritance even in cases where the diamond "problem" doesn't even arise.
GCC 4.6.0 released
Posted Apr 5, 2011 20:38 UTC (Tue) by cmccabe (guest, #60281)
[Link]
As the Gang of Four book says, you should "favor 'object composition' over 'class inheritance'." So rather than creating mixins, you should usually create objects that are comprised of several smaller objects which operate independently.
There are a lot of reasons for this. The first and most obvious reason is that it makes unit testing a lot easier. If I have a class which inherits from 3 other classes, I can't test that class without also testing the three base classes. I may not even be able to construct an instance of that class without providing a lot of irrelevant inputs-- file descriptors to open, memory to allocate, and so forth. On the other hand, it's easy to create an instance of a component and test just that component.
You can get around some of these problems by constructing "mock ups" of some of your class components. You see this a lot in Java code. But it's difficult, and even when executed successfully, it bloats the code.
Creating elaborate and deep inheritance hierarchies increases compile time and the coupling between components. The former chews up machine cycles when compiling (at least if you're using C++). The latter chews up human time when trying to maintain the code, no matter what language you're using.
Posted Apr 5, 2011 22:43 UTC (Tue) by HelloWorld (guest, #56129)
[Link]
Firstly, this is a general statement about inheritance and has little to do specifically with multiple inheritance. Secondly, if we assume the GoF to be right, then Java did it just as wrongly as C++, as it still allows inheritance.
GCC 4.6.0 released
Posted Apr 5, 2011 23:24 UTC (Tue) by cmccabe (guest, #60281)
[Link]
My main point is that using inheritance for code reuse is bad.
Using inheritance to implement runtime polymorphism is still ok.
So Java interface classes and C++ abstract base classes are ok in my book. Mixins are bad, in my opinion.
I do like the way Golang handles runtime polymorphism more than the way C++ or Java do it, but you can only do it that way if you're using Go. :)
GCC 4.6.0 released
Posted Apr 7, 2011 16:42 UTC (Thu) by daglwn (subscriber, #65432)
[Link]
Mixins do not have to implement anything. Again, you're artificially restricting what's possible. It's sometimes convenient to use mixins to convey relationships among types. I have a mother and a father. My mother has a mother and a father. So does my father. That means my maternal-side cousin and I have grandparents in common and my paternal-side cousin and I also have grandparents in common, but a different set.
In more concrete terms, an add expression is a binary operator. So is a subtract expression. Both are also associative, but only one is commutative. That's a useful thing to express in class hierarchies and using mixins is a great way to do it.
GCC 4.6.0 released
Posted Apr 8, 2011 17:57 UTC (Fri) by cmccabe (guest, #60281)
[Link]
from Wikipedia:
> In object-oriented programming languages, a mixin is a class that provides
> a certain functionality to be inherited by a subclass, while not meant for
> instantiation (the generation of objects of that class). Inheriting from a
> mixin is not a form of specialization but is rather a means of collecting
> functionality.
So it's not about relationships between types. It is about code reuse.
Bruce Eckel suggests a way of implementing mixins in C++ using templates:
Posted Apr 8, 2011 18:35 UTC (Fri) by daglwn (subscriber, #65432)
[Link]
I've used CRTP as well and find it useful. I also find mixins as relationship useful. I my mind, inheritance is about relationships. For functionality, I would agree with GoF and you that composition is generally a better path. I very rarely use private inheritance. I honestly can't think of a situation where I've found it absolutely necessary.
But in any case, I think the discussion leads us to a place where general MI is useful, even with the pitfalls. Pointers in C have a similar usefulness/pitfall tradeoff. I like the fact the C++ is flexible like this. I wish it were more flexible than it is! :)
GCC 4.6.0 released
Posted Apr 11, 2011 0:30 UTC (Mon) by cmccabe (guest, #60281)
[Link]
Well, as I said before, I think being able to inherit from multiple (fully) abstract base classes is useful. I have never found a good use for inheriting from multiple non-abstract base classes. I guess we'll have to agree to disagree.
Anyway, language design is an endless process. It really comes down to who what languages are most successful in the marketplace, and in the open source world. My philosophy is to use the right tool for the job.
GCC 4.6.0 released
Posted Mar 29, 2011 10:54 UTC (Tue) by jwakely (subscriber, #60262)
[Link]
> By the way, most experts recommend that you never use C++'s multiple inheritance support (unless you are inheriting from abstract base classes).
What about non-abstract empty bases? Should they never be used with MI?
What about std::ctype, std::codecvt, std::time_get and other facets?
What about std::iostream?
I guess I'll "never" be an "expert"
GCC 4.6.0 released
Posted Apr 2, 2011 0:10 UTC (Sat) by cmccabe (guest, #60281)
[Link]
> What about non-abstract empty bases? Should they never be used with MI?
That's what I just said.
> What about std::iostream?
from a footnote in "Thinking in C++" by Eckel:
> Jerry Schwarz, the author of iostreams, has remarked to both of us on
> separate occasions that if he had it to do over again, he would probably
> remove MI from the design of iostreams and use multiple stream buffers and
> conversion operators instead
> I guess I'll "never" be an "expert"
Try reading Effective C++, More Effective C++, and anything by Alexandrescu. Or you can go renegade and read the C++ FQA. No matter whether you agree with Yossi, you will learn a lot.
GCC 4.6.0 released
Posted Mar 29, 2011 15:47 UTC (Tue) by k8to (subscriber, #15413)
[Link]
If you say Yosef doesn't understand C++, then you've demonstrated that you're willing to claims someone is wrong just because you don't like their position, and without actually understanding what they have to say.
There is a very *deep* grasp of the language there, by someone who has had to implement aspects of it in production systems for many many years. You may not agree with the assessment, but to claim a lack of understanding only makes you look a fool.
GCC 4.6.0 released
Posted Mar 29, 2011 16:20 UTC (Tue) by mpr22 (subscriber, #60784)
[Link]
My experience of C++ directly contradicts the position that the FQA is written to advance (which can be fairly summarized as "C++ delenda est" - and if you disagree, please explain why).