programming

from Machine Code to JavaScript

Machine Code

It's important to remember (see the notes on What's a Comuter) the computer is a very specific (and complex) arrangement of circuits in such a way that makes it possible for it to remember values and manipulate values (do math), but how does electricity become "values"? That's where Machine Code (often written in binary code) enters the picture. That electrical current is made up of high voltages and low voltages which we refer to as a 1 or a 0 (binary code) for the sake of being able to use these voltages to represent values or data.

As the video above explained, binary code can be used to represent ANY data we choose and we can give the computer data in binary code to operate on, in the old days we would do that by flipping switches (on/off 1/0) or storing our data in punched cards/tape (whole-punch/no-whole-punch 1/0) and having the computer read the tape. We can also pass instructions for what we want the computer to do with the data, computers are designed to (or "wired up to") interpret certain sequences of binary code as instruction codes (like "add" this, or "store" that), and so early programs could look something like this:

machine code
click the image to "step" through the program ↑

Programmers rarely ever deal with binary code directly, we made things easier by writnig "assembly code" which were slightly more human readable versions of this machine code (which we would translate into binary before running), here's the same program in a hypothetical assembly language:

     	ORG 0
     	LDA A
     	ADD B
     	STA C
     	HLT
     A,	DEC 84
     B,	DEC 12
     C,	DEC 0
     	END
	   

It's rare you find folks working in assembly these days (though some folks do, check out the cool 8bit art of Rachel Weil for example) becuase if it's that complicated to tell a computer to add 2 numbers together it be virtually impossible to make it do much more complicated tasks (generally speaking, Rachel might disagree). Add to that the fact that you need to know the instruction codes and "architecture" (how the switches are wired up) for every CPU design if you wanted your program to work on every computer (the only computer Rachel worries about is the NES) and you would have to re-write your code each time, essentially you would have to be quite the expert to do even really simple things... enter Grace Hopper:




Programming Languages

This code is an example of FLOW-MATIC the first "english-like" compiled language developed under Admiral Hopper, which would eventually lead to COBOL, which is still used today.

      INPUT FIRST FILE=A SECOND FILE=B,
      OUTPUT SUM FILE=C;
      ADD A TO B
      TRANSFER B TO SUM
      CLOSE-OUT FILE SUM
      STOP.
      

It's an obsolete language, but this is as close as I can approximate what it would have looked like to add tweo numbers together, let's assume the values 84 and 12 are stored in file A and B. Admiral Hopper also popularized the idea of machine-independent programming languages which is generally how we think of programming languages today.

Today we have lots of "higher level" (of abstraction) languages meant to be written and read by humans. Different languages specialize in different contexts (for example JavaScript is ideal for programming apps for the web) and they all have different "syntax" but ultimately they can all do the same things (JavaScript could be used to write pretty much anything, not just web apps). In order to use a language on any given system (particular computer architecture) you need to make sure someone has written a compiler or interpreter for that language on that system so that your code can get translated to the machine code the computer needs in order to actually run your program. Here are a few more examples of the same simple program written in a few different languages, notice their general similarity despite their difference in syntax

// C 
#include <stdio.h>

void main(){

  int a = 84;
  int b = 12;
  int c = a + b;
  printf("%d\n", c );

}
// Java

class myprogram {
  public static void main(String args[]) {
    int a = 84;
    int b = 12;
    int c = a + b;
    System.out.println(c);
  }
}
     
// JavaScript (aka ECMAScript)

function main(){
  var a = 84;
  var b = 12;
  var c = a + b;
  console.log( c );
}

main();

# Python 

def main():
  a = 84
  b = 12
  c = a + b
  print(c)

main()

     
<?php # php 

  function main() {
    $a = 84;
    $b = 12;
    $c = $a + $b;
    echo $c."\n";
  }

  main();
?>
// C++
#include <iostream>

void main() {
  int a = 84;
  int b = 12;
  int c = a + b;
  std::cout << c;
}

     



JavaScript

As we've discussed computer programming languages are meant to be read by people, in order for computers to understand your code (your instructions) it needs to be translated into machine code that the computer understands. Typically, this is done by running your code through a compiler which will spit out a machine code version of your file (the "source" code) that the computer can actually run (the app/program or "binary"). Another way to do this is with an interpreter or "runtime" which rather than converting your source code into a separtae machine code file, it will translate your code for the computer right at the time you run your file through the interpreter (ie. at "run-time"). All your browsers and many other apps (including Adobe's creative apps like Photoshop and the apps of the Microsoft Office suite) have a JavaScript runtime included in them. This means we can write JavaScript code that can run inside these various apps in order to write "scripts" for controlling these applications. But it's also possible to create our own applications using other JavaScript "libraries" and "frameworks", for example we can create terminal or CLI (command line interface) apps using pkg and we can create native GUI (graphical user interface) applications for desktop using electron (but these are both beyond the scope of this lesson).

There is also a standalone runtime, specifically a jit (or just-in-time) compiler which we can run in the terminal (like we would for other languages like C or python using their terminal based compilers and interpreters) which is called nodejs. Visit the nodejs website to download the LTS version (the latest stable long-term-support version) of the compiler. Then after you've installed node make sure everything's working by running node -v in your terminal (you may need to quit and relaunch your terminal after installing node first). If you see your node version number print to the console then you've got it installed! There's a couple of ways to get started from here, like most CLI apps you can run man node or node -h or node --help to learn more about it, but in our case (to finish this lesson) we're going to launch the node "shell" in order to write and run some JavaScript code.

nodejs demo

If you run node without any arguments it will open up a JavaScript shell, this is essentially an interactive JavaScript environment (it's sort of like being "inside" node) every line of JavaScript you enter (as in type-in + hit enter) will automatically get turned into machine code and executed by your CPU then returned back (echoed) to the shell. Once in the shell enter a number to see the shell echo it back to you. This worked because numbers in JavaScript are an official data-type so the shell can return it back to you. Next try writing something like 84 + 12, this time it returns 96 b/c the + symbol in JavaScript is an "operator" which is used to load up that "ADD" instruction we discussed earlier and return the result of that operation.

A fragment of code that produces a value is called an expression. We use operators in conjunction with data to write expressions. While an expression like this one is as simple as it possibly gets, I hope this background (from Machine Code to JavaScript) gives you a bit of an appreciation for the level of abstraction programming languages like JavaScript provide.