Is c ++ necessary to learn Java

Community

Who?

This is Sascha 'Xin' Atrops' personal opinion on the question of whether you want to learn to program with Java or C ++ as your first language. Unless otherwise stated, the arguments also apply to C #.

Background

I have been programming since 1986 and I have a degree in computer science (FH). I worked as a Java developer and am currently jointly responsible for, among other things, 3D visualization in a CAD program. I am also developing the Genesys programming language and the associated compiler. I wrote my diploma thesis on the subject of programming languages ​​and their design. I taught C and C ++ to several dozen people, partly as a tutor at my university, where I taught students with Java experience, partly without any programming experience.

short version

I advise you to learn C first and, as soon as the basic constructs are known, to switch to C ++ when the decision is between C ++ and Java / C #. If there is no preference for the programming language at all, the article “Choice of programming language” may help.

As a programming novice, you will probably not yet understand much of what is discussed here. This ensures that a newcomer will not be able to consciously make the right decision afterwards. Therefore, anyone who would like to ask questions on this topic is invited to do so in the forum.

My reasons

The argument that I am making here may seem a bit far-fetched for some, I am aware of that, but I would like to emphasize that I do not orient this opinion towards short-term learning success, but towards long-term qualification.

The learning process

There is a myth that C ++ is more prone to errors than Java. I would like to clearly deny this statement and explain how this statement comes about.

If you start to learn C ++, you will run into errors even with very small programs. Even with Java, not everything will run perfectly straight away. With Java you will get exceptions that give you an indication of what actually happened and the C ++ programmer has to get used to the fact that his program simply ends with "Segmentation fault" from Linux / MacOS, or Windows a message box opens "The program had to be closed".

Here, the Java programmer receives a hint directly, so he has an advantage at first, while the C ++ student may be frustrated because he cannot explain the reaction. While the Java programmer eliminates the error, the C ++ developer has to go to himself and try it out until he finds the error. At that moment he is not learning C ++, at that moment he is learning to program. So while the Java developer takes care of the symptom, the C ++ developer has to develop two qualities: First of all, he has to develop a certain tolerance for frustration, i.e. the desire to solve the problem instead of simply giving up, and he has to try to grasp and understand the problem .

C ++ is less forgiving of mistakes and offers the beginner many more opportunities to fall into a trap. In my experience, learning to program is not about learning how to program, it is about learning how not to program. I'm not teaching the one way how to do it right, but the ways how not to do it and why not going those ways.

This process of figuring out the wrong paths can be much less frustrating with a skilled teacher. In the tutorials, dealing with things in a really meticulous manner meant that the students with previous knowledge of Java sometimes had difficulties understanding the problem solutions because they were too simple. Attempts have been made to build a complex structure around the solution that should facilitate understanding rather than simply accepting the simplicity of the solution.

C is like math - it doesn't get hard until you've learned it's hard - and it only stays hard as long as you think it's hard.

No matter which language you prefer to learn programming, you have to know the paths that lead to ruin, in C ++ as well as in Java. In Java, however, you can put off a lot of paths. The advantage is that you don't get so frustrated at the beginning, but get a sense of achievement more quickly. The frustration comes later, when one has already developed the belief to call oneself advanced. The pitfalls that were left out as a beginner now have to be mastered in larger programs. That makes the search more time-consuming and difficult.

At this point, in my opinion, the C / C ++ students overtake the Java students again. Armed with a wealth of experience as to which mistakes you should avoid and, above all, to be more critical of the knowledge of your own programming, you program more effectively, more carefully and make fewer mistakes.

With the paths that are left, you are free to do what you want: whether you limit yourself to the rhetorical quality of a prose novel, learn the art of programming well (e.g. design patterns) or become a poet Developed for source texts, everyone has to decide for themselves.

Java forces the developer to a complex error handling with exceptions. Forced error handling - even when an error is excluded - hinders the development of fault-tolerant algorithms. Beginners often write elaborate fault considerations instead of realizing that they could write a short algorithm that cannot fail. Since exceptions (which often cannot occur) have to be handled, many beginners no longer even think of simplifying an algorithm and thus speeding it up. The language thus hinders the development of the student.

The Java hype and the consequences

When I learned Java, it was said that Java avoids errors because it doesn't have pointers. I don't think there is anyone today to say that, but it was taught in universities back then. No meaningful programs worth mentioning can be written without pointers.

In addition to the few primitives (basic data types such as int, char, which a good developer should not actually use if possible, but are specially typed, e.g. class Id, class Size ...), only reference types (i.e. classes), which are in Java pointers means, which Java calls "reference" and addresses with the '.' operator, which suggests false security to a C ++ developer. The fact is: C ++ can embed class instances in classes or manage them locally on the stack (RAII). In C ++ there are references that, when used correctly, deliver a contract that they point to an existing object. You can't check them for zero because they can't be zero. These references do not exist in Java. There are no embedded class instances. There are only pointers and null pointer exceptions.

The fact that there are only pointers means that a constructor in a class must initialize all reference types with new for the first time. If you forget something here - e.g. within a condition - errors occasionally occur.

Embedded classes under C ++ neither require additional commands to request memory, nor can they be uninitialized, since at least the standard constructor is executed.

Another feature that was hyped at the time are the exceptions. Exceptions are not a new feature of Java, C ++ also supports exceptions, but they are only used very sparingly in C ++.

Exceptions are usually raped in Java. In addition to error handling, the normal course of the algorithms is declared to be an exception if something does not go exactly as the developer wanted. If you want to open a file and the file does not exist, you have an exception. But is it really so unusual that a file is not available because it has not yet been created, for example?

In order to correctly map an algorithm in Java, a program explodes in exception handling. Even if exceptions reduce the number of places where errors are handled, the most important information about an error is lost with an exception: Where did the error occur? So there is no information about what I have already done, which resources have I used? In relation to the missing file: If I want to open 10 files, I suddenly get the information that the file could not be opened. Which file? And if that is a file that interests me, maybe this file can be left out. All of this has to be retested. The answer is often that this information can be passed on to the exception. However, this makes it even more time-consuming to first describe the error case in order to then test what has happened and then react accordingly. If I look at the error at the point where it happens, I know exactly how many files I have already read and whether the file to be read is important enough for me to see it as an error.

During my time as a Java developer, it became apparent that there was no time for correct exception handling in everyday life because it was extremely time-consuming. I would like to emphasize that I partly made up for other developers' error handling because I needed it for myself. However, as soon as the first only passes the base class on, any meaningful error handling is lost. However, the Java development environment 'Eclipse' suggests this approach, so it is done.

Correspondingly, error handling is neglected. Above all, it is not conclusive, even if you try to do it. In this way, exceptions are caught by exception base classes that were not extended for this exception that was added later. This is a bug, but this problem occurs when you use exceptions. The error is declared to have been dealt with, so that invalid objects can continue to live and later cause errors in what are actually correct sections. These errors run randomly and are extremely difficult to test or reproduce, especially since the program explodes at any point that does not have to have anything to do with the error. Understanding of the big picture of the program is lost, just as exceptions jump right through the program. There is no clear process.

I've been teaching Java developers in C / C ++. It looked more like group therapy because I had to ask these developers about their understanding of programming to find out why they had problems programming in C ++. The idea that Java beginners develop of their abstract machine is often very vague. C / C ++ does not allow this blurry view, these are the beginner mistakes a C ++ student must first understand. Java does not allow these errors either, but this is often only noticeable in larger programs if you are lost in it.

significant linguistic differences

Const correctness

C ++ is semantically stronger. This includes specializations in templates, such as - even more important - const-correctness. A feature that Java completely lacks and helps me in C ++ not to inadvertently modify data that I better not access at the moment, e.g. because I need it in an unchanged form elsewhere. This restriction cannot be formulated in Java.

Multiple inheritance

C ++ supports multiple inheritance. In Java they were removed to prevent the diamond problem. Multiple inheritance or the diamond problem are not a bad spell, but a very useful feature. Applied correctly, multiple inheritance helps avoid redundancies (repetitions of the same text passages) in the code. Less code means fewer opportunities for errors and, at the same time, higher test coverage.

Instead, there are interfaces in Java to prevent the diamond problem. However, implementing interfaces in Java often means redundant sections of code. Redundancy means that when changes are made, there is an extremely high probability that a redundant point will be overlooked, so that a bug can be installed quickly. There are now, say, 10 correct interface implementations and one implementation that has been overlooked. This bug appears seemingly arbitrary, since (almost) all implementations are correct. Problems suddenly arise only if a faulty implementation is called up by chance.

With multiple inheritance there is only one place. It is either always correct or always wrong and therefore easy to find. If it is always wrong, the error will also occur more frequently: You also have a higher test coverage of the existing code.

The diamond problem is well known and needs to be understood by the C ++ student so that the developer can decide whether he needs this as a feature or whether he wants to avoid it. The situation can be precisely controlled in C ++ using virtual derivations. To do this, of course, you have to know what you are doing. Otherwise, the diamond problem can be reconstructed in Java / C #, in other words: It is not solved by prohibiting multiple inheritance.

Garbage collection

Another important difference is garbage collection. The developer doesn't have to worry about freeing up memory again. Garbage collection does that for you. That sounds good at first and also works wonderfully for small programs, but unfortunately it's not that easy to get out of history as soon as you write something that is to be taken seriously. The garbage collector starts up at some point and tries to free memory. At that moment the Java program stalls and that can stagnate noticeably.

Imagine this with an airbag control program at the moment an accident occurs. The garbage collector starts up, the car hits an obstacle. Until the garbage collector is finished, the head hits the steering wheel. The garbage collector is now ready, the program continues, detects the accident and ignites the airbag. The control of an airbag is time-critical and therefore has to be taken seriously.

Every resource that is time-critical (e.g. the airbag) or is not available as often as required (e.g. a printer, a file) must be released immediately so that other programs can also use it. The bottom line is that the garbage collector unfortunately only helps with small programs or applications where it doesn't matter whether the software shows no reaction for a second.

A garbage collector is limited to a certain memory size, which is determined when the program is started. If the memory size becomes too large, memory is used up until this memory is occupied and the rest of the computer has less memory available and has to swap to the much slower hard disk. If the selected buffer for the garbage collector is too small, the program may not be able to be executed due to insufficient memory or it may crash even though gigabytes of memory are still free. The garbage collector solves a beginner's problem, but creates new problems: the frustration comes later.

Thanks to its own memory management, however, the request for memory is faster and - as long as the garbage collector does not start up - no memory has to be released. So here Java is faster than C ++ (just as long as the garbage collector is not running). C ++ requests new memory from the operating system, which takes longer due to the context change (the program asks the operating system and then has to wait once). However, variables that are on the stack do not have to be requested by the operating system and in the case of embedded classes, the memory is requested in one go with the enclosing class and does not have to be requested for each variable as in Java. The advantage that Java requires faster memory is more of a theoretical nature here. If it becomes practically relevant, memory management in C ++ can also be taken over by optimized, custom implementations - for all classes or specifically optimized for each individual class. (see Real World Comparison, GC vs. Manual Memory Management)

object oriented programing

Object-oriented programming is sometimes sold as a paradigm (basic programming style), then again as the non-plus-ultra of programming. I have to disappoint whoever says that. Object-oriented programming is a programming technique; it solves a certain problem, comparable to lists, which solve the problem that you cannot insert into arrays without problems. One buys the simpler possibility of inserting and deleting data in lists, but it takes more effort to search through a list. In the same way, you pay a price for object-oriented programming in the form of computing power: the program becomes slower.

The fact that virtual function calls are called “messages” in the theory of object-oriented programming does not make it a wonder of the world. A virtual function that creates a connection to an object on another computer does not change anything in the concept, on the real machine it remains virtual functions. In Java everything is virtual until it is declared to be static calls with "final".In C ++ everything is static (that is, the method is static in one place in memory and does not need to be searched first) until it is declared a virtual method. Evaluating which method is chosen for the virtual method call is not expensive - but it is not free either. So if you need this additional function, you have to buy it in C ++ using the keyword “virtual”, in Java you have to use the keyword “final” to make it clear that you don't want to pay an unnecessary extra. I have rarely seen the keyword “final” in Java source codes. So you almost always pay.

Virtual access to a method - the interesting part of object-oriented programming - is superfluous for most method accesses and should be chosen carefully. C ++ chooses the fast way here and allows the developer who understands the concept to use virtual methods - Java basically uses virtual methods, the developer does not have to understand the interesting part of object-oriented programming - it works. It just costs computing time, but if you don't know, you don't care.

The JIT compiler

The computer can only run compiled programs. Java programs are delivered in bytecode. The just-in-time compiler compiles a Java program when the program is started, while a C ++ program is immediately compiled. Starting a Java program therefore not only means loading the program, but also the JIT compiler and, finally, the program must first be compiled.

It is sometimes said that the JIT compiler can optimize the program flow at runtime. That's right. To do this, he has to recognize when it is worthwhile to recompile a program in a modified form so that it can run faster. The monitoring, administration, compilation and just loading the JIT compiler takes more time than most programs actually need for the calculation. The chance of saving so much time through the (laborious) recompiling of parts of the source code that you get a statically compiled C ++ program, I would describe as more than just a small one. An example must presumably be constructed for this, but this is not to be expected in real everyday life.

Frameworks

The Java framework and .NET in C # provide a large amount of functionality that can be accessed immediately. Unfortunately, both still contain many sins from their early days - sins that should not have been committed, since the answers could have been copied in the C ++ environment, which was also partially done in later versions (generics cover part of the template functionality from).

C ++ also comes with sins from the past, but these sins were still important when C ++ was created and were consciously accepted. In comparison, C ++ comes onto the disk with almost no functionality worth mentioning. However, there are extensions in absolutely all areas that can be used from C ++. This is where C / C ++ sets the bar, so to speak. There is so much that not everything can be included. A large number of libraries for graphical interfaces, game programming, 3D visualization, mathematics, databases and much more are available for C ++. Java and C # offer a more or less comfortable connection to the functionality that can be reached via C ++. Even if the frameworks around the two languages ​​are large, a language that does not have access to the gigantic pool of libraries available for C ++ would also not be taken seriously.

My conclusion

Java has delivered a good approach, but fails because of the reality. An important problem has been considered, namely to simplify programming. Unfortunately, in my opinion and in my experience, you have set off in the wrong direction.

Java itself has been highly hyped, in order to achieve this, C ++ had to be poorly represented. The follow-up problems have arisen in the past five years. I know of large companies that are now doing away with their internal Java products and reimplementing them with other languages. The Java hype is over. However, the popularity of Java will continue for a few more years: With people who don't know better, with decision-makers who still have the marketing sayings of the last decade in their ears and due to the fact that the software that was written in the last decade after all, cannot simply be thrown away. So learning Java is still worthwhile, especially since it is generally not a bad language. C ++ is only better suited for learning if you want to understand Java: "C ++ developers know what they are doing.", I was told as a reason why they chose me as a Java developer, even though I am a C ++ developer in had no significant Java experience at the time.

C ++ is not the answer to the question of what the programming language of the future will be. C ++ is old, has inherited a lot from C that is no longer desirable today and is also not particularly progressive. But it is still clearly superior to Java and C #. In my opinion, it is closer to future language concepts than Java or C # and it does not allow the learner to muddle through with half-knowledge. The learner should not necessarily confuse the frustration at the beginning with their own inability or with the mistaken belief that C / C ++ is difficult. It's just one of those things that you have to learn sooner or later in any language. In C ++ you learn a lot at the very beginning, as long as the programs are still manageable.