Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

1.2.4. Types of Programming Language

GitHub last commit

Programming languages follow different paradigms, depending on the philosophy of the community and decisions by their creators.

A programming paradigm is the style or model in which a programming language uses.

Different languages utilise different paradigms, or can even support multiple, becoming the programmer’s choice as to which to use. Some paradigms will be more useful in solving a specific problem than another, therefore it should be decided which to

Warning

Function and procedure are used mostly interchangeably by me within this chapter. Functions return a value, procedures do not. This is an important difference that you should take note of.

Procedural languages

TLDR:

  • Programmer specifies steps needed to complete the program
  • Statements are grouped together in procedures and functions
  • Variables can have varying scope (local/global)
  • Logic is expressed in chains of imperative procedure/functioncal calls

Procedural is the easiest and simplest paradigm, involving a chain of instructions that are executed sequentially. The execution of the program goes from top to bottom, where most functionality is contained within defined, imperative functions.
Procedural languages are the stereotypical programming languages, making use of the typical concepts of data structures, sequence, selection, iteration, functions, etc.
Variables in procedural languages are defined to have either a local or global scope.

  • Local scope is where the variable is obly available within the function
  • Global scope is where the variable is accessible throughout the program and across all functions

Object-Oriented languages

TLDR:

  • Data is grouped into objects
  • Objects contain methods and attributes which belong to their instance
  • Instances are self contained
  • Objects can be reused and inherited across the codebase
  • Logic is expressed as the relationship between objects

Note

For the exam, you will need to be familiar with OOP concepts, and how they work in OCR Reference Language

The concept of OOP is to produce reusable, self contained, or encapsulated, objects that interact with each other to form logic and represent data. OOP is frequently used in the modern day due to the self contained nature of different structures. Thus has the benefit of making debugging easy, while also simplifying the relationships between data.

OOP utilises access modifiers to control who or what is able to access the data stored within an object.
The private keyword means that the method or attribute can only be called/accessed from itself.
The public keyword means that other objects can access/call attributes/methods within the class.

For example, consider the following class:

public class Pet {
    public String name; 
    public Float hunger;

    public Pet(String name) {
        this.name = name + " " + "Ayana";
        this.hunger = 10.0;
    }

    public String getName() {
        return this.name;
    }

    public void feed() {
        this.hunger = this.hunger - 1.0F;
    }
    private void eat(String name) {
        this.hunger = this.hunger + 1.0F;
    }
}

This is an example of a class, representing a simple pet. The pet has a name that is set when a new pet is created. The name is a property of the class, or an attribute.
The pet also has a method which manipulates the data of the instance of Pet.
The pet also has a private method that only the pet can access.

This pet is encapsulated, where data is self contained, data that relates to the pet is an attribute of the pet, and the data of the pet can be manipulated by using provided publicly accessible methods.

Encapsulation is defined as packaging behaviour and data within a class, and access to a class's data is controlled through **getter** and **setter** methods.

Getters and setters return or set private attributes. 

Other objects can inherit traits and attributes from the parent class.

Consider the following child class:

public class Dog inherits Pet {
    public Boolean tailWagging;
    public Dog() {
        this.tailWagging = true;
    }

    public void toggleTailWag() {
        this.tailWagging = !this.tailWagging;
        this.hunger = this.hunger - 1.0;
    }

}

The above class Doginherits the attributes and methods from Pet, even though they aren’t explicitly declared within Dog. For example, I didn’t declare float hunger; at the top of Dog, yet it’s still accessible within toggleTailWag().

Taking this into account, you can also call the .feed() methods on the Dog class, as it is also inherited from Pet.

Caution

Private methods are not inherited, so you cannot call .eat() from any subclasses.

However, what if you wanted to inherit from another class, but you needed to modify a specific method’s behaviour?
This can be achieved using polymorphism.

Consider the new mechanical dog that doesn’t need to eat.

public class RoboDog extends Pet {
    private Boolean tailWagging;
    public RoboDog() {
        this.tailWagging = true;
    }

    @Override
    public void feed() {
        throw new UnsupportedOperationException("It's a robot, it isn't hungy!");
    }
    
    public void toggleTailWag() {
        this.tailWagging = !this.tailWagging;
        this.hunger = this.hunger - 1.0;
    }

}

Since robot dogs cannot eat anything, but are still pets, we need to alter the inherited feed method to throw an error when we try to feed the robot dog.
In Java, this is notated with the @Override decorator (don’t worry about this), telling the compiler that when we call .feed() on an instance of the subclass RoboDog, we need to throw an error. If we didn’t do this, the default .feed() from the parent Dog class would be used, which is not what we want.

This concept of modifying behaviour based on their subclass is referred to as polymorphism.

In short, these child classes (referred to by the exam board as subclasses), encapsulate data and behaviour using attributes and methods, which can then be inherited from the parent class (super class), allowing behaviours to be modified through polymorphism.

Assembly languages

  • Low level
  • 1-1 conversion to machine code
  • Specific to processor architecture
  • Uses addresses to reference data

Assembly language is a low level family of programming languages that give you direct control over the machine code being executed by the CPU. You have direct control over what is stored and moved within each register.

Assembly revolves around the concepts of op-codes and operands, which map directly to machine code.

Consider the following LMC assembly:

LDA #50
ADD #1
OUT

In the first line, the instruction is LDA #50, where the op-code is LDA and the operand is #50. The op-code deterines what the CPU should do with the data provided (the operand).
The above program will load 50 into the accumulator and add 1 to it, then outputting it.

Since assembly has almost no abstractions over the raw machine code, things such as data types don’t exist and control flow is limited. Instead, data is read and interpreted as raw bytes, and if statements are limited to jumping to certain addresses based on conditions.

Little Man Computer Instruction Set

Caution

You need to know the instructions in LMC and how to write programs with LMC assembly.

The LMC Instruction Set is a simplified form of Assembly, where you manipulate

Declarative languages

Declarative lanugages are not in the specification, however you will be familiar with them. These are languages that describe what needs to be done, rather than how it should be done, essentially providing what the final result should be. SQL and HTML are considered declarative languages, as they define how the output from the database, or how the website should look.

Functional languages

Functional languages are a type of declarative language. This involves a series of declarations, where functions are continually piped into each other in order to form logic.

See Haskell or Nix for further reading, as these are 2 commmon functional languages.

Addressing Memory

There are several ways of addressing memory with assembly.

ModeInterpretation of the operand
ImmediateThe value is used literally, and is the actual value used in the instruction
DirectThe value contains the address of the value which can be read for the value we want.
IndirectThe value contains the address of a pointer which is then dereferenced for the value we will use
IndexedThe value is added to the index register and then we read from the address inside of the index register