Home > Programming > Zen and the art of statefulness

Zen and the art of statefulness

The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said “Master, I have heard that objects are a very good thing – is this true?” Qc Na looked pityingly at his student and replied, “Foolish pupil – objects are merely a poor man’s closures.”

Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire “Lambda: The Ultimate…” series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.

On his next walk with Qc Na, Anton attempted to impress his master by saying “Master, I have diligently studied the matter, and now understand that objects are truly a poor man’s closures.” Qc Na responded by hitting Anton with his stick, saying “When will you learn? Closures are a poor man’s object.” At that moment, Anton became enlightened.

Anton van Straaten

When I first read the above koan some time ago, I didn’t really understand it. I had a very basic idea of closures, but at the time they were just a syntactic oddity to me – something you could do a few cool things with, but not particularly useful. Since then I’ve worked through quite a bit of Structure and Interpretation of Computer Programs and delved into functional programming in JavaScript, which has given me a much deeper understanding of closures. On the other side of the divide, I’ve been doing a lot of Ruby programming, which has helped me grok objects a lot better. I now feel like I can begin to comprehend what the quote was getting at.

My moment of enlightenment came today while reading Test-Driven JavaScript Development and looking at the code for a JavaScript strftime function (abbreviated here for brevity):

Date.prototype.strftime = (function () {
  function strftime(format) {
    var date = this;

    return (format + "").replace(/%([a-zA-Z])/g, function (m, f) {
      //format date based on Date.formats
    });
  }

  // Internal helper
  function zeroPad(num) {
    return (+num < 10 ? "0" : "") + num;
  }

  Date.formats = {
    // Formatting methods
    d: function (date) {
      return zeroPad(date.getDate());
    },
    //...
    //various other format methods
    //...

    // Format shorthands
    F: "%Y-%m-%d",
    D: "%m/%d/%y"
  };

  return strftime;
}());

The above code uses an IIFE (Immediately-invoked function expression) to produce a function with additional data (if Date.formats was instead declared as a local variable, this would be a better example). If it doesn’t make sense, I thoroughly recommend Ben Alman’s post on IFFEs for an overview of the technique. The code executes, and returns a function. The important thing is that one function is used to define another function and its context.

In Ruby, when you define a class, the class definition is executed as Ruby code, unlike in Java, for example, where a class definition is just a syntactic construct read at compile-time, but not executed in the way other Java code is. A Ruby class definition is read at run-time, and builds up a new class as it is interpreted.

In a lot of ways, Ruby class definitions and JavaScript function-defining functions are equivalent. I’ll give you a little example to illustrate:

zen.js

var Cat = function () {
  var age = 1;

  function catYears() {
    return age * 7;
  }

  function birthday() {
    age++;
  }

  return {
    catYears: catYears,
    birthday: birthday
  }
};

var powpow = Cat();
var shorty = Cat();

//yo shorty, it's your birthday:
shorty.birthday();

alert(powpow.catYears()); // => 7
alert(shorty.catYears()); // => 14

zen.rb

class Cat
  def initialize
    @age = 1
  end

  def cat_years
    @age * 7
  end

  def birthday
    @age += 1
  end
end

powpow = Cat.new
shorty = Cat.new

#yo shorty, it's your birthday:
shorty.birthday

puts powpow.cat_years # => 7
puts shorty.cat_years # => 14

Strictly speaking, in zen.js I’m returning an object, but the private data and methods of that object are saved in a closure. So, zen.js stores its state in a closure, while zen.rb stores its state in an object. Every time Cat() is called in zen.js, a new closure is created with a unique age. Every time Cat.new is called in zen.rb, a new object is created with a unique @age. (These two examples aren’t strictly equivalent – each cat in zen.js gets a new copy of the functions, whereas in zen.rb they share the same methods. It’s possible to make the JavaScript version function more like a Ruby class definition, but it takes a bit more code.)

Of course, there’s a lot you can do with JavaScript closures that you can’t do with Ruby objects. And there’s a lot you can do with Ruby objects that can’t be emulated using JavaScript closures. Any time you decide that one is better than the other, just imagine Qc Na hitting you with his stick.

Further reading

  1. February 12th, 2011 at 16:06 | #1

    Thanks for these nice biscuits. Question: How is it that the strftime() example is related to state? There don’t seem to be any internal state-full vars such that one would make use of a persisting instance. Also, can you explain what the self-instantiation does that wouldn’t occur if it were function(){…} instead of (function(){…})() ?

    Perhaps enlightenment will come for me tomorrow.

  2. February 12th, 2011 at 16:19 | #2

    @Michael Richardson Thanks. You’re right about the strftime() example – I meant to add “(if Date.formats was instead declared as a local variable, this would be a better example)” which I’ve done now. If instead of Date.formats = it said var formats = it would have been a better – then formats would have been held in the function’s closure. I mainly included that function because it was what set me off thinking about all this, but it’s not perfect for illustrative purposes!

    If it were function(){} then Date.strftime() would call the function that returns the inner strftime. If you wanted to actually call strftime you’d have to write Date.strftime()(). Immediately invoking the anonymous function causes it to execute at that point in the code and return the inner function, which is what is assigned to Date.strftime. Hope that all makes sense!

  3. February 13th, 2011 at 14:05 | #3

    This does make sense, yes. Kind of! Wall. Screen. Ceiling. Beginner’s mind… Still squinting at all this to see the relevance to statefulness. …. Okay. Reading Sensei Alman’s piece about it, now I see what you’re saying about a local var: It would give you the medium with which to keep Date.strftime() as a stateful (alive, subject to amending, incrementing, etc) component into which you could, say, add a new format provided by a user.

  4. February 13th, 2011 at 23:32 | #4

    @Michael Richardson Exactly. It’s really not a very good example – I just didn’t like the idea of saying “this certain bit of code made me suddenly understand” without actually quoting the code.

    If I was going to rewrite the code sample, I could add a add_format function that could add a new format to the formats object. Then you’d have your mutable state :)

  5. December 13th, 2012 at 21:11 | #5

    I am in fact happy to glance at this blog posts which contains lots of useful data, thanks for providing these data.

    Feel free to visit my web-site – [iphone repair specialist](http://Iphonerepairkl.Webs.com/ ” iphone repair specialist”)

  6. gamanegumanews.com
    December 31st, 2012 at 15:31 | #6

    “Skilldrick Zen and the art of statefulness” was in fact a terrific article, can not wait to read more of your blogs. Time to spend some time on the web hehe. Thank you ,Deandre

  7. June 7th, 2013 at 16:26 | #7

    Hello, just wanted to tell you, I enjoyed this blog post. It was funny. Keep on posting!

  8. July 4th, 2013 at 09:42 | #8

    You made some good points there. I looked on the internet to learn more about the issue and found most individuals will go along with your views on this website.

  9. July 26th, 2013 at 17:37 | #9

    Until now – now there are Weber Performance Grills that offer the best of both grilling worlds.

    You will find them so much in varying sizes that they come in the range from very small and light weight to close to home sized. When looking for gas grills on sale, the best brands to choose from are Weber, Char-Broil, Brinkmann, and Coleman.

    Stop by my page: [top rated gas grills](http://www.

    picowiki.com/josh7854/index.php/Portable Gas Grills- Weber Spirit Liquid Propane Gas Grill “top rated gas grills”)

  10. July 31st, 2013 at 04:48 | #10

    I know this if off topic but I’m looking into starting my own weblog and was wondering what all is required to get set up? I’m assuming having a blog like yours would cost a pretty penny? I’m not very internet savvy so I’m not 100% certain. Any recommendations or advice would be greatly appreciated.

    Thanks

  11. September 9th, 2013 at 03:03 | #11

    Hello everyone, it’s my first pay a quick visit at this web site, and piece of writing is really fruitful designed for me, keep up posting such content.

  12. September 12th, 2013 at 03:58 | #12

    Hi there I am so glad I found your site, I really found you by accident, while I was looking on Digg for something else, Nonetheless I am here now and would just like to say cheers for a fantastic post and a all round enjoyable blog (I also love the theme/design), I don’t have time to read it all at the moment but I have bookmarked it and also included your RSS feeds, so when I have time I will be back to read much more, Please do keep up the awesome b.

  13. September 13th, 2013 at 23:47 | #13

    I just purchased a used lenovo Y410p for $469.99 at and I recommend it.

    It was basically new; no scratches or anything. They ship worldwide for free and they accept Paypal. It’s the best deal I’ve found for this gaming laptop.

  14. September 29th, 2013 at 10:31 | #14

    If you want a thigh gap or simply just want to slim down your thighs, I recommend the Thigh Gap Magic program. Just do a search in Google, you will find it. It’s amazing!

  15. January 26th, 2014 at 21:10 | #15

    Wow, that’s what I was seeking for, what a data! present here at this weblog, thanks admin of this web page.

    Also visit my blog post – Watch House of Cards Season 2 Online Free ([http://houseofcardsseason2.Blogspot.com](http://houseofcardsseason2.Blogspot.com/ “http://houseofcardsseason2.Blogspot.com”))

  16. May 19th, 2014 at 02:26 | #16

    Greg: I haven’t used them being a resource, but I went along to their site and like what I see. Thus, the technology supports phenomenally and everything is going to be driven very close for the activities worldwide through.

    report [Main Page](http://is.gd/eFulsQ “Main Page”)

  17. June 5th, 2014 at 02:50 | #17

    asus laptop comparison

  1. February 12th, 2011 at 16:23 | #1
  2. February 13th, 2011 at 03:39 | #2
  3. August 15th, 2011 at 09:33 | #3
  4. April 23rd, 2013 at 00:20 | #4
  5. May 17th, 2014 at 09:29 | #5
  6. June 27th, 2014 at 04:39 | #6
  7. June 27th, 2014 at 07:07 | #7

Comments parsed as Markdown.