This post will use Java (again) as the language of choice, but the concepts presented are relevant for most object-oriented languages.
A classic tutorial for understanding concepts of object oriented programming is the class Animal
which is subclassed into Cat
, Dog
and Panda
. This example usually gives Animal
as an abstract class with an abstract method called makeNoise()
, which all subclasses must implement.
Here is a slightly different example:
abstract class Animal { ... abstract boolean isAlive(); ... }
Each subclass must implement the isAlive()
method. The Cat’s method indicates whether the cat has spent its 9 lives, the dog’s checks if its tail is wagging, etc. But what about the subclass Zombie
? Zombie objects will always return false for isAlive()
, which makes the implementation of the method unnecessary. Instead of writing a method that simply returns false all the time the language could be changed in the following way:
class Zombie extends Animal { ... false isAlive(); ... }
That results in less code and makes it clear that this method is of no interest in this particular subclass.
Expanding on this idea, switch
statements, which control a method’s response for parameters, could be made with a construct that is similar to overloading:
public class SomeHandler { enum State { STATE_OK, STATE_FILE_NOT_FOUND, STATE_NO_DATA_CONNECTION, STATE_GPS_INACTIVE, } true handleState(STATE_OK) { // Do something when the parameter is STATE_OK, // but always return true } boolean handleState(STATE_FILE_NOT_FOUND) { // Do something when the parameter is STATE_FILE_NOT_FOUND, // notice that this time the method isn't declared to return a constant value, // therefore it must return a boolean value by itself } false handleState(State state) { // Do something when the parameter is neither STATE_OK nor STATE_FILE_NOT_FOUND, // but always return false } }
Similar to a switch
statement, the first matching signature will cause that method to run and return either its pre-declared value or the value that it calculates during its run. The default
case being the last method, which must be declared or otherwise a compilation error will occur. Readers familiar with Prolog will find this idea very familiar.
In the above example, if the “default
” state should always return false, the following handler, which is much simpler, could be used:
public class SomeHandler { ... false handleState(State); ... }
This way if the method is overloaded with another method signature (such as boolean handleState(String)
), the runtime environment would still know which of the overloaded methods to call depending on the parameters.
While logic programming never caught in the industry, I believe it has a lot to offer. As an aside, if you never touched Prolog in your life and you’re interested in trying something completely different from what you’re used to as a programmer, now would be a good time to find a good introduction to it.