Code – from symbols to program
Human speech is fruitful, rich, colorful, and way beyond what the words themselves may express. Nouns, verbs, and adjectives for precisely expressing a moment or action can be used. In contrast, machines do not understand the complex constructions or expressions that humans are able to create.
Machine language is limited, well-defined, extremely specific, and simplified. Its goal is to provide the precise expression of intent for which it is designed. This contrasts with human language whose purpose is just communication and not necessarily with specifics.
A machine’s intent can be expressed as a defined instruction or a set of them. This means that machines understand the instructions. These instructions must be available to the machine in some form at the time of execution. Each machine normally has a set of instructions. Based on this kind of instruction set, machines can perform the required instructions, as shown here:
Figure 1.1 – A simplified instruction cycle inside the CPU (instruction is taken from memory and the result is stored)
Let us explore one individual instruction. The instruction can be understood as a command given to the processor. The processor is the heart of the machine, or the center of the ordering and executing of processes. The machine may contain one or more of them. It depends on its design, but in any case, there is always one that takes the lead. For further simplification, we will only consider one – that is, consider a system that only has one central processing unit (CPU) dedicated to executing a program.
A CPU is a device that executes instructions containing a computer program. The CPU must contain such an instruction set, as shown in the previous diagram, to process the requested action.
Because instructions can take completely different forms depending on the CPU, there is no defined standard. This promotes different CPU platforms, which is not necessarily a bad thing and contributes to evolution. However, the fact remains that the instructions are not easy for people to read.
We have stated that machines can perform instruction collection, ideally as a continuous flow. The flow of instructions can be simplified as a queue in memory, where one instruction goes in and the other leaves. The CPU plays the role of an interpreter who works with this memory cyclically (as we saw in Figure 1.1). Okay, so the CPU interprets, but as the instructions are added to the memory, where do they come from, and how can such a stream be created?
Let us gather some thoughts. Machine instructions, in most cases, originate from a compiler.
What is a compiler? The compiler can be viewed as a CPU or a platform-specific program that translates text into target actions. The text we use to call the program and the result could be named machine code. The following diagram illustrates this:
Figure 1.2 – A simplified platform-specific flow from the source code through the compiler program to its resultant action
Machine code is a low-level language that the machine understands and consists of language instructions that are processed sequentially (see Figure 1.1); the program was compiled, executed, and run.
In the case of Java, there is no machine code:
Figure 1.3 – A simplified flow for the Java program through the compiler to its platform execution
The source code is compiled by the Java compiler into bytecode. The bytecode is running a Java virtual machine (JVM) (see Figure 1.3). In this situation, the JVM plays the role of the interface between the bytecode and the actual instructions that are executed on the CPU. The JVM emulates a bytecode instruction. It does this using the just-in-time (JIT) compiler that is part of the JVM. The JIT compiler translates bytecode instructions into native processor instructions. The JVM is a platform-specific interpreter, analogous to directly compiled code (see Figure 1.2). The JVM also provides additional features such as memory management and garbage collection, which is what makes the Java platform so powerful. All these features allow developers to write code once, compile it into bytecode, and run a supported platform – known as write once, run anywhere (WORA).
In the context of the previous exploration, Java is a high-level language that is translated to a low level. Java provides a strong abstraction from the details of computer functionality. It allows programmers to create simpler programs for complex challenges.
At this point, we begin our journey of jointly exploring standardized solutions. Later in the book, we will review how to create code that is maintainable and extensible with fewer memory requirements. Together, we will discuss different types of design patterns that can help us to make our daily work understandable, transparent, and more fun.