# Why are not programs already in binary code?

First of all, please forgive me if this question shows ignorance on my behalf. What I'm asking is not why we don't program in languages written in binary code, I know the answer for that. What I would like to ask instead is: considering all information we input into a computer is registered as binary code, and all data is stored in binary code, are not common programming languages already binary code, and what we see as instructions or variables just a translation? If that is so, why are assemblers or compilers necessary?

• (The part between colon and question mark is too complicated for me.) are not common programming languages languages are sets of symbol sequences. Any given sequence in a programming language is a program - some argue correctness is required, too. What we see (on paper, screen, …) to me are renditions. Then, there is binary code and binary code. Jan 1 '20 at 17:39
• I believe that people answering this question are conflating two meanings of "binary code": (a) machine code, in other words, the programming language of a processor; (b) binary encoding of programs, as opposed to text encoding. For (b), see softwareengineering.stackexchange.com/questions/119095/… . Feb 26 '20 at 18:46

Let me expand on this. The very first generation of computers were indeed programmed directly in binary, either by entering each binary instruction using physical switches on the computer itself or by some simple bulk loading mechanism such a reading and loading instructions from a paper tape. This was first generation programming (although at the time it was just called "programming").

Programmers soon realised that it would be simpler and quicker to write programs use mnemonics instead of binary instruction codes. So instead of having to remember or look up the binary code for "load the next byte into register A", they could use the mnemonic "LDA". Translating mnemonics into binary instructions required a program called an assembler. Once someone had invested the time and effort into writing an assembler on a particular computer, programs could be written in mnemonics or "assembly language". This was much quicker than working out all the binary codes for yourself, and it also made it much easier to debug and update programs. This was second generation programming.

As more and more programs were written on different machines, programmers realised that the underlying concepts of programming were similar, regardless of which type of computer the program was being written for. Programmers would be even more productive if they could use a language that implemented concepts like variables, loops, case statements and sub-routines. It would also be convenient to be able to write complex instructions like "print the following string of characters to the screen" or "multiply A+1 by B+2, divide the result by C and store the final result in a variable called D" in one line of code instead of multiple assembly language instructions. So programmers invented higher-level languages such as FORTRAN and BASIC (and eventually C and Java) and wrote compilers and interpreters which would translate code written in a higher level language into assembly language instructions or directly into binary instructions. Not only did this make programmers even more productive, but also by creating compilers for different types of computer, the same FORTRAN program could be translated and run on different computers. So programs became portable and programmers did not have to learn lots of different different assembly languages. This was third generation programming.

Mainstream development in programming languages and computer architectures have continued in this direction, with more and more layers of abstraction between the languages that programmers write in and the machine code instructions that a CPU executes directly. Programming languages have become more specialised, with languages specifically designed for implementing user interfaces; processing data in large databases; creating management information reports; running simulations; processing graphics; developing video games etc. Developments in computer architecture design have concentrated on running a relatively small, simple and general set of machine code instructions more rapidly. Increasing CPU speeds and falling memory costs mean that it is more cost effective to translate each line of high level language into hundreds of machine code instructions than it would be to develop more complex CPUs that could execute higher level language code more directly.

You ask a good question. Why doesn't a CPU just execute say C++ directly? Why go to the trouble of translating it first (i.e. compiling or interpreting) into some arcane machine language (Intel x86)?

The answer is all to do with flexibility. Computer hardware architectures are designed to be able to execute a broad range of programs. To enable this flexibility there needs to be a kind of lowest common denominator - a common language to execute all those different programs.

The biggest hurdle to flexibility is that hardware is fixed in terms of operation. This means that the possible range of instructions it can execute is fixed. Yes, you could have a system whereby a microcoded CPU is reprogrammed on the fly, but there would still need to be a core set of immutable instructions that could do the re-programming.

Once you have have a fixed set of instructions, there's no possibility for upgrade or bug fixing and so on. You would have to release new hardware for every upgrade. This does happen, but constantly upgrading hardware is expensive. In other words for every new release of say the C++ standard, you would need a new C++ CPU and hardware. And for every different type of language you would need a different processor: a Pascal or C or Erlang processsor.

Of course, the way to improve the flexibility of a fixed instruction set architecture is to use emulation. Turing said that all computing machines are equivalently powerful (i.e. can run the same programs), as long as they can be made to emulate a Turing Machine. This is called Turing Completeness.

This means that one language (as long as it is Turing Complete) can emulate another language without loss of fidelity. The consequence being that all languages can be emulated by a generic CPU no matter what instruction set architecture it has, as long as it is Turing Complete.

So in practice the CPU instruction set is chosen so that it most closely fits the hardware model (bits and bytes) and then languages (C++ etc.) are emulated by it principally through a translation process (either compilation or interpretation). This gives you the most bang for your buck. You can upgrade and tweak and bug fix your translator to your heart's content and all the time keep the same hardware.

In practice this works both ways, hardware is made so that it is backwards compatible, so even new hardware can run older languages. It's win win.

But. My own personal opinion is: why not have a C language CPU? The whole world runs on C right? Compilers would then be very simple, but CPUs orders of magnitude more complex. Software is cheap, hardware is not.

Though the programs are in binary code, they are not still in the form of most basic operations that a CPU's logical unit can perform. The assemblers and compilers would remove the for loops, functions, etc that is our way of interpretation, and convert the code into one that comprises of more fundamental operations. These can then be processed by the logical unit of CPU.

That would be akin to reading a natural language in another with the same character set, "Hello" is meaningless in Italian even though the letters are in the Italian alphabet. Interpreting the code as we see it with English words and mathematical symbols into CPU instructions is meaningless for the CPU.