Simple prototyping in Python

Michael Geary Mike at DeleteThis.Geary.com
Tue May 4 03:05:06 EDT 2004


Greg Ewing wrote:
> BTW, IMO [the closure] is a seriously warped technique
> that I would never use, even in Javascript. I can't see any
> benefit in it that's anywhere near worth the obfuscation.

I think part of the problem is the contrived examples that we all use to
illustrate closures. They show the technique, but the closure doesn't
provide any apparent benefit.

At the risk of overstaying my welcome, here is a real life example, a bit of
Acrobat 6 multimedia JavaScript code that uses closures. I may have posted
this before (or maybe I'm thinking of the Prothon list), but this time I
translated the closure code into a version that uses objects and no
closures, so we can compare the two.

Here's what the code does. The reportScriptEvents function opens a media
player and starts it playing, and it provides an event listener that handles
two events, onScript and afterClose. Each time a script event occurs in the
media clip, the onScript event method appends the script event's command
name and parameter to a log string. After the media clip finishes playing,
the afterClose event method takes that accumulated log string and passes it
to a reporter function which was provided in the call to reportScriptEvents.

The testReport function calls reportScriptEvents and provides a reporter
function which displays the accumulated log in an alert box. testReport has
a title parameter which is used for the title of the alert box.

Note that the media player opens and plays asynchronously.
reportScriptEvents and testReport return immediately upon opening the
player, and the event methods and reporter function are called later on, as
the media clip plays and closes.

Here is the code using closures:

function reportScriptEvents( reporter )
{
    var log = "";

    app.media.openPlayer(
    {
        events:
        {
            onScript: function( e )
            {
                log += e.media.command + ": " + e.media.param + "\n";
            },

            afterClose: function()
            {
                reporter( log );
            },
        },
    });
}

function testReport( title )
{
    reportScriptEvents( function( log )
    {
        app.alert({ cTitle: title, cMsg: log });
    });
}

Now for a version with no closures, using object properties to hold the
persistent state instead. I had to change the definition of
reportScriptEvents slightly. Instead of using a reporter function, it takes
a reporter object with a report method. In this version, the events object
has reporter and log properties which replace the closure variables in the
previous version, and the testReport function creates a reporter object with
a title property which it passes in to reportScriptEvents.

function reportScriptEvents( reporter )
{
    app.media.openPlayer(
    {
        events:
        {
            reporter: reporter,
            log: "",

            onScript: function( e )
            {
                this.log +=
                    e.media.command + ": " + e.media.param + "\n";
            },

            afterClose: function()
            {
                this.reporter.report( this.log );
            },
        },
    });
}

function testReport( title )
{
    reportScriptEvents(
    {
        title: title,

        report: function( log )
        {
            app.alert({ cTitle: this.title, cMsg: log });
        },
    });
}

The two versions are fairly similar, but the closure version of the code is
shorter and simpler, and to me it's easier to understand as well. I don't
have to create any objects or properties to hold persistent state. I just
use ordinary variables, and I don't have to think about the fact that the
event methods and reporter function are called long after the
reportScriptEvents and testReport return. The variables just work.

In the object version, I have to create the machinery to hold persistent
state myself, setting up the reporter and log properties in the events
object and the title property in the reporter object.

Sometimes objects and properties are a better solution, but to my eyes the
closure version is the winner in this particular case.

(Sorry to be posting so much JavaScript code in the Python group! :-) But
it's a good example of real world code that benefits from using closures.)

-Mike





More information about the Python-list mailing list