SamePlace, the contest, and Italy

This blog used to be mostly about SamePlace. If you’ve been reading it long enough to remember that, you’re probably one of the early adopters, so please virtually celebrate with me this little bit of news. :-)

SamePlace won a grand prize together with Shareaholic and Minimap (the announcement lists them in alphabetic order with a numeric bullet and they look like first/second/third prize—they’re actually co-winners, just like the twelve runners up.)

And it seems it’s been a productive time for Italy: my friend Davide is there too with Table2Clipboard. Not bad for this old little country. :-)

Dynamic variables hack in Erlang

One thing that jumps to the eye in functional code sources is longer-than-usual argument lists.

process(Tree, Env, Plugins, Config, ...).

It’s easy to see that as a consequence of functions using arguments as sole input channel. (Global -define()‘s don’t qualify as input channels—they can’t vary at runtime, arguments can.)

Usually it’s no big hassle.

Sometimes though you have a front-end function to a complex computation which is arranged in many layers of function calls, and you need to pass something to the front-end that only the lowest layer needs. You’d rather to not care about it in intermediate layers, but you still have to because intermediate layers forward it to the lowest one.

Obligatory contrived example (if you can read Ruby, Dave Thomas has a better one):

%% User invocation
library:do_it(A, B, C, D).

%% Library
do_it(A, B, C, D) ->
    part1(A) ++ part2(B, C, D).

part2(B, C, D) ->
    extra_computation(B) ++ part3(C, D).

part3(C, D) ->
    another_extra_computation(C) ++ part4(D).

%% ...

Above, D isn’t really needed until part4, but part1, part2 and part3 have to accept it as argument.

Functions being unable to see beyond their argument list spares me many a headache compared to when I dwell in OO-land, so I tend to deem it a feature, not a bug. In cases like the above however I’d like to relax boundaries. Especially when doing exploratory programming and part1, part2, partN have several clauses and invocation points, maintaining “forwarding” argument lists can impair your flow.

Common Lisp has dynamic variables. They’re best described through an example (leaving out the parentheses, since they scare away large chunks of the population):

> defvar *player* "Dr. Falken"

> defun player-greeting
>   concatenate 'string "Hello, " *player*

> player-greeting
"hello, Dr. Flaken"

> let ((*player* "Matt")) player-greeting
"hello, Matt"

> player-greeting
"hello, Dr. Flaken"

let temporarily changes the binding of *player* for the scope player-greeting is evaluated in.

Here’s a way to do it in Erlang. (Read it up to the end, there are caveats.)

First, user’s point of view:

player_greeting() ->
    "Hello, " ++ dynvar:fetch(player).

test() ->
    Greeting = dynvar:with([{player, "Dr. Falken"}],
                           fun player_greeting/0),

Invoking test/0 will produce "Hello, Dr. Falken".

The code:

-export([with/2, fetch/1, test/0]).

with(Bindings, Action) ->
    lists:foreach(fun({Name, Value}) -> put(Name, Value) end, Bindings),
    try apply(Action, []) of
        X -> X
        lists:foreach(fun({Name, _Value}) -> erase(Name) end, Bindings)

fetch(VarName) ->

Yes, the process dictionary seems to be at the epicenter of dirty Erlang hacks. :-)

A few considerations:

  • Common Lisp’s player-greeting can work without a “let” explicitly binding a value to *player*. The Erlang example can’t. This isn’t necessarily a drawback (see next point).
  • Syntax of the Erlang example is more verbose. A few bytes could be shaved off using macros and ditching dynvar:fetch/1, but that would only be a win in the eyes of the “beauty above all” crowd (surface beauty, let me add). First, indirecting via a macro would make life harder for whomever maintains the code six months down the road. Second, when you’re going against the grain of the language, you may want the comments to mention it, and you really want the code to scream it. (Do as I say, don’t do as I do.)
  • This may collide with other uses of the process dictionary. Consider adding a unique prefix to keys (e.g. dynvar-) before put()’ting them into the dictionary if that is an issue.
  • Where will you want to use this? Well, I’m using it in the internals of the seethrough template engine to avoid passing arguments through intermediate layers. Using it in library internals, preferably within a single module, not leaking signs of dynvar to the library user, is where I can advise to use this and still retain a clear conscience.

Put the Fox in the Box

More goodies for MozRepl-equipped Firefoxes: T. V. Raman points me to a simple shell script to start and drive the browser on headless machines and to a module to drive Firefox from Emacspeak.

Quote of the day from the above post:

But in the fine UNIX tradition of Get out of my way or I’ll turn you into a shell script XVFB also turns out to be just what I needed in order to run Firefox as a headless application.


Why talking about “alternative” is shooting yourself (and others) in the foot

I’ve seen it happen time and again. Companies and individuals go out of their way to write great open source software, then, when the moment comes to let the world know about it, they (and/or their early adopters and proponents) present it as “an alternative to [proprietary solution] Foo”.

That’s bad when Foo is an established player:

But it borders on self-flogging nonsense when Foo is not even in the stores: Linux MPX Multi-touch Table May Become Alternative Microsoft Surface.

When you frame things like that, you’re giving positive (and free) advertising to the opposing party. At least for me and for those I asked, the following accurately portrays what the phrase “alternative to Foo” brings to mind:

Whether you’re the author of “Bar” or a passionate user advocating it, is that really the picture you want to suggest? (This, by the way, is why there’s no place for things like alternative to MSN/AIM/YahooIM/whatever on, despite much well-meant advice to the contrary.)

“Oh, that’s all good and well, but how am I supposed to advocate Firefox to someone who doesn’t even know what a browser is? How, if not contrasting it to something they know, such as Internet Explorer?”

If you’re advocating a product, and genuinely believe that it’s better (if not, why are you advocating it in the first place?), that is the idea you want to get across.

“Oh, you’re still using this to browse the ‘net? Haven’t you upgraded to Firefox yet?”