Skip to content
William Wood edited this page Apr 12, 2023 · 2 revisions

Objects and Classes

In programming we often use the concept of an "object". This is similar to what you might consider to be an object in the real world. For example, a bicycle or a dog. Each of these objects has "state" and "behaviour". For example, a bicycle has a state comprised of its current speed and gear, and has behaviour in the form of "speed up", "brake", "change gear".

Objects in programming are the same. They have a state comprised of variables, and behaviours implemented as functions/methods. You might also notice that whilst there are many bikes in the world, they are essentially copies of the same thing. That is they are of the same type. We call this type a "class", and each individual bike is an "instance" of the bike class.

In JISA we use objects to represent each individual instrument that you are connected to. This makes sense if you think about it because each instrument is just an object in the real world too. They have a state and behaviours. For example, an SMU has a state comprised of many things including: how much voltage it's currently applying, whether it is on or off, its measurement range etc. As well as behaviours such as: turn on, turn off, change voltage applied, change measurement range, measure voltage, measure current etc.

Objects

As explained in the introduction, an object is something that has "state" and "behaviour". Let's take a new example, this time an office chair with wheels and adjustable height.

The state of an office chair can be described as its:

  • Current position (x and y co-ordinates)
  • Current orientation (angle)
  • Current height

And its behaviours are:

  • Move (change position)
  • Rotate (change orientation)
  • Adjust height (change height)

In programming, if this chair was represented as an object called chair then its state would be described using variables and the behaviours would be implemented as functions like so:

// Make chair move to (x=30, y=50)
chair.moveTo(30, 50)

// Change the height of the chair to be 20 cm
chair.adjustHeight(20)

// Rotate the chair by 45 degrees
chair.rotate(45)

we could then check on its current state by accessing the relevant variables too:

var xPosition   = chair.x
var yPosition   = chair.y
var orientation = chair.orientation
var height      = chair.height

println("Current state:")
println("X           = $xPosition")
println("Y           = $yPosition")
println("Orientation = $orientation")
println("Height      = $height")

However, it is often considered to be a bad idea to let people access these state variables directly like we just did. For instance, let's say the maximum height we could set the chair to be is 50 cm. If the height variable is freely accessible like this, then anyone can set it to be whatever they like, even if the value is not possible:

chair.height = 100 // Too high, the chair would break!

For this reason, we make the variables "private" so that they can only be accessed and changed by the objects own functions, allowing you to put checks in place so that nothing stupid is done. This means that we now need to create functions to "get" each value instead:

var xPosition   = chair.getX()
var yPosition   = chair.getY()
var orientation = chair.getOrientation()
var height      = chair.getHeight()

chair.height = 100 // This will now give an error as we cannot access height directly

// Instead we need to use the function:
char.setHeight(100)

// This function will check the value before setting it
// to make sure it won't break the chair. That is it will
// see that 100 is too high, and stick to 50 instead.

Classes

What variables and functions an object has is defined by its type, called "class". If you think about it, all bicycles have the same basic behaviours, as do all office chairs. Each individual bike or chair is therefore simply an "instance" of a Bicycle or OfficeChair class.

Essentially then, a class is the blue-prints of an object. It is in the class definition where we specify what variables and functions objects of that type have. For instance, if we created the OfficeChair class in Java it would look like:

public class OfficeChair {

  private int x;
  private int y;
  private int orientation;
  private int height;

  public void moveTo(int x, int y) {

    // Change internal variables x and y to match the newly given values
    this.x = x;
    this.y = y;

  }

  public void rotate(int degrees) {

    // Increase orientation by the given number of degrees
    this.orientation += degrees;

  }

  public void adjustHeight(int height) {

    // Check that the new height isn't too high!
    if (height > 50) {
      this.height = 50;
    } else {
      this.height = height;
    }

  }

  public int getX() {
    return this.x;
  }

  public int getY() {
    return this.y;
  }

  public int getOrientation() {
    return this.orientation;
  }

  public int getHeight() {
    return this.height;
  }

}

The words private and public refer to whether the variable/function is only accessible from inside the class (private) or can be access from outside (public).

Here we have defined that objects of class OfficeChair shall have three integer variables: x, y, orientation and height that are only accessible from inside the class and 7 functions: moveTo, rotate, adjustHeight, getX, getY, getOrientation, getHeight which are all publicly accessible from outside the class.

This means that each time we create an object of type OfficeChair, it will get its own copy of all these variables and functions. Inside the class the word this means "this current instance". So when we write this.x it means "the copy of x that is inside the object this function is being called from".

Creating Objects

Now that we've defined the OfficeChair class, we can create an OfficeChair object with its own copy of each variable and function. In Java, you create an object by using the new keyword like so:

new OfficeChair();

You can then assign it to a varible (with its type being the class):

OfficeChair chair = new OfficeChair();

So now chair is an OfficeChair object:

chair.adjustHeight(30);
chair.rotate(23);

System.out.printf("X-Position = %d\n", chair.getX());

In Kotlin and Python, objects are created much the same way, but you do not write new like you do in Java:

Kotlin

val chair = OfficeChair()

chair.adjustHeight(30)
chair.rotate(23)

println("X-Position = ${ chair.getX() }")

Python

chair = OfficeChair()

chair.adjustHeight(30)
char.rotate(23)

print("X-Position = %d" % chair.getX())

Constructors

When we create an object, as we have seen, we invoke its name, ie:

new OfficeChair();

This is called the "constructor" of the object as what it does is... well... construct a new object. However, you might have noticed the brackets at the end. Some classes require you to provide arguments in these brackets when creating an object. Our example of OfficeChair required none, hence there being nothing between them.

However, you can probably imagine that some types of objects that need to be given some information when created. For example, we would probably need to tell an OfficeChair what its initial position, orientation and height is:

new OfficeChair(x, y, orientation, height);

// for example x=20, y=30, o=90, h=15:
new OfficeChair(20, 30, 90, 15);

This is important for connecting to instruments in JISA as when you create an object to represent your instrument, you will often have to also tell it how and where that instrument is connected to your computer.

Clone this wiki locally