Creating a Super Class (OOP)

_config.yml

I will make the assumption that you know what inheritance is. If you don’t know that it means, think of a mummy, daddy and a baby. The baby “inherits” characteristics the parents.

It is no less different with things in code.

class Vehicle
    def has_wheels?
        true
    end
end

class Car < Vehicle
end

c = Car.new()
c.has_wheels?    # will this return a no method error?

# No it does not!
# c.has_wheels? returns TRUE!

This is because the car inherits everything that its
parent, vehicle has.

Some important points when creating a super class - especially in ruby need to be born in mind:

  • When you override a method in a derivative class, if you need the super method to also run, you need to send super. If you don’t call super - or forget - then you might get some confusing results. You can avoid this situation by asking your super class to send a message which is overriden by the sub class.

Take the following for example:


class Vehicle
    def components
        {wheels: true}
    end
end

class Car
    def compoents
        {radio: true, steering_wheel: true}.merge(super)
    end
end


# Compare the above to the below configuration, where
# the Vehicle super class is the one calling all the shots

class Vehicle
    def components
        {wheels: true}.merge(local_components)
    end

    def local_components
    end
end

class Car

    def local_components
        {radio: true, steering_wheel: true}
    end
end

# Notice how in this situation, the Vehicle super class
# sets out the main details, and provides the ability to override
# in the child class. In other words, in the original 
# scenario, it was really easy to forget to send super
# but in the immediate case above, you are not 
# required to send super, but just the unique implementation
# the child class is meant to provide.

# in the onus is on the child to implement

Here the car knows the super has some components and it also knows the type that super’s component’s message returns. This knowledge can be eliminated by asking the super class to take care of things.

  • Supposing you have two classes: Car and Truck, and you realise that they both share common functionalities, and you decide that it’s in your best interests to abstract out a common super class - a Vehicle class for example. If that is the case: how should you go about doing so?

The most important thing to note is to start with an empty super class and to work towards putting stuff in there. If you forget, then a sub-class might send a message which is not defined in the sub-class, nor the super class. This one’s easy to sort out.

But if you work the other way around: if you start with an abstract class with stuff already in there, which you are trying to remove: what if you forget to remove something that should be in a child class? Guess what, every single class which inherits from super is going to have that property/method. And if that property/method does not apply to that child class, then that’s inviting trouble. You’ll have to check for reliability rather than being able to blindly trust your child classes. And that’s just bad code. Child classes should be images of their parent classes, and not some quasi-hybrid mongrel.

  • Lastly, any method sent in the super class must also be implemented in the super class. Do not rely on the implicit receiver being the child class.

class Vehicle
    def initialize()
        can_move
    end
end

class Car < Vehicle
    def can_move
        true
    end
end

# notice here the can move method is implemented in 
# the child class but is not implemented at all in the super
# class?

# if you accidentally forget to include the can_move
# method in the Car class, or any other child class of
# Vehicle, then you might be confused.

# A better situation rather than no implementation at all would be this:

class Vehicle
    def initialize()
        can_move
    end

    def can_move
        raise NotImplementedError, "subclass did not define #create"
    end
end

# Now in this situation, if somebody forgets to impelement
# can_move in the child class, you'll immediately realise what is going on

Hope this helps.

Written on April 29, 2017