A PHP maybe monad

I believe that the single most frequent bug in almost all applications is the Null-Reference-Exception bug, followed by the Unhandled-Exception bug. And I thing that both of these problems have their origin in the way we write code. Take for instance the following piece of code:

echo $x->GetType()->GetName();

This simple code is evil! What happens if not “Type” object is found? There are two usual approaches. Either GetType will return a null value or it will throw an exception.

In the first case, the correct code is boring:

$type = $x->GetType();
echo !is_null($type) ? ‘Untyped’ : $type->GetName();

In the latter one, the correct code is even more boring:

try {
    echo $x->GetType()->GetName();
}
catch (NotFoundException $ex){
    echo ‘Untyped’;

Because all three syntaxes are acceptable by the language, we tend to use the first one because it is simpler, even though is error prone!

There is an answer coming from the functional programming world that can change that. It’s called “monads” and can enforce some discipline in out code. Here I will try to handle the Null-Reference-Exception problem by using an immitation of the Maybe monad for PHP.

Let’s say that the GetType method returns null if no “Type” is found. The Null-Reference-Exception problem is caused by the fact that GetType returns either some Type object or a null. What if we changed that? Let’s make the GetType method always return an object of a specially crafted class called Maybe:

class Maybe {
    private $object;
    public function __construct($object=null){
        $this->object = $object;
    }
    public function IsNull(){
        return is_null($this->object);
    }
    public function Select( $function ){
        if (is_null($this->object))
            return $this;
        else
            return new Maybe($function($this->object));
    }
    public function GetValueOr($default){
        if (is_null($this->object))
            return $default;
        else
     
            return $this->object;
    }

Have you noticed that there is no exposure of the object without checking for null first?

Now let’s say that GetType returns a Maybe object. Our final code will become like this:

echo $x->GetType()
  ->
Select( function($x){ return $x->GetName(); })
  ->GetValueOr( ‘Untyped’ );

It’s a litte bit long, but this is because PHP is bavard when it comes to anonymous functions. Yet, the cool thing is that there is no way to write something shorter that could hide a Null-Reference-Exception problem.

PHP is an untyped language, so compile-time type checking is not an option. All bugs cannot be seen until run-time. Still, with the use of this pattern, we made the error prone code to produce an error any time it is called, and not only some of the times. This, in my opinion, is a big advantage.

6 thoughts on “A PHP maybe monad

  1. Have you looked into Null Objects? Nice syntax; obvious to read and understand; no exceptions.

    $x->getType()->getName();

    function getType() {
    if ($this->_type) {
    return $this->_type;
    } else {
    return new NullType();
    }
    }

    class NullType {
    function getName() {
    return “Untyped”;
    }
    }

Leave a reply to Justin Cancel reply