Class, Instance, Object, Interface, Trait

“We read to know we’re not alone.” ~ William Nicholson, Shadowlands

What is the difference between a:

  • Instance
  • Object
  • Interface
  • Trait
  • Types (Bonus for TypeScript)

Ask anyone this question you will get a range of responses from knowing none, some or all. Ideally we all have a common understanding what these mean because it matters.

Why it Matters

Many languages including PHP, TypeScript and JavaScript are built on these concepts; they are core concepts of Object Oriented Programming. It matters if you want to be able to use language features as well as outside libraries that depend on these ideas.

It also matters because when you write code, another person who reviews the code or reads it a later date should understand it. So let’s dive in.

Class

A class is a template or a blueprint. It says what properties and what functionality something has.

For example, every so often we have a personal appraisal and it involves filling in a document. The general document that’s sent around to everyone is a class.

In code this could be:

class AppraisalForm {
protected string $name;
function __construct(string $name) {
$this->name = $name;
}

function save()
{
...
}
}

This class AppraisalForm has an attribute $name and the functionality save

Object

Submitting the appraisal form is more than just sending back the template document, you actually need to fill it in. When you fill it in it’s an object (your appraisal form). An object is the concrete thing you built from the template.

new AppraisalForm('MyName');

Instance

Instances are virtual copies. You send a copy by email, copy by slack and you print the same form. You fill the form in once and then make copies of that same form.

$myForm = new AppraisalForm('MyName');$sendBySlack = $myForm;
$sendByEmail = $myForm;
$print = $myForm;

Objects vs Instances in Practice

This is a view from Structural Programming. There’s no real significant difference that should consume too much of your time. There might be some fancy language that some people might take up a lot of spaces to write about, but at the end of the day, as far as a coder, developer, programmer, architect, is concerned, an instance of a class and an object mean the same thing and can often be used interchangeably. I have never met anyone in my career that would be picky and spend a half-hour trying to point out the differences because there’s really none. Time can be better spent on other development efforts.

What is the difference between an Instance and an Object?

The difference between the two doesn’t matter much for most modern languages, notable exceptions are Swift, C, C++, C#

InstanceOf Checks

In many languages and libraries a variant instanceOf is available for use. It checks if an object / instance follows a given template.

For example from php unit:

$myForm = new AppraisalForm('MyName');
$this->assertInstanceOf(AppraisalForm::class, $myForm); // true
$myForm2 = 'MyName';
$this->assertInstanceOf(AppraisalForm::class, $myForm2); // false
// For null checks use:
$this->assertNotNull($myForm); // true

Remember that new is always used to create an object from a class.

$myForm = new AppraisalForm('MyName');// error not a class but an instance
$this->assertInstanceOf(new AppraisalForm(), $myForm);

Interface

So now we have class, object, instance. What about interface?

An Interface is a contract that guarantees that a class has certain minimal functionality (by extension the objects / instances).

interface Form {
function save();
}
class AppraisalForm implements Form {
protected string $name;
function __construct(string $name) {
$this->name = $name;
}
function save() {
...
}
}

Why would we do this, we already know it’s an AppraisalForm.

Interfaces allow you to write abstractions or more generic code.

Let’s add another type of form, an anonymous SurveryForm

class SurveryForm implements Form {
function __construct() {
}
function save() {
...
}
}

Then we can write the following function to handle forms:

$forms = array(new SurveryForm(), new AppraisalForm('MyName'));foreach ($forms as $form) {
$form->save(); // works
vardump($form->name); // error
}

The interface Form guarantees that each instance of Form has a save functionality, nothing more and nothing less.

Abstract Classes

Interfaces are useful to guarantee that a functionality is present. They do not guarantee that the function works in any particular way. Also interfaces in many languages do not guarantee that certain attributes are present. For this you would use an abstract class (a template for templates).

As a general rule of thumb:

  1. Do you need a function to behave in a particular way? If yes, use an Abstract Class
  2. Do you need a certain function to be present, nothing more or less? If yes, use an Interface
  3. If none of the above, don’t use anything

Trait

Classes, objects, instances, interfaces and abstract classes are all classic Object Oriented Programming. Most of the time these are enough to do what you need.

However sometimes you have certain functionality that is needed in many places and it doesn’t make sense to use an interface or an abstract class.

For example:

In the different forms it would be useful to log all the changes. So we create an abstract class:

interface Form {
function save();
}
interface Logging {
function log();
}
abstract class AbstractForm implements Form, Logging {
function log() {
...
}
}
class AppraisalForm extends AbstractForm {
protected string $name;
function __construct(string $name) {
$this->name = $name;
}
function save() {
...
}
}

AppraisalForm inherits a function log, which is great so mission accomplished right? Well not really because in any larger system logging is used everywhere it doesn’t belong to any class in particular.

If we create a new class:

abstract class Person {
...
}
class Employee extends Person {
...
}

It doesn’t make sense to extend AbstractForm (an employee is not a form) so an abstract class becomes too much work (it could be done by having an abstract class above both of these). But an interface cannot guarantee that the logging function will work the same everywhere, just that it exists. Now what? Solving this problem without too much work is what a Trait is for.

Traits are portable pieces of code that can be mixed (added) into a class.

For example

trait Logging {
function log(string $message) {
...
}
}
abstract class Person {
...
}
class Employee extends Person {
use Logging;
...
}
interface Form {
function save();
}
class AppraisalForm implements Form {
use Logging;
...
}
class SurveryForm implements Form {
use Logging;
...
}

In PHP, the use keyword inside a class tells the interpretator that you are mixing in a certain Trait. That trait has some functionality that you can use. Since the function log is written in the trait Logging it will be run the same way in each class (Employee, AppraisalForm and SurveryForm).

Traits are not strictly necessary and should be used sparingly, many times a proper hierarchy with abstract classes and interfaces can achieve the same thing.

The trait Logging could also be rewritten to an abstract class AbstractLoggable which both AbstractForm (from earlier) and Person would inherit from. The problem is more about understanding what the code means. It’s a lot easier to explain what the trait Logging is adding to a given class than why you need a complicated abstract class structure that says that a Person and a Form are the same thing. The more functionality you add the worse the problem becomes.

Types

Bonus section for TypeScript. In TypeScript you are free to use classes, interfaces, etc. There is also an alternative.

{name: 'MyName', email: 'MyEmail'}

The code snippet is valid object but it’s not an instance of any class.

Which means that interface doesn’t apply here since it guarantees things about classes.

In TypeScript you can dynamically assign this object a type which guarantees that it has a certain structure.

type AppraisalForm = {
name: string
}

This means that even though the object has two attributes you can guarantee that at least the name attribute is present as is a string.

While TypeScript is pretty loose about interfaces and types the main difference is this:

  • Types guarantee that an object has a certain structure

Types can also be used to guarantee that certain functions are present:

{name: 'MyName', send: () => {console.log('Sent')} }type AppraisalForm = {
name: string,
send: () => {}
}

Types cannot guarantee that a function behaves in a certain way.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Tony Reijm

Guiding development teams with both experience and data. Passionate about people, technology and complex problems.