C++ is syntactically heavy in the sense that you need far more pages to describe all of C++ syntax than you need to describe Java syntax. I think I should sometimes check out some formal C++ grammar, I assume it is fairly nasty reading / parsing...
There is a C++ grammar in one of the appendices of "The C++ Programming Language" by Stroustrup. I will not deny that the grammar is disgusting, and Stroustrup even admits that it's a 'simplified' version of the grammar that a compiler would have to use.
Most of the gotchas also stem from this syntactic complexity and subtleties in semantics. A lot of the competence of a C++ programming comes from knowing the difference between stuff like footype foo; and footype foo();
Yes, things like that are very annoying about C++. Once again I won't deny it. However there are far worse subtleties than footype foo() ; Try working out what the following does:
Code:
ifstream file("myfile.txt");
vector<char> v(istream_iterator<char>(file),istream_iterator<char>());
It's
meant to be a rather 'cool' way of reading a file into a vector.
In fact, the second line declares a function which returns a vector<char>, takes an istream_iterator<char> named 'file' as its first parameter, and an unnamed parameter which is a pointer to a no-argument function that returns an istream_iterator<char> as its second parameter.
The second line has to be rewritten with some type of syntax that will make it clear to the compiler that it's a variable declaration, not a function declaration. The simplest is probably,
Code:
vector<char> v((istream_iterator<char>(file)),istream_iterator<char>());
I will openly agree that this is likely to be rather confusing to someone learning the language.
I have found this to be a matter of taste...
Isn't this entire discussion a 'matter of taste'?
I suppose you were doing C++ before Java?
No, I was doing mainly C before Java. I had programmed in C++, but I did not know it well or like it at the time I learnt Java.
When you change to a language you haven't done anything in before, of course it feels difficult to do things in general...
Yes it does, however this is not the reason I don't like Java. I programmed in Java for more than 2 years, and it was my language of choice at one stage. It was only after I learnt C++ properly that I realized I could do things easily that I had been wishing I could do in Java.
100% Java programmers might moan hard about, for example, lack of garbage collection and its implications when you do something as simple as, say, a string class with operator overloading... and use those overloading in a chained fashion, such as string x = a + b + c;
Huh? Are you talking about using the C++ string class, or writing your own? If you're using the C++ string class, then everything is handled for you. No need to worry about memory management of the string at all. string x = a + b + c; will work fine.
If you're writing your own string class, well, why? Both Java and C++ have string classes. Even if you did write your own string class, you could trivially implement it in terms of vector, and not have to worry about any memory management issues.
To address your more general point, I can see how lack of garbage collection in C++ would be very difficult for someone coming from a GC-oriented language to deal with. That's a normal part of learning a new language, and yes, C++ is harder to learn than most.
Once you've learnt the techniques that C++ makes available to manage resources, I think they are as good as Java's - each have their own advantages and disadvantages. Java's garbage collection is good for managing heap-allocated memory, but it fails to address the more general issue of arbitrary resources - network sockets, open files, and so forth. Finalizers are not an acceptable solution, since Java lacks any guarantee about when they will run (or even run at all).
C++'s solution of using destructors extensively to precisely specify the scope of a resource is one I personally prefer, although I see advantages and disadvantages of each approach.
Disagreed. C++ needs to introduce a whole new concept, the templates... which are the worst implemented C++ feature anyway (I don't claim that they don't -work- if you know how to use them, though).
I don't see the problem with introducing a 'whole new concept' for something as important as containers. Java specifically tries not to add any new concepts, just implements containers in normal classes, and ends up with very bad containers.
Following this logic we could say, "C++ is a worse language than Java because it has more features".
About C++ templates at kuro5hin
I've seen this article before. The author is saying that templates are a good idea, he just thinks they are better implemented in some other languages. I don't think that C++ templates are brilliantly implemented, but I don't think they are awful either.
I certainly think C++ having templates vs Java not having them is a huge plus for C++.
Also, writing your own templates might be a little difficult, but using templates provided by others or by the language really isn't that difficult. It's easy once you learn how templates work.
Java manages it within the core framework of the language... you get a collection the way you would get any other object.
C++ manages it 'within the core framework' of the language too, it's 'core framework' is just different to Java's.
I have also seen the other side use the inverse of this argument -- in C++ you need to resort to void pointers or a common base class to store heterogenous collections... depends on what you prefer as standard behaviour.
It's quite likely that in the case of heterogenous collections you end up using runtime type checking anyway, which is more convenient in Java... the alternative would be to add an extra identifier attribute, and I consider this ugly design.
Firstly, if you need heterogenous collections, your program probably has a design flaw. The 'object oriented' approach to this is to have a polymorphic function in a common base class (or interface in Java), and then call the polymorphic function on each item in the collection. This has a similiar implementation in both Java and C++.
If you are needing to use RTTI, then you are probably doing something wrong. However, in C++ you could do it, as you say, either by declaring a common base class, or, the worst solution, using void pointers and using dynamic_cast.
The thing is, using void pointers and dynamic_cast is the same way Java does it. That is my entire point: The
worst way to do it in C++ is the
only way you can do it in Java. That it might be slightly 'more convenient' in Java hardly makes a difference. (And for that matter, it isn't really much more convenient than Java at all).
This is one of the core reasons I dislike Java collections: the Java ArrayList is more or less equivalent to having to use a vector<void*> everywhere in C++.
Java can indeed get hideous with its casting. I've had a modular IRC bot as a hobby project this summer, and I have lines like that that take up about two screen widths Certainly you can and should break them up by using local variables, but modern IDEs like Eclipse make it very easy to create casting monsters, because they automatically add the casts for you... and of course, the code looks much more leet that way
Yes it can, and not only is the code verbose, it has a hideous number of possible paths through the code with all the exceptions that can be thrown.
Breaking them up with local variables simply means that you are taking 5 lines to do something which should be doable in one line.
When it comes to the [] operator, it is handy syntactic sugar, but in most cases, you're better off using a pair of getter and setter methods.
Oh the point of my example wasn't the [] operator. It is syntactic sugar, with only mild advantages. Vector also supports the at() function which you could use instead.
However there are a few advantages of having operator overloading, the biggest of which is that it provides a language-mandated way of doing things. The way to make an indexable object in C++ is to overload the [] operator. In Java it's to use the get() function, but the encouragement to follow that standard isn't nearly as strong. Further, Java's own builtin arrays violate that standard.
Suppose you have a lot of code that uses an array. Suppose that you need to add a feature which requires the array to be dynamic in size, so you want to switch it to being an ArrayList. How many changes would you have to make in Java? If you wanted to switch it to being a vector in C++, very few changes would be needed. This is even more important for C++, since it supports templates, and one might want to write a function template which could accept either an array or a vector, however it is less important for Java, since Java does not support templates.
It could be my incompetence with the language, but when an [] implementation gets complex enough, especially when paired with dynamic memory allocation and tricks like copy-on-write, stuff starts to seem too hairy to be motivated.
Hmm....you were just saying a moment ago that the [] operator is just syntactic sugar, and now you're saying there is something inherently more complex about operator []? Huh?
Tricks like copy-on-write? I'm afraid I don't understand......you don't have to know anything about copy-on-write unless you're trying to implement an optimized container yourself. If you fiddle with the internals of the standard libraries supplied by your compiler vendor, then sure it's going to be hairy. But I don't understand why you'd do this. There is also no reason at all why this has anything to do with operator [] vs getter and setter methods.
The problem with [] is that you don't know whether you're reading or writing through it.
The semantics are exactly the same as for a normal variable or a builtin language array. I don't understand how this could possibly be a problem. Can you provide an example where it is unclear whether you are reading or writing? Are you saying that some people who implement operator [] may return by value when they mean to return by reference?
Of course if you're doing operating system programming you need to be bothered with reference counting, smart references and whatnot, but things like this are why I don't use C++ unless I can justify its use.
I'm afraid I don't understand your complaint here either.
Reference counting is an optimization technique that will reduce the number of copies of an object in certain situations. There is nothing inherent in C++ that has anything to do with reference counting. So what does this have to do with anything? You might as well blame C++ for the Knuth-Morris-Pratt string searching algorithm being complicated because you had to implement KMP in it once.
Some standard library container implementations use reference counting on the string class, but that's completely irrelevant because it is an implementation detail you will never have to deal with. Complaining about that would be like complaining that Java's mark-and-sweep garbage collection algorithm is complicated.
As for 'smart references', there are no such things in C++. You might be talking about smart pointers, in which case, similiar comments to reference counting apply.
That's a nice philosophical question, but I am afraid I am not getting what your complaint with the actual behaviour is, in practical terms. Your program still dies immediately, as if you were doing an assertion, and barfs a stack trace, does it not?
It depends upon whether you catch the exception or not. Since it's often useful to catch(Exception) at other points in the program, the error will often cause unexpected behavior rather than a stack trace.
That's a relatively minor thing, but more generally, I do think the Java misuses exceptions rather badly. Exceptions are useful for reporting errors *outside* of the program. Not inside of it.
I've heard about this problem earlier in other discussions, but haven't quite looked deeper into it... off the top of my head, I can't figure out what makes C++ exception handling so different from that of Java's that Java makes things more difficult to do... is the argument that in C++, you simply don't do things with exceptions, but Java forces you to?
Firstly, in C++, you do do things with exceptions. Many standard library functions throw exceptions. new will throw an exception if it fails. dynamic_cast throws an exception if it fails if it's trying to cast to a reference.
The problem is that in Java you have to use try...catch statements:
Code:
op1();
try {
op2();
} catch(Exception e) {
rollbackOp1();
throw e;
}
In C++, you can use a helper class:
Code:
class execute_rollback
{
bool cancelled_;
public:
execute_rollback() : cancelled_(true) {}
~execute_rollback() { if(!cancelled_) rollbackOp1(); }
void cancel() { cancelled_ = true; }
};
This class would be written once and made slightly more generic and powerful, and then would be used throughout an entire project.
Then when you want to do the transactional operations:
Code:
op1();
execute_rollbacker guard;
op2();
guard.cancel();
Simple, and with no control statements at all. It is far more scalable to a larger function as well. This is just one of many applications of the "Resource Acquisition Is Initialization" (RAII) resource management idiom, support of which, is one of the best features of C++.
Yes, it would probably take a novice a little longer to understand the second one (although not much longer, if they know neither approach to begin with), but the second approach is far more powerful, flexible, and less error prone than the first.
-Sirp.