Grado iGi in-ear monitors

For a while, I’ve been “sur­viv­ing” with the iPhone ear­buds, and they are, to put it sim­ply, dread­ful. They aren’t the worst I’ve ever heard, but they’re def­i­nitely a tri­umph of style over sub­stance. Given I also own a pair of Ety­motic Research ER-6i ear­phones, why was I using the dread­ful Apple bits? Sim­ple … the ER-6i made my ear hurt, though not because of the design. No, it was the “sound”. It sim­ply was painful to lis­ten to them for any extended period, some­thing I didn’t learn until after hav­ing had them for a while. The boost in the 2kHz and up range made my head hurt — per­haps from hear­ing dam­age as a child — and I couldn’t lis­ten to them for more than 15 – 20 min­utes before hav­ing to surrender.

So, when I wanted to lis­ten to things, I returned to my ever trust­wor­thy Grado Labs head­phones, for­ever wish­ing that they’d finally release an in-ear prod­uct wor­thy of their sto­ried name. And, now, they have. In fact, they’ve released two dif­fer­ent in-ear mon­i­tor head­phones: the afford­able iGi and the more up-market GR8. Since what I was look­ing for was some­thing to wear dur­ing my com­mute, the gym and per­haps at work, I went with the iGi, which arrived this afternoon.

The ini­tial ver­dict? They’re def­i­nitely voiced like a Grado prod­uct. Right now, there’s a tiny bit of break­ing in to be done — Grado claims 100 hours — but already they’re lightyears ahead of the piti­ful Apple prod­uct and the tire­some Ety­motic head­phones. I’m look­ing for­ward to wear­ing them as often as I want, and now all I need to do is fig­ure out the best set of tips to use.

Pushing the waterfall uphill

The ideas behind agile devel­op­ment method­olo­gies are not new. They were more for­mally stated in The Agile Man­i­festo. The ideas behind more basic iter­a­tive devel­op­ment are even older, and have their own trade-offs. Both con­tain the idea that you can not know every­thing upfront. The agile method­ol­ogy states this idea explicitely:

Wel­come chang­ing require­ments, even late in
devel­op­ment. Agile processes har­ness change for
the customer’s com­pet­i­tive advantage.

Iter­a­tive, on the other hand, allows for change between iter­a­tions, though not within them in any mean­ing­ful fash­ion. Each has it’s advan­tages, and largely they are cul­tural dif­fer­ences. Some orga­ni­za­tions sim­ply aren’t capa­ble of one or the other, and that’s OK.

The project I’m work­ing on now is attempt­ing to be iter­a­tive. We are try­ing very hard to be iter­a­tive, but the dif­fi­culty is that the client is absolutely insis­tent that we define every sin­gle require­ment up front before we do any­thing. For exam­ple, we are devel­op­ing use cases to doc­u­ment the exter­nal actor’s inter­ac­tions with the sys­tem. A sim­ple enough idea, and one that is very use­ful in a large sys­tem such as this. The prob­lem is two-fold how­ever. First, we are expected to com­plete the use case in one iter­a­tion and never touch it again. Touch­ing it again requires a con­tract change. Bril­liant. Equally bad, but more sub­tly so, is the fact that there is entirely too much detail in the use cases.

To me, use cases rep­re­sent value when they “tell a story” about how an actor (user) inter­acts with the sys­tem. They are told clearly from the actor’s per­spec­tive, and dis­cuss how the actor accom­plishes their goal, but not how the sys­tem works under­neath. Unfor­tu­nately, here we are putting in detailed enti­ties, attrib­utes and ser­vice (SOA) calls that will be con­sid­ered part of the con­tract. This makes it nearly impos­si­ble to “do the right thing” when the time comes, and forces an inor­di­nant amount of design detail into a period of time where not enough infor­ma­tion exists to make the decision.

In the end, it feels like a water­fall process, but with use­less labels applied. You can pre­tend it’s “agile”, or it’s “iter­a­tive”, but when the client looks at you in a meet­ing, and with a straight face and no sense of irony says: “This project is too big to be agile” you know some­thing is going to go ter­ri­bly wrong. The larger the project, the more impor­tant it is to be agile and adap­tive. The scope is entirely too big to ever know every­thing up front. When they say they want to define every sin­gle require­ment before begin­ning the design, and will not allow revis­it­ing of the require­ments, you know it’s going to be a long uphill battle.

There has to be a bet­ter way. I’m no Mar­tin Fowler, but this just doesn’t feel like a good idea.

A beautiful Google Reader application for the iPhone

Main screen of the Reeder 2 iPhone application for reading Google Reader feeds

Cur­rently, I sub­scribe to just over 740 RSS/Atom feeds in Google Reader. This has replaced my old stand-by of Net­NewsWire that I used for­ever. There’s two main rea­sons for this. First, it’s avail­able and always syn­chro­nized, some­thing Net­NewsWire wasn’t at the time. More impor­tantly, though, is the “social” aspect that it brings with shar­ing of links with my friends, as well as com­ments about those links. It’s helped me dis­cover a lot of new things over the years.

One of the down­sides of that many feeds is the sheer quan­tity of items that show up every day. It ranges from around 450 on a “slow” day to over 1,200 on a reg­u­lar day. This makes it quite dif­fi­cult to get through every­thing, and often I let some cat­e­gories just lan­guish until I just wipe them clean. Not use­ful! All that has changed based on a tweet by Jacob Kaplan-Moss that alerted me to a beau­ti­ful ded­i­cated Google Reader appli­ca­tion for the iPhone: Reeder.

So what makes Reeder such a plea­sure to use?

  • It is an iPhone app. I mean this in the sense that it behaves in a very touch-centric way, and has all the nice touches that a good iPhone appli­ca­tion should have. Like Tweetie it has the physics in it’s UI that feels “right”.
  • It’s rea­son­ably fast. The first sync took a lit­tle bit of time — per­haps a minute over 3G — but after that it’s been quite fast for me.
  • It works with other online ser­vices like Twit­ter, Instapa­per and Deli­cious. It also let’s me share things with my friends on Google Reader.
  • I keep dis­cov­er­ing lit­tle touches that feel like presents. For exam­ple, swip­ing over an item let’s you mark it read with­out look­ing at it.

All told, for $2.99, it’s a bar­gain. On my 30 minute ride home, I was able to sift through about 750 links, read some, throw some at Instapa­per for later and mark the rest as read. Highly rec­om­mend.

The holy war of the open-source era

Dis­trib­uted ver­sion con­trol sys­tems (DVCS) are all the range right now in the geek com­mu­nity. It has been just over 5 years since Matt Mack­all announced Mer­cu­r­ial to the world, and about the same since Linus Tor­valds announced Git. In the inter­veen­ing years, both have sprung up to be wor­thy com­peti­tors to one another, and more impor­tantly, viable replace­ments for the his­tor­i­cal cen­tral­ized ver­sion con­trol sys­tems, and really, any­thing that quick­ens the death of ClearCase and CVSgets my vote.

What wor­ries me is that there’s so many “flame wars” between the oppos­ing camps. At PyCon 2010, there was a great talk by Scott Cha­con of GitHub enti­tled “Hg and Git : Can’t we all just get along?”. The sum­mary mir­rors my views:

There is a fair amount of unnec­es­sary ani­mos­ity between devel­op­ers about ver­sion con­trol sys­tems, espe­cially between Mer­cu­r­ial and Git users. In real­ity, these two sys­tems are very sim­i­lar and can actu­ally coop­er­ate pretty well.

Git and Mer­cu­r­ial are more alike than dif­fer­ent. Rather than argue about the nuances of DVCS, let’s focus our energy on destroy — once and for all time — CVS and ClearCase. Sub­ver­sion is at least func­tional, but it too could go. Before we can do this, though, there’s one thing that has to be solved some­how, although I’m afraid it is a philo­soph­i­cal prob­lem with DVCS: large file sup­port. While there’s some effort to fix the prob­lem in both Git and in Mer­cu­r­ial, the real­ity is the prob­lem is a dif­fi­cult one when one of the core foun­da­tions of DVCS is that your “check­out” is really a “clone” of the entire repos­i­tory. This is how it is able to make a lot of things pos­si­ble, or at least fast enough to be use­ful. So, how do you deal with the ver­sion con­trol of large (> 10MB) files. These are more com­mon than you think. One project I work on has, quite lit­er­ally, hun­dreds of these files with extracts of other sys­tems that are expen­sive to per­form, but which form a depen­dency that needs to be tracked. For now, we keep those in Sub­ver­sion and the rest in Mercurial.

Finally, I think the real com­pe­ti­tion between Git and Mer­cu­r­ial is bet­ter viewed as the dif­fer­ence between GitHub and Bit­bucket. The real story is how these two sites have changed the inter­ac­tion model among devel­op­ers in open source projects. While GitHub cur­rently “leads” in adop­tion, with over 833,000 repos­i­to­ries (ver­sus who knows how many on Bit­bucket), the com­pe­ti­tion is excep­tion­ally impor­tant to drive fur­ther advances. These sites, and oth­ers like them, are where the rub­ber hits the road on chang­ing devel­op­men­tal processes. So whether you use Mer­cu­r­ial or Git, or even Bzr, remem­ber that col­lab­o­ra­tion is where the real inno­va­tion is hap­pen­ing. The change in orga­ni­za­tional inter­ac­tions is what really brings the ben­e­fit, the rest are just tools.

Charles Darwin was wrong

We are not, as Dar­win prof­fered, descended from the “lower mam­mals”. We are not the prod­uct of mil­lions of years of evo­lu­tion. We are, instead, the unre­lent­ing descen­dant of tele­phone san­i­tiz­ers. This was made ever more clear over the last few weeks as I strug­gled to explain to a client why charg­ing their cus­tomers for the sim­ple priv­i­lege of cre­at­ing an account on their web­site was epi­cally stupid.

You see, I cur­rently do some work for a large orga­ni­za­tion that han­dles a lot of paper­work. Forests full of paper­work, quite hon­estly, and they are finally try­ing to step into the 20th cen­tury and auto­mate things more. As part of that, they want to allow their cus­tomers to sub­mit a lot of their requests elec­tron­i­cally. This comes with innu­mer­able dif­fi­cul­ties, most espe­cially around fix­ing processes that are paper-centric, or replac­ing them whole­sale with new ideas. And yet, they con­tinue to insist that their cus­tomers should pay for the priv­i­lege of hav­ing an online account whereby they can sub­mit their requests elec­tron­i­cally. It seems to escape their notice that this idea would doom the entire effort and ensure that they will con­tinue to process only paper. To me, this is no dif­fer­ent than Ama­zon ask­ing for a fee to set up an account online so that you can later spend money with them. Or per­haps Safe­way charg­ing you to enter their store.

In what alter­na­tive uni­verse is this a ratio­nal idea?

The devolution of Facebook privacy

To truly under­stand the devo­lu­tion of pri­vacy that drove my deci­sion to aban­don Face­book, you need only look at this post by Matt McK­eon, which leads in:

How­ever, Face­book hasn’t always man­aged its users’ data well. In the begin­ning, it restricted the vis­i­bil­ity of a user’s per­sonal infor­ma­tion to just their friends and their “net­work” (col­lege or school). Over the past cou­ple of years, the default pri­vacy set­tings for a Face­book user’s per­sonal infor­ma­tion have become more and more per­mis­sive. They’ve also changed how your per­sonal infor­ma­tion is clas­si­fied sev­eral times, some­times in a man­ner that has been con­fus­ing for their users. This has largely been part of Facebook’s effort to cor­re­late, pub­lish, and mon­e­tize their social graph: a mas­sive data­base of enti­ties and links that cov­ers every­thing from where you live to the movies you like and the peo­ple you trust.

I was OK when Face­book only shared infor­ma­tion I shared with them, but the creep­ing inte­gra­tion of Face­book with every­thing else gives them “acci­den­tal access” to way more infor­ma­tion in aggre­gate. In some ways, they get more than Google does now, and that’s pretty scary to me. Just click on the graphic to under­stand how bad it’s got­ten. Event the ven­er­a­ble New York Times has got­ten into the act with an arti­cle enti­tled “Tell-All Gen­er­a­tion Learns to Keep Things Offline”.

Vattene via Facebook!

That’s it. After all the idiocy, incom­pe­tence, mali­cious­ness and gen­eral sus­pi­cious behav­ior at Face­book, I’ve deleted my account. You too can delete yours.

First, it’s impor­tant to under­stand there’s a dif­fer­ence between “sus­pend­ing” your account and actu­ally delet­ing it. The first will sud­denly re-activate if you log back in, or do any­thing that might cause an appli­ca­tion to acti­vate it again. The sec­ond actu­ally deletes it, although you have to wait 14 days before it takes effect. If you log in at any point dur­ing that 14 days, your account is active again.

The past few months have demon­strated that only one of the two things can be true:

  1. Face­book is run by epi­cally incom­pe­tent man­age­ment, devel­op­ers and admin­is­tra­tors who haven’t the slight­est clue how to deal with pri­vacy, and have been liv­ing in a cave for about 20 years.
  2. Face­book is run by epi­cally evil man­age­ment that is intent on destroy­ing your pri­vacy for their finan­cial gain at any cost and will couch it all in “hon­est mis­takes” and apolo­gies, but con­tinue to rip it down.

You can decide which is worse, but the real­ity it is one of the two. The Elec­tronic Fron­tier Foun­da­tion has posted some excel­lent information:

Are you ready? Go delete your Face­book account. If you do it “cor­rectly”, you should receive an email that looks like this:

Hi LoserWhoWantsToDeleteTheirAccount,

We have received a request to per­ma­nently delete your account. Your account has been deac­ti­vated from the site and will be per­ma­nently deleted within 14 days.

If you did not request to per­ma­nently delete your account, fol­low this link to can­cel this request:

http://www.facebook.com/account_delete.php

Thanks,
The Face­book Team

What are you wait­ing for?

A consolidated list of changes in Django 1.2

For some rea­son, there doesn’t seem to be a con­sol­i­dated list of changes that are com­ing in ver­sion 1.2 of Django. An odd deci­sion, but maybe it will be rec­ti­fied prior to release. Until then, I’ve put together a non-prioritized list of what seems impor­tant to me. This is mostly based on the release notes. I put it together for my own use so that I can bet­ter migrate my 1.1 stream projects. Things left out are things I don’t think are par­tic­u­larly note­wor­thy. Read the full release notes if you want to know.

CSRF pro­tec­tion (more)
This one is the big one that bit me when I started migrat­ing. Gone is CsrfResponseMiddleware and CsrfMiddleware an in is the csrf_token. Def­i­nitely read the upgrade instruc­tions, because it broke an enor­mous num­ber of things for me. In the end, it’s a great addi­tion, but it’s def­i­nitely not a triv­ial change for some peo­ple with all sorts of crazy form-based sites.
get_db_prep_*() meth­ods on Fields in a Model (more)
Restruc­tured the way you can over­ride default behav­ior. For now, if you’re not using the mul­ti­ple data­base sup­port, you are back­wards com­pat­i­ble, but you’ll need to make the change prior to Django 1.4 (sched­uled for 2050 I sus­pect at this rate).
Django e-mail hand­ing (more)
The way that Django han­dles send­ing email has changed pretty sub­stan­tially, and very much for the bet­ter. Now, instead of hav­ing to kludge around a lot of the pre­vi­ous issues, you can swap out the mail back­ends for some­thing eas­ier to debug or which behaves the way you want. I still use James Tauber’s excel­lent django-mailer, since I often have to do a lot of bulk email sends and need to do them at the right time. That, com­bined with django-notification makes for a good solution.
Mul­ti­ple data­base sup­port (more)
This is the new fea­ture which prob­a­bly brings the most expanded func­tion­al­ity. No longer are you forced to either deal with a sin­gle data­base, or worse, monkey-patch in some solu­tion, but there is now an approved way to han­dle the prob­lem. This includes the very cool routers fea­ture. It does, how­ever, change how you spec­ify the data­base con­fig­u­ra­tion.
User mes­sages frame­work over­haul (more)
The wildly bro­ken mes­sages han­dling (user.message_set.*) has been replaced with an entire user mes­sage frame­work (django.contrib.messages) that allows you to spec­ify back­ends and comes with a much more robust implementation.
Tem­plate caching (more)
No longer does Django stu­pidly reload and recom­pile your tem­plates from disk every sin­gle time. Huz­zah! More infor­ma­tion is avail­able.
New syn­di­ca­tion frame­work (more)
What more need be said than: it doesn’t suck any more.
Object-level model per­mis­sion (more)
You can now con­trol access on a per-object basis to your mod­els. This is effec­tively row-level per­mis­sions in the data­base. It’s not per­fect, and it can come with some pretty sig­nif­i­cant per­for­mance hits, but if you need it, you need it.

Next, the changes that are pretty small, but also nice.

  • Nat­ural keys in fix­tures (more)
  • Sup­port for a BigIntegerField. 64-bits ahoy! (more)
  • Read-only fields in the admin­is­tra­tive inter­face (more)
  • Incre­men­tal improve­ments in local­iza­tion (more)
  • Anony­mous users are now real users (more)
  • Improve­ments to han­dling of select_related (more)

Finally, there’s some minor changes that maybe will hit some peo­ple, but didn’t hit me.

  • Changes with the if tag (more)
  • LazyObject doc­u­men­ta­tion and changes (more)

  • __dict__ on Model instances (more)
  • State­ful tem­plate tags (more)
  • Test run­ner exit sta­tus code (more)
  • Changes to how the user mes­sages frame­work works (more)
  • Changes to date for­mat helper func­tions (more)
  • Changes to the unit test run­ners (more)
  • Minor changes in cookie encod­ing (more

I think that cov­ers just about every­thing at this point. Obvi­ously, a huge num­ber of bugs have been closed, and doc­u­men­ta­tion con­tin­ues to get bet­ter and bet­ter (and it was already pretty much the best of any open source web frame­work). Over­all, I’m look­ing for­ward to a sta­ble release stream to fol­low and get­ting every­thing moved over.

The case for “green energy” in 140 characters or less

From a recent tweet by Tim Bray on Twitter:

BREAKING: Large Air Spill at Wind Farm. No threats reported. Some claim to enjoy the breeze.

That pretty much sums it all up right there. I real­ize that there are all sorts of issues with “green energy”, but I think many peo­ple fail to rec­og­nize how absolutely dirty and filthy the legacy-petrochemical indus­try is.

Understanding let versus binding in Clojure

As I get back into writ­ing Lisp code — via Clo­jure — I am find­ing a few things that I’m trip­ping up over on a reg­u­lar basis. Some of this is pre-conceived notions of behav­ior, and some is just men­tal lazi­ness. The one I keep com­ing back to, over and over, is the sub­tleties of lex­i­cal scop­ing ver­sus dynamic scop­ing. Inspired by this post, I thought I’d take a stab at explain­ing it in a slightly dif­fer­ent way. You can never have too many expla­na­tions. This is my under­stand­ing as it exists today. It is likely some­what wrong. It might even be com­pletely and totally wrong.

The first thing to do is replace the word “lex­i­cal” with the word “sta­tic”. Now we’re using orthog­o­nal vocab­u­lary. It also makes some things a bit more obvi­ous. Before we dig into scop­ing (sta­tic v. dynamic), we first need to be care­ful to define what we’re talk­ing about: bind­ings. The idea of a “vari­able” doesn’t really exist in the tra­di­tional sense. You have sym­bols, val­ues and bind­ings. Take the fol­low­ing code snip­pet for example:

user=> (def foo)
#'user/foo

Here, we have def, which is a spe­cial form that cre­ates a Var, and foo, which is a sym­bol that is used to iden­tify the Var in the future. At this point, foo has no “value”, and so we can’t refer to it:

user=> foo
java.lang.IllegalStateException: Var user/foo is unbound.

So why in the world would you want to do this? Just you wait and see. More typ­i­cally, you also cre­ate the ini­tial bind­ing to a value:

user=> (def foo 100)
#'user/foo

Once again, we have the sym­bol foo, but it’s now bound to the value 100. The bind­ing is that “invis­i­ble” link between the Var and the value. To quote the Clo­jure “man­ual”:

Every Var can (but needn’t) have a root bind­ing, which is a bind­ing that is shared by all threads that do not have a per-thread bind­ing. Thus, the value of a Var is the value of its per-thread bind­ing, or, if it is not bound in the thread request­ing the value, the value of the root bind­ing, if any.

That seems easy enough, right? Right. So, if you saw the fol­low­ing code snip­pet, what would you think we would get in response?

user=> (println "The value of foo is:" foo)

Easy, right? The value of foo is: 100. Sim­ple, and no strange behav­ior, right? Right. Next up, sta­tic (lex­i­cal) scop­ing. This is best typ­i­fied by the let spe­cial form.

user=> (let [foo 50] (println "The value of foo is:" foo))

Also, not too hard, I sup­pose. We get The value of foo is: 50, which is pretty pre­dictable. So what’s the fuss? Well, take a look at the next code sam­ple and see if you can fig­ure out what the out­put is.

(def foo 100)
 
(defn print-foo []
  (println "The value of foo is:" foo))
 
(let [foo 50]
  (print-foo))

Did you answer 50? That’s unfor­tu­nately wrong. The answer is 100, but why? Let’s return to Wikipedia:

With lex­i­cal scope, a name always refers to its (more or less) local lex­i­cal envi­ron­ment. This is a prop­erty of the pro­gram text and is made inde­pen­dent of the run­time call stack by the lan­guage implementation.

When Clo­jure eval­u­ated the defn form, it used the Var that was avail­able at-the-time. When you use the let spe­cial form, you “shadow” the orig­i­nal Var — cre­at­ing a hier­ar­chy of bind­ings — but you don’t change the bind­ing that print-foo was refer­ring to. Hence, 100. In the other exam­ple, we don’t refer to the Var until inside the let spe­cial form.

Another bit about let that some poe­ple might not pick up is that once assigned, the value of the local can never change. The bind­ing is fixed. For example:

user=> (let [foo 100]
         (println "The value of foo is:" foo)
         (def foo 200)
         (println "The value of foo is:" foo))
The value of foo is: 100
The value of foo is: 100

Wait, what? As I said, you can’t rebind foo inside the let form. It is a “con­stant”. Another behav­ior of let is that it per­forms its bind­ings sequentially.

user=> (let
           [foo 100
            bar foo]
         (println "The value of foo is:" foo)
         (println "The value of bar is:" bar))
The value of foo is: 100
The value of bar is: 100

So that cov­ers the basics of the let spe­cial form.

Next, we have the binding spe­cial form, and it’s a tad more com­pli­cated to under­stand. So let’s first take the API doc­u­men­ta­tion:

Cre­ates new bind­ings for the (already-existing) vars, with the sup­plied ini­tial val­ues, exe­cutes the exprs in an implicit do, then re-establishes the bind­ings that existed before. The new bind­ings are made in par­al­lel (unlike let); all init-exprs are eval­u­ated before the vars are bound to their new values.

So, first, the Var must already exist. You can’t do this:

user=> (binding [bar 100] (println "The value of bar is:" bar))
java.lang.Exception: Unable to resolve var: bar in this context

So how might we solve this? Well, if we don’t care about the root bind­ing, but only the bind­ing that exists within the binding spe­cial form, then we could do some­thing like this:

user=> (def bar)
#'user/bar
user=> (binding [bar 100] (println "The value of bar is:" bar))
The value of bar is: 100

Recall, that def with­out a value just cre­ates an unbound Var. If we had tried to refer to it prior to binding it, then we would have got­ten an excep­tion. I’m not sure this is a wise way to use things, but in my mind binding is pri­mar­ily some­thing to be used in a con­cur­rent envi­ron­ment since any binding is always thread-local.

So what does binding do? It replaces the root bind­ing of the Var with a thread-local bind­ing for any­thing inside the form. So, for example:

user=> (def bar 10)
#'user/bar
user=> bar
10
user=> (binding [bar 100]
  (println "The value of bar is:" bar))
The value of bar is: 100
user=> bar
10

As you can see, bar returns back to it’s orig­i­nal value out­side the form. Now, let’s play with it in a sim­i­lar way to how we did with let earlier.

user=> (defn print-bar [] (println "The value of bar is:" bar))
#'user/print-bar
user=> (print-bar)
The value of bar is: 10
user=> (binding [bar 100] (print-bar))
The value of bar is: 100

In this case, we’ve swapped the root bind­ing out from under the orig­i­nal one and we’re not actu­ally shad­ow­ing it as we would with let. Another dif­fer­ence is that binding per­forms its ini­tial bind­ings in par­al­lel, which means you can’t have depen­den­cies on ear­lier bind­ings made in the same form.

user=> (def baz 20)
#'user/baz
user=> (defn print-baz [] (println "The value of baz is:" baz))
#'user/print-baz
user=> (binding [bar 100 baz bar]
         (print-bar)
         (print-baz))
The value of bar is: 100
The value of baz is: 10

There’s one last lit­tle piece, and that’s the behav­ior of anony­mous func­tions inside let ver­sus their behav­ior inside of binding.

user=> (binding [print-bar print-baz] #(print-bar))
#<user$eval__1620$fn__1621 user$eval__1620$fn__1621@144683c2>

Wait, what just hap­pened? Why didn’t it print some­thing? That’s sim­ple. The cre­ation of the anony­mous func­tion doesn’t call the func­tion, so the result of the form is the func­tion, not the value of call­ing the func­tion. So that’s point one. Point two is that if you look at what was returned, say by cap­tur­ing it in another Var, you’ll see that it’s the orig­i­nal print-bar, not the rebound one.

user=> (def print-what (binding [print-bar print-baz] #(print-bar)))
#'user/print-what
user=> (print-what)
The value of bar is: 10

Why might that be? It’s because the anony­mous func­tion was actu­ally eval­u­ated “out­side” the bind­ing. This is because it’s actu­ally cre­ated by the reader macros. So, what do you do if you want the binding to apply?

user=> (binding [print-bar print-baz] (#(print-bar)))
The value of baz is: 20

In this sit­u­a­tion, the extra set of paren­the­sis force the eval­u­a­tion of the anony­mous func­tion inside the binding.

Hope­fully, this has been of some use to some peo­ple. It’s been use­ful for me in think­ing through the dif­fer­ences and the uses of the two forms. As with the orig­i­nal post, I come away with a few spe­cific guidelines.

  1. Use let unless you really know you need binding.
  2. Use binding when you need a thread-local ver­sion of a Var.
  3. let is assigns sequen­tially, but binding is parallel.

If I’ve made any mis­take, no mat­ter how minor, please cor­rect me in the com­ments, and I’ll update this to reflect it. This is an excep­tion­ally impor­tant, but also sub­tle, area of languages.