Closures are Beautiful

As of late I have been looking at simulation systems and in that context at media and gaming frameworks as platforms to host simulations. One such library/framework is the Simple Direct Media Layer or (SDL).  Graphics in SDL are simple, but simple things like rendering text are difficult. What might be a trivial call to std::cout or printf in C/C++ becomes cumbersome as one needs to load true type fonts, bit-blit to screen contexts and update regions invalidated by the bit-blit operation. In other words, there is plenty of state going around.

Here is my first attempt at a function to render text to an SDL screen context.

SDL RenderText Function

It’s all pretty simple. Aside from the use of C++ string, this is pretty much idiomatic C. Let’s ponder this for a moment.

What’s the trouble with it? All a user wants to do is write some text, the equivalent of printf(“Hello World”), but all the other bits are needed to render this text given the context of SDL.  We have some choices now. We might elect to wrap the whole thing in a class, call it Render, and initialize peripheral state in its constructor, e.g. font, and then give any client code an object of type Render. Render would now have to have at least one other function to effect displaying the text  that accepts just the intended text as input. This would be an idiomatic object-oriented solution the problem of state. Alternatively, if  we wanted to be stateless, we are forced to thread the other arguments (font, etc. ) everywhere through the client code, which is clearly undesirable. But it would let us keep just the simple function we have above. Now then, if we go the object route, we need to decide on access control ( private / derived etc ) as otherwise less well-behaved client code might well modify associated state in unintended ways. That would break encapsulation. Further, if we go the object route, we need to declare a new type and accept that type as input argument somewhere, which creates further dependencies throughout our code. We can avoid this and stay generic by using templates. This would allow us to code to just an interface, not an implementation. But we are faced with issues on that front as well. If we template a client code class, we create an incomplete type. Doing simple things like passing a pointer to the client class now becomes impossible.  We effectively broke polymorphism by choosing to template a class. To be sure, if we are only templating a function, the problem of an incomplete type does not arise, but then we cannot store our Render type in client code. If multiple functions in a client class needed it, we’d have to pass it around everywhere. In short, it’s ugliness all round!

Closures to the rescue ! 

In C++11 we rewrite thusly using a lambda over lambda idiom. There are other ways, but this is one.

Lambda over Lambda

This creates a function that serves as “constructor.” It’s return type is a lambda function that binds all ‘peripheral’ state as free variables to the inner lambda form. The argument to the inner function will be just the text we want to render.

We create a Render function using this construct like so :

Create Render Function

This can now be called using regular function notation, just as simple as printf

Simple Use

But what of client code using this ?

Any client code would simply mandate that we provide a function taking a string as an argument …

Screen Shot 2014-12-18 at 8.32.19 am

…and subsequently simply invoke foo() with a text argument.

In client code the only interface to our renderer becomes this: (). We didn’t  create a type in a class hierarchy and dependencies upon it. We didn’t even use templates in an endeavor to stay generic, with all the complications that entails. We didn’t even bind ourselves to a specific method – in object orientation land we’d likely have a dot-render method on a class with state somewhere.

… Closures are beautiful


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s