When learning about computer hardware and digital electronics, we learn about the CPU and how it fetches, decodes, and executes instructions with the help of the fetch-decode-execute cycle, but where actually do those instructions come from? They need to be written, which is done by something called programming. (If you have no fucking clue what the fetch-decode-execute cycle is, look up Stored Program Execution on the Internet, or maybe I’ll write about it on my blog soon?)

There are all sorts of programming languages out there that can be categorized into generations, and their generation indicates how close they are to the hardware.

The first-generation - Machine Language

To speak directly with electronic hardware, we need to send electric signals (0 and 1), and these two signals are the only things that the microprocessor understands. Machine language consists of instructions made up only of 0s and 1s.

Why only 0s and 1s as electric signals at the lowest level?

Having anything more will make the digital design harder and more confusing to implement as we’ll have to specify ranges. Example: 0v = 0, 1v = 1, 2v = 2 Sometimes due to interference or lack of power, we may not get proper results, say we wanted to give 2 as a signal but due to low power supply, we could only have 1v, thus the machine will get 1 as a signal, thereby confusing it and causing unnecessary drama. The 0 and 1 system is already good.

An instruction is a command we give to a computer system to instruct it to do something,

Format of machine-level language instruction:

  • Opcode (Operation Code): Instruct the computer on what functions are to be performed
  • Operands: Instruct the computer where to find/ store data for the desired operation
0101 00111 11110
  |     \       \
┌────┐   ┌─────┐ ┌─────┐
│0101│   │00111│ │11110│
└────┘   └─────┘ └─────┘
Opcode     A        B
            Operands

Advantages

  • Faster (>high level) because of the lack of translation overhead
  • Extremely granular control on hardware

Disadvantages

  • The language is very much dependent on the hardware. Lack of portability is a big problem here
  • Since the language is all 0s and 1s, it makes it much harder to learn
  • It takes time to write code using machine language (it’s fricking obvious)
  • Less efficient (of course! because it’s very difficult to code in)

The second-generation - Assembly Language

Since writing machine code was extremely hard, processor-dependent, and time-consuming, something was needed which was closer to the way humans think.

Assembly is the symbolic representation of binary instructions in which mnemonics are used instead of binary instructions. Mnemonics are the mappings for the binary machine codes so as to enable faster writing and debugging of code. The instruction:machineCode mapping is maintained by the ISA (Instruction Set Architecture)

Example: in the 8085 architecture, A register is the mapping for 111, and ADD is the mapping for 10000, when we assemble our code for say ADD A it would get translated to (10000)(111)

Since abstraction is involved, mnemonics can’t be directly understood by a processor, and an assembler is needed to translate Assembly Code into its machine equivalent.

;; Format of an assembly instruction:

label: mov A, B
;;In this scenario, label will have the value of the address where this instruction is loaded in memory and can be used to reference it.

Advantages

  • Relatively easier to understand and use
  • Less error-prone than directly writing machine language
  • Faster (>high level)
  • (still) control of hardware

Disadvantages

  • Not cross-platform, and very specific to the processor family such as Intel has IA-32 and IA-64
  • Harder to learn
  • Slow development time
  • Less efficient
  • No standardization

The third Generation - High-Level Languages

Even though assembly made it easier for programmers to code, it was too procedural in nature viz. closer to the way a processor executes instructions and not how a normal person would think. This is why we added more abstraction and invented High-Level languages

HLLs allow a program to think in a more natural language than a set of imperative statements that will be executed by the microprocessor.

Example: C, Java, COBOL, FORTRAN, C++, Perl, SQL, JavaScript etc

Advantages

  • Offers ease of development (easy to read and code in, easy debugging, and easy maintenance)
  • Machine-independent and compilers/ assemblers will handle the translation.
  • Lots of hardware operations managed by the language itself
  • No need to know computer architecture in detail
  • Less time taken to develop the program

Disadvantages

  • Less flexible than low level
  • All the additional steps increase the execution time of an application