The programming language is our interface
for speaking to the computer and getting it to follow our instructions. We write code
in what we refer to as a “high-level” language. Some examples of high-level languages include
C++, Python, Ruby, Scala, Fortran and Java, which is the language we’re using in this
course. The instructions we write have a syntax – basic rules that we must follow in writing
each statement – that another program called the compiler uses to convert the high-level
instructions to a low-level state that the machine itself can implement. The computer stores all data as binary information,
zeros and ones. This includes instructions. We would struggle to write code in binary,
which is why a wonderful woman named Grace Hopper did all of us a favor in inventing
the compiler. With a compiler, we can write our code in a form that resembles English.
It still has patterns and rules which must be obeyed, but the code is readable to us.
The compiler translates those words and symbols – referred to as tokens – into instructions
specific to a machine’s instruction set architecture. Most machines have a limited vocabulary of
their own, and these instructions map to specific actions that the computer can execute. Some
examples: ADD, JUMP, FETCH, STORE. Some of our individual high-level instructions when
translated make up several instructions in machine code. We consider these instructions
still readable, but less-so. This stage is what is known as assembly code. From there
each instruction can be mapped to binary codes that refer to specific machine operations,
memory locations, and numerical representations. More recently, another model for translating
high-level instructions has emerged. Code that is read in small pieces and translated
on the fly is called interpreted code. Let’s look at three common languages to see the
advantages of these models. In C++, we have a compiled language. The instructions
for a C++ program are compiled for a specific instruction set – i.e., your machine. This
means that the lines execute more quickly, and can be optimized during the compile process
to become more efficient. Unfortunately, your code is not portable, as a distinct version
needs to exist for every type of instruction set architecture. Looking at Python, we have an interpreted
language. These instructions are translated on the fly, which grants us machine-independence.
Our high-level code is portable, but runs more slowly as pieces are frequently compiled
for a specific machine at run-time. In Java, the language we will be using, you
have a hybrid process. Java is compiled to an intermediate stage called “bytecode”. This
bytecode can be run on any machine by the Java Virtual Machine (JVM), which does what
is known as just-in-time translation of bytecode to machine code. The JVM already knows the
specific of your machine, so it can translate faster than an interpreted language like Python.
This model does allow for machine-independence, and runs faster because it has been pre-compiled. There are many programming languages, and
each offers advantages and disadvantages for particular tasks. Your choice of one language
over another is usually based on the type of programming task you are taking on. Java
is a good general-purpose language, and has features common to most languages at the basic
level. This course will focus on these basic features, which you can learn throughout your
programming lifetime even as you move on to use other languages. Our next topic will address the system that
the machine language is based on, binary numbers.