What Is Programming Part II

From CompSciWiki
Jump to: navigation, search

COMP 1010 Home > What is Programming?


Introduction

Programming languages are written languages that allow people to specify how a computer should behave. There are three major types of programming language:

  • High-level languages
  • Assembly languages
  • Machine code

Most people do all of their programming in high-level languages, with some low-level operating system code written in assembly languages. In COMP 1010 you will be doing all of your programming in Java, a high-level language. If you continue your studies in Computer Science you will study assembly languages and machine code in more detail in other courses.

   

{{{Body}}}

High-Level Programming Languages

High-level languages are the most commonly used languages for computer programming. They tend to be the most easily read by a programmer, though they require the most work to turn into machine-readable code. This work is called compilation or interpretation, and is done by specially-designed computer programs called compilers or interpreters.

There are three major families of high-level programming languages, each with their own advantages and disadvantages:

  • imperative languages
  • functional languages
  • declarative languages

Imperative Languages

Imperative languages are the most commonly-used types of programming languages. They differ from other types of languages in that each line of code, or statement, tells the computer to do something: read this file, print this sentence, etc... Imperative languages are generally the simplest languages for beginners, but offer enough depth and control that advanced programmers make use of them too.

Some of the best-known imperative languages are:

  • Java
  • C/C++
  • Pascal
  • BASIC (Visual Basic, QuickBasic, VB.net)
  • Perl
  • Python


Functional Languages

Functional languages are rarely seen in everyday use; they are typically used for artificial intelligence research. However, there are some programmers who do the majority of their programming using functional languages.

They key property of functional languages is that every program is a single function that is evaluated. This function can be made up of smaller, simpler functions in much the same way that mathematical functions can be combined. For instance if we take the functions f(x) = 2x+1 and g(x) = sin(x) we can combine them to create h(x) = g(f(x)) = sin(2x+1).

The best known functional language is Lisp, though some imperative languages (such as Python) offer functional programming capabilities.


Declarative Languages

Declarative programming is very different from functional and imperative approaches. Functional and imperative programming focus on defining functions and procedures that the computer will follow. Declarative programming focuses on defining what the problem is and what the solution should be, and the computer determines how to actually solve the problem. The program itself is a set of rules about the information to be processed and what the output should be.

The only commonly used declarative programming language is Prolog.


Comparison between Imperative, Functional, and Declarative Programs

The following examples illustrate the differences between the different types of programming languages. One language from each family is used: Java (imperative), Lisp (functional), Prolog (declarative).

Example #1: Hello World

This is a very simple program that, when executed, will print the words "Hello World!" to the screen.

Java
public class Hello
{
    public static void main(String[] args)
    {
        System.out.println("Hello World!");
    }
}


Lisp
(defun main () (quote "Hello World!"))


Prolog
assert(main :- write("Hello World")).


As you can see none of these programs are terribly complex; they consist of one simple function: the command to print the words "Hello World!" to the screen.

Example #2: 99 Bottles of Beer

This is a slightly more complicated example that prints the lyrics to the song "99 Bottles of Beer" on the screen:

99 bottles of beer on the wall!  99 bottles of beer!  Take one down, pass it around, 98 bottles of beer on the wall!
98 bottles of beer on the wall!  98 bottles of beer!  Take one down, pass it around, 97 bottles of beer on the wall!
97 bottles of beer on the wall!  97 bottles of beer!  Take one down, pass it around, 96 bottles of beer on the wall!
...
2 bottles of beer on the wall!  2 bottles of beer!  Take one down, pass it around, 1 bottle of beer on the wall!
1 bottle of beer on the wall!  1 bottle of beer!  Take one down, pass it around, all done!


Java

Here we define a main function that will loop through the numbers 99, 98, 97, ..., 4, 3 and print out the lyrics with each number. After the loop the lines for 2 bottles and 1 bottle are printed separately to make sure that the pluralization is correct.

public class BeerSong
{
    public static void main(String[] args)
    {
        for(int bottles=99; bottles>2; bottles--)
        {
            System.out.println(bottles + " bottles of beer on the wall!  " + bottles +
                               " bottles of beer!  Take one down, pass it around, " + 
                               (bottles-1) + " bottles of beer on the wall!");
        }

        System.out.println("2 bottles of beer on the wall!  2 bottles of beer!  Take one down, pass it around, 1 bottle of beer on the wall!");
        System.out.println("1 bottle of beer on the wall!  1 bottle of beer!  Take one down, pass it around, all done!");
    }
}


Lisp

As mentioned previously, Lisp programs are one single function made by combining smaller ones. Like the Java program above, this one will count down from 99 to 1 and print the lyrics. Instead of printing the lyrics for 2 bottles and 1 bottle separately, the function cond is used to make a decision: if the number of bottles is greater than 2 the lyrics will be printed as normal, if the number of bottles is equal to 2 a different set of lyrics will be printed, and if neither of those cases occurs a third set of lyrics will be printed.

(defun BeerSong (n)
    (cond ((> n 2) (print (list n 'bottles 'of 'beer 'on 'the 'wall!  n 'bottles 'of 'beer!  
                   'Take 'one 'down 'pass 'it 'around n 'bottles 'of 'beer 'on 'the 'wall!))
                   (BeerSong (- n 1)))

          ((= n 2) (print (list n 'bottles 'of 'beer 'on 'the 'wall!  n 'bottles 'of 'beer!  
                   'Take 'one 'down 'pass 'it 'around n 'bottle 'of 'beer 'on 'the 'wall!))
                   (BeerSong (- n 1)))

          (t       (print (list n 'bottle 'of 'beer 'on 'the 'wall!  n 'bottle 'of 'beer!  
                   'Take 'one 'down 'pass 'it 'around 'all 'done!)))
     )
)
(BeerSong 99)


Prolog

Prolog programs are a set of rules. Because there are three different cases to consider when printing the lyrics (1 bottle, 2 bottles, 3+ bottles) three separate rules are defined. The first rule covers the 1 bottle case, the second the 2 bottles case, and the third the 3+ bottles case. Just like the two previous programs, the number of bottles is decremented from 99 to 1, and the lyrics are printed. The computer will find the proper rule to follow based on the number of bottles.

assert(beersong(N) :- N is 1,write('1 bottle of beer on the wall!  1 bottle of beer!  Take one down pass it around all done!')).

assert(beersong(N) :- N is 2,write('2 bottles of beer on the wall!  2 bottles of beer!  Take one down pass it around 1 bottle of beer on the wall!'),
                      beersong(N-1)).

assert(beersong(N) :- write(N),write(' bottles of beer on the wall!  '),write(N),
                      write(' bottles of beer!  Take one down pass it around '),
                      write(N-1),write(' bottles of beer on the wall'),
                      beersong(N-1)).

beersong(99).


Assembly Languages

Assembly languages are very rudimentary languages specific to every computer processor; each processor has its own "dialect". Most assembly languages are fairly similar, despite the processor-to-processor differences. There are two main families of assembly languages:

  • RISC (Reduced Instruction Set Computer)
  • CISC (Conplex Instruction Set Computer)

For the purposes of COMP 1010 it is sufficient to know that there is such a thing as an assembly language. If you are interested in learning more about assembly languages consider taking the COMP 2280 course.


RISC Languages

RISC assembly languages offer a very limited selection of operations. The philosophy behind RISC machines is to make each instruction as fast as possible, so that the processor's clock speed (measured in MHz or GHz) can be as high as possible. Every instruction does one thing, and one thing only. This means that for any complex operation to be performed multiple instructions need to be used.

Most RISC languages will include the following operations:

  • Mathematical operations
    • Add
    • Subtract
    • Multiply
    • Divide
  • Bitwise operations
    • And
    • Or
    • Not
  • Memory access
    • Load
    • Store


CISC Languages

In the early days of computer science memory was very expensive. As a way to reduce the memory required to store a program CISC languages were developped. These languages combine several RISC instructions into a single operation. While this concept does reduce the size of a program in memory, it forces the processor's speed down.

Every CISC language will have its own set of instructions over and above the standard set of RISC instructions. Some typical examples of these more complex instructions are:

  • Load-and-increment -- load data from some memory address, and then increment the address
  • Decrement-and-load -- decrement a memory address value, and then load the information from that address
  • Exclusive Bitwise Or


Machine Code

Machine code, or machine language, is literally the language that the computer itself understands. Machine code is essentially unreadable by humans, though some people who work with embedded micro controller chips are familiar with many machine code instructions.

When you compile a program written in a high-level language, you translate the program into a sequence of 0s and 1s that the computer understands. These 0s and 1s are divided into blocks that correspond to one assembly language instruction each. The size of these blocks varies from system to system, but is almost always a power of 2. Traditionally when one talks about an n-bit system (where n is some number like 8, 16, 32, or 64) every instruction is n bits long. Thus an 8-bit system would use 8-bit instructions, and a 32-bit system would use 32-bit instructions.

A typical machine language program would look something like this:

...0100010100010111010101101111111111101111010100101011100000010100...

Often instructions will be converted from binary to hexadecimal for ease of reading. The previous example translated to hexadecimal would look like this:

...45 17 56 FF EF 52 C8 14...

Machine language instructions and assembly language instructions are very strongly related; every machine-language instruction corresponds to one assembly language instruction for a given processor. For the purposes of COMP 1010 it is not necessary to understand everything about machine code, but if you would like to know more about how instructions are stored and processed by the computer consider taking the COMP 3370 course.