Not logged in
Log in now
Create an account
Subscribe to LWN
LWN.net Weekly Edition for May 16, 2013
A look at the PyPy 2.0 release
PostgreSQL 9.3 beta: Federated databases and more
LWN.net Weekly Edition for May 9, 2013
(Nearly) full tickless operation in 3.10
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)
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.
Posted Mar 28, 2011 21:11 UTC (Mon) by Trelane (subscriber, #56877)
Posted Mar 31, 2011 15:37 UTC (Thu) by mister_m (guest, #72633)
Posted Mar 28, 2011 21:15 UTC (Mon) by daglwn (subscriber, #65432)
Fully generic templates
Just to name a few.
> 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.
Posted Mar 28, 2011 21:55 UTC (Mon) by cmccabe (guest, #60281)
> 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.
Posted Mar 29, 2011 1:05 UTC (Tue) by mtall12 (guest, #73924)
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:
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).
Posted Mar 29, 2011 1:11 UTC (Tue) by HelloWorld (guest, #56129)
> By the way, most experts recommend that you never use C++'s multiple inheritance support
I just recommend reading this:
> 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.
Posted Apr 3, 2011 22:34 UTC (Sun) by cmccabe (guest, #60281)
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.
Posted Apr 4, 2011 19:10 UTC (Mon) by daglwn (subscriber, #65432)
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.
Posted Apr 5, 2011 10:47 UTC (Tue) by HelloWorld (guest, #56129)
Posted Apr 5, 2011 20:38 UTC (Tue) by cmccabe (guest, #60281)
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.
This is related to the "midlayer mistake" that Neil Brown talked about earlier: http://lwn.net/Articles/336262/
Posted Apr 5, 2011 22:43 UTC (Tue) by HelloWorld (guest, #56129)
Posted Apr 5, 2011 23:24 UTC (Tue) by cmccabe (guest, #60281)
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. :)
Posted Apr 7, 2011 16:42 UTC (Thu) by daglwn (subscriber, #65432)
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.
Posted Apr 8, 2011 17:57 UTC (Fri) by cmccabe (guest, #60281)
> 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
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:
I would suggest yet another: private inheritance.
Posted Apr 8, 2011 18:35 UTC (Fri) by daglwn (subscriber, #65432)
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! :)
Posted Apr 11, 2011 0:30 UTC (Mon) by cmccabe (guest, #60281)
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.
Posted Mar 29, 2011 10:54 UTC (Tue) by jwakely (subscriber, #60262)
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"
Posted Apr 2, 2011 0:10 UTC (Sat) by cmccabe (guest, #60281)
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.
Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds