PHP Functional Programming Part II: OOP & Immutable Objects

immutableImmutable

In his book on Functional Programming in PHP Simon Holywell laments the lack of immutable structures in PHP, and while he suggests some hacks to insure immutability, we can make-do with some different hacks I’ll suggest. (Most of the hacks are mind-hacks–a way of thinking about data.) The idea of having a programming language where all objects are immutable (unchanging) sounds pretty awful. Not only that, it sounds impractical. Take, for example, a Boolean. It has two states; true and false. In functional programming, that means the Boolean variable is mutable, and so it’s out. However, you can have two objects that we can call, Alpha and `Alpha. Alpha is true and `Alpha is false. (The tick mark [`] is the key below the ‘esc’ key on your keyboard.) So instead of changing the state of Alpha from true to false, you change the object from Alpha to `Alpha.

Why would anyone want to do that? It has to do with the concept of referential transparency. In a concrete sense it means that if an object (reference) were replaced by its value, it would not affect the program. Consider the following:

   $val=5;
   $alpha= function() use ($val) {return $val * $val;};

can be replaced by;

   $alpha=25;

Nothing in the program will change if either $alpha variable is used. For a simple example of referential transparency, that’s no great shakes. Besides we lose the value of changing states. However, functional programming eschews the concept of changing states. To quote one functional programmer,

Do not try to change the state; that’s impossible. Instead only try to realize the truth: There is no state.

Again, this looks nuts both conceptually and in the real world. Take, for instance, a thermometer that changes from freezing (32F / 0C) to not freezing (say 50F / 10C). The temperature has changed states! How can anyone say it has not? Or a child changes states into an adult, or a caterpillar changes states to a butterfly?

According to the functional programming model, a freezing temperature is a different object than a non-freezing one; an adult is a different object than a child, and (clearly) a butterfly is a different object than a caterpillar. So, if I say that the thermometer has changed from 32° to 33°, it is not state that has changed, it is a different object. Objects can be as granular as you like, and if you think of atoms arranged to display a ruler, you can move from one atom (object) to the next atom (object) with no state involved at all.

The State Design Pattern: Wasn’t it Immutable All Along?

The State design pattern would seem to be the polar opposite of functional programming. However, if we examine it closely, we can re-conceptualize it as object swapping. Take a simple two-state example: a light going on and off. There’s a light-on object and a light-off object. The design is the same, but we think about it in different ways. Also, the individual state methods can include nothing but lambda functions or closures. Consider Figure 1. An “on” light JPG and an “off” light JPG can be considered two separate states or two immutable objects.

Figure 1: Two States or Two Immutable Objects

Figure 1: Two States or Two Immutable Objects

To make the State pattern more “immutable-like” the interface has two constants with the URLs for the two different images. To get started, Play the light switch State application and Download the files:
PlayDownload

The application uses a simple State design pattern. All requests go through the Context, which keeps track of the current state. However, this implementation fudged a bit because each time the UI calls the Client, it creates a new Context object; so no state is saved, and I had to add a statement to use the called method to set the correct state for switching the light on and off. (Note to self: Get busy on the RESTful API!) Also, I added two constants to the interface (IState) to impose an immutable property in the state implementations. Figure 2 shows the class diagram of the implementation:

Figure 2: State design pattern implementation

Figure 2: State design pattern implementation

The pattern diagram in Figure 2 provides an overview of the classes and key methods in those classes. The LightSwitch class is just an HTML document wrapped in a PHP class, an it is where a request originates in this model. The other roles you can see in the following outline:

  • Client: Get the request from the UI (LightSwitch) and using a Context instance and method, the request is sent to the Context.
  • Context: Always the most important participant in a State design pattern, it determines the current state and passes the request to it via the appropriate method based on the request.
  • IState: The State interface specifies the required methods and may include constants.
  • Concrete States: The On / Off states (IState implementations) return the requested state-as-an-object.

With that overview in mind, you can better understand all of the singular roles of the participants. (Continue to see listings and explanations.)

The UI and Client

The UI/Client initiates the request process. Each of the two radio button in the UI (LightSwitch) have values with the name of a Context method. The selected method is passed to the Client through a GET superglobal. The passed method is placed in a static variable, $method, and used with a Context instance to call the requested state.


//Client.php
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", 1);
// Autoload given function name.
function includeAll($className)
{
    include_once($className . '.php');
}
//Register
spl_autoload_register('includeAll');
//Class defined
class Client
{
    private static $context;
    private static $method;
    //client request
    public static function request()
    {
      self::$method=$_GET['lightswitch'];
      self::$context=new Context();
      echo self::$context->{self::$method}();
    } 
}
Client::request();
?>

In this case, the static property $method is a variable; so it is not immutable. It gets its value from a superglobal that changes as the request from the UI changes.

However, the variable can also be seen as choosing between two immutable choices simply expressed through the variable. I note that point not to trivialize functional programming in PHP but rather to bring attention to the fact that we may actually be dealing with immutable objects rather than variable ones more than is realized.

The Context

A key participant in the State design pattern is the Context. It defines the starting state and keeps track of the current state. When using an HTML UI form (even one encapsulated in a PHP class), each new request requires a new Client class instance and, in turn, a new Context instance. When that happens, all preserved state information is lost.

In order to rectify that, I’ve added an operation that determines which state the user wishes to move to and establishes the state to move from as the current state. In this way, the user can both turn on and off the “light.” (I know, it’s a bit of a kludge, but it’s useful for examining the mutable and immutable parts of a design pattern.)


//Context.php
class Context
{     
    //Immutable states
    private $onState;
    private $offState;
    //variable states
    private $flip;
    private $currentState;
 
    public function __construct()
    {
        $this->onState=new On($this);
        $this->offState=new Off($this);
        /**
        * With each instantiation, these next 2 statements determine whether the
        * state changes from off->on or on->off at the outset.
        * Normally, in a Context, the current state is determined when
        * a concrete class and method has been selected with a single default
        * starting state being defined in a statechart.
        */
        $this->flip = $_GET['lightswitch'];
        $this->flip=="lightOn" ? $this->currentState=$this->offState: $this->currentState=$this->onState;
    }
 
    //Call State methods--triggers
    public function lightOn()
    {
        return $this->currentState->turnOn();
    }
    public function lightOff()
    {
        return $this->currentState->turnOff();
    }
 
    //Set current state
    public function setState(IState $state)
    {
        $this->currentState=$state;
    }
 
    //Get the states
    public function getOnState() 
    {
        return $this->onState;
    }
    public function getOffState()
    {
        return $this->offState;
    }
}
?>

Given the simple two-state design of this pattern, the Context is not the busy and highly functional nerve center it is in a typical State design pattern. However, it should give you an idea of the Context’s role within the State pattern. For now, just see it as a way-station on the journey to a requested state.

The Interface and State Participants

Finally, we come to the state interface and concrete state classes. To generate a sense of immutability, the state’s returned content is frozen in two constants stored in the interface.


interface IState
{
    public function turnOn();
    public function turnOff();
 
    const ONLIGHT ="";
    const OFFLIGHT ="";
}
?>

As constants, ONLIGHT and OFFLIGHT represent immutable function returns. Given the capacity of PHP interfaces to include constants, they are available to any implementations of the IState interface. That makes them easy to use in the concrete states as shown in the following:


//On.php
class On implements IState
{
    private $context;
 
    public function __construct(Context $contextNow)
    {
        $this->context = $contextNow;
    }
 
    public function turnOn()
    {
        return null;
    }
 
    public function turnOff()
    {
        $this->context->setState($this->context->getOffState());
        return ISTATE::OFFLIGHT;
    }
}
?>
 

//Off.php
class Off implements IState
{
    private $context;
 
    public function __construct(Context $contextNow)
    {
        $this->context = $contextNow;
    }
 
    public function turnOn()
    {
        $this->context->setState($this->context->getOnState());
        return ISTATE::ONLIGHT;
    }
 
    public function turnOff()
    {
        return null;
    }
}
?>

The point in this OOP-Design Pattern example has been to point out that design patterns are full of immutable objects. Using the State pattern (since the concept of a mutable state is often the whipping boy of functional programmers), I thought it would be worthwhile to point out that returned states are actually immutable objects. You can find variables (mutable objects) in both the Client and part of the Context, but when it comes to the actual states, the returned objects are rarely mutable.

What’s the Point: FP and/or OOP

Novice PHP programmers are like a bunch of kids playing in the mud, having the time of their lives. Along comes a big brother and hands them a soccer ball gives them the rudimentary rules of the game, and they play all day in the same mud puddle only vaguely aware of the rules of fútbol. Then comes a coach and tells them that they need organization and introduces the equivalent of OOP, and so they become more efficient and effective as players but they have to pay more attention to the rules and develop futebol strategies. As some go professional, they learn the design patterns of the game involving more sophisticated plays and winning tactics. A coach from a different league comes along and tells them a better Fußball strategy is functional play.

To strongly urge anyone to abandon OO for FP runs counter to both observable and logical tenets in programming. However, by the same token, I do believe that all PHP programmers should become familiar with and practice functional programming at least some. I have no problem mixing FP with OOP, but I run the risk of being told that 1) I really don’t understand FP, 2) I really don’t understand OOP or 3) I really don’t understand programming. However, while not pure FP or design pattern programming, they both have value. (Haskell programmers have already broken ranks on the absolute necessity for immutable variables.) While you may find some of the rules in languages like Objective C (OOP on steroids) and Haskell border on the totalitarian compared to languages like PHP and C#, that can accommodate both FP and OOP, I believe it important to understand the purer forms of these other programming models. After all, PHP seems to be adaptable to all of them.

Copyright © 2014 William Sanders. All Rights Reserved.

3 Responses to “PHP Functional Programming Part II: OOP & Immutable Objects”


  • I wouldn’t even elevate OOP or FP to the level of futbol “strategies”, let alone “rules”. I would equate them to postures/forms/styles, like keeping one’s back straight or keeping one’s hips square or using the instep bone of the foot (the “sweet spot”) rather than the side of the foot or toe to strike as opposed to pass. There are no “right” answers in real-world solutions – only what scores the goal and wins the game. You could score a goal with the heel of your foot…and that would be “right” for that particular context if it worked. Software developers should use creativity and judgment in crafting unique solutions that fit the situations, rules be damned. OOP and FP are nice styles…but they can quickly be taken way too far and become dogmatic draconian doctrine that is subjective, meaningless, inefficient, and inappropriate in the real world. Keep up the great thinking and writing!

  • Hi Matt,

    OOP programming is difficult. Design Patterns are even harder. Both OOP and DP have been misunderstood, over-simplified and judging from a lot of the “examples” have little to do with what Gamma, et al (aka, Gang of Four) set out to do.

    Their goal was to offer (not force or cram) a set of patterns that show a set of relationships between objects that can be used in dealing with recurrent problems in programming; especially large and complex ones that would likely require change and updates and involving more than a single programmer. The patterns put fourth are strategies, (or even meta-strategies) for combining and relating objects used to encapsulate programming code.

    They are not proffering “right” answers, but instead they are showing how to deal with complex problems in a way that can be re-used and re-shape a computer program that has a set of complex relationships. All are based on what you call “real-world” problems, and while a good programmer can handle all sorts of programming challenges, he relies on some kind of abstracting tools to work through problems—usually mathematical ones. Much of it is learned or intuitive calculus. So, while algebra and calculus solutions may not be formulated consciously, they are there nevertheless. (In Functional Programming [esp Haskell] Lambda Calculus is more consciously present.)

    A programmer can do math by removing her shoes and counting her toes and fingers, and while not too efficient, it works. By the same token, you can solve programming problems with fairly unsophisticated routines that work. Better programmers have better solutions, either of their own making or borrowed from others—mostly the latter. The bigger the program, the greater the problem, and design patterns are for big, sophisticated problems. So, when dealing with big programming problems, I find that the strategies inherent in design patterns are helpful tools. They took me quite a while to master, but once understood, they make the path so much smoother.

    By the way, I like your blog and you’ll be getting visits from me with lots of comments!

    Kindest regards,
    Bill

  • Bill, thanks for your excellent email reply. In it, you make a solid case for the true spirit of OOP. It sounds like we agree that the industry as a whole has overexposed and badly mangled OOP. Keep up the writing!

Leave a Reply