When You Can't Misuse the Immutable

| 4 Comments

There are two well-known ways to make things impossible to misuse. One way is to remove all but the simplest and safest features. You could call this the Haskell Report approach, where the original language avoided most security holes by forbidding user input.

(Yes, I know that wasn't the point of the Haskell Report. Fortunately, most of the really good Haskell fans have good senses of humor.)

The other approach is less popular. It allows people to perform complex tasks—even dangerous ones—but it prefers to make them safe by making the safe things easy to do correctly. You could call this the CUC approach, where a language designer would never say "Hey, let's provide a builtin where you can load arbitrary data from the Internet and automatically populate values into your single global variable namespace! Including $is_admin and $is_verified and $discount!"

It's easy to believe that the next decade of professional programming will deal with the tension between functional programming and just-get-something-done-now programming. (Objects have won, at least enough. Genericity has won, at least enough. JSON and REST have won, at least enough to wash the taste of SOAP out of our mouths.) Popular belief may claim that functional programming is interesting because it can provide cheap parallelism with the flip of a switch. Popular belief is wrong, but popular belief is popular.

The interesting parts of functional programming aren't the silly utopianisms that "Learn Haskell and your programs will automagically scale to 256 cores and beyond!" but the way we can steal useful features of functional languages as patterns for real programs that aren't solely pure, functional, typeful, lazy, and referentially transparent.

To call back to the Haskell Report reference, we handle user input all the time, but we can be safer and saner about it.

Many of your programs will benefit from pervasive laziness. (Most of mine do.) Many of your programs will benefit from reducing side effects, especially global side effects. It's not just Haskell; you're probably already using dependency injection too.

Another great feature of functional programming is immutability, where things can't change after you've created them.

This is in truth a great feature of any API. I reviewed some code from a slightly less experienced developer a couple of hours ago. He's competent with Perl, though his code has a C accent that comes from electrical engineering school. Good C programmers handle errors. Robust C code spends probably at least 30% of its lines of code on error handling. This code was no exception.

The bad news is that C has few possibilities for abstraction. In particular, C doesn't make it easy to create immutable data structures. The good news is that Perl does.

The biggest suggestion I made was to consider a pattern I've discovered while using Moose pervasively: perform all of your verification and validation at the point of object construction and resist the temptation to make mutable objects. This pattern obviously needs a catchier name.

The benefit to your API is that if you can create an object, the object is always in an consistent state. Any validation errors get reported from the point of the code that attempts to create the object. This keeps the scope of the error reporting to the point at which it matters the most (at least to the constructor API). This reduces the possibility that someone will manipulate the object and make it invalid.

You have to go to great lengths to misuse such an object (or such an API) because you have to bypass its interface altogether, if the interface forbids mutation.

You get to remove a lot of error checking code because within the API you can assume that the object is always in a valid state. (Anyone who's violated that contract gets to keep the broken pieces.)

This pattern would work just as well in C or Python or PHP or Java. Nothing is specific to Haskell or Perl that makes this pattern impossible in other languages. It works better in Haskell than in Perl because the language supports it much like it works better in Perl than in C because the language somewhat supports it and great libraries make it easier.

The technique works, if you're diligent about figuring out what changes from what stays the same at each level of your design. That may mean some classes or data structures need to break into smaller pieces. That's not always easy, nor always simple. It's often not obvious.

The benefit, though, is what the functional programmers have been saying all along. Reducing mutable state can help us write better code and less code and code that's easier to use correctly and much, much more difficult to use incorrectly.

(One of the reasons I use Perl 5 so much is that Moose makes it really easy to make my classes immutable. Any object system worth using should do the same.)

4 Comments

The more I try to design my Perl programs well the more my programs become as if coded in a functional language. I wonder where it goes. Maybe there is a need to support side effect free programming in Perl(6) (http://perlalchemy.blogspot.com/2012/04/if-all-of-your-state-is-on-stack-then.html)?

One more thought - if you treat functions as first class objects then what immutability means for them?

I agree, though I recently have had a few thoughts around this. should all of my attributes be read only? even my optional ones? I've started making optional attributes on the Data Transfer Objects read-write/setonce but I've debated whether I should do that.

One of the reasons I decided to do that is moose doesn't treat passing undef to the constructor the same as unset, and so sometimes it's easier to handle optional attributes, that come from user input, individually. There's also the whole, should I specify this ArrayRef attribute all upfront?

That led me to a question as to how can I lock the instance later. Which hasn't been answered (
http://stackoverflow.com/questions/10778148/make-object-instance-immutable )

I have that pattern. I skim past it in my OSCON talk. Definitely needs a better name though. Hell, it needs a name.

Modern Perl: The Book

cover image for Modern Perl: the book

The best Perl Programmers read Modern Perl: The Book.

sponsored by the How to Make a Smoothie guide

Categories

Pages

About this Entry

This page contains a single entry by chromatic published on May 31, 2012 2:02 PM.

Why I Use Perl: Reliability was the previous entry in this blog.

From Alchemy to Science in Programming is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.


Powered by the Perl programming language

what is programming?