Whenever I'm doing the same thing over and over, a little background thread in my brain starts to wonder if there's a better way. Sometimes I tell it to shut up and let me code, other times I listen. In this case it took me a long time to listen, so it must have been pretty persistent. The first time I noticed it was while writing some lisp. Here goes the usual overly trivial example:
I write (+ 3 4)
then realise I want to multiply the result by 5. I have to go back to the start of the expression and change it to (* (+ 3 4) 5)
. I could easily blame lisp's prefix syntax and maybe define some reader macro so I can write something like (+ 3 4) >> (* 5)
. But that would solve one case and not really fix the overall problem. Here's the obligatory less trivial example:
I write (+ 3 x)
then realise that x needs to be a lambda parameter, so I go back and write (lambda (x) (+ 3 x))
. I think it's difficult to make the above >> reader macro work with this.
(+ 3 x) >> (lambda (x))
might work, but it's starting to get hard to read. It doesn't seem as natural as it did for the previous case.
But, as I said, it took me a long time to take notice of this background thread, and in fact when I did I was writing Scala, not lisp. When in lisp I just wrote the code anyway, and it didn't harm me noticably. I never wrote the above reader macro, and as I've never written one, chances are it's unwritable anyway.
The case when writing Scala was where I was looking at an expression, then realised that one of its inputs would be a collection, not a single value. A closer-to-reality example - you have a Client, and a Client has a manager, the contact there that you speak with. So you have:
def sendSpam(client: Client) = emailer.send(marketingTripe, client.manager.emailAddress)
. Then later you change Client.manager to Client.managers, and change its type from Manager to Iterable[Manager]. Now the emailer protests (at compile time), so you have some options:
1. Change the emailer to make it accept an Iterable[Client]. This is actually quite reasonable, and what I did in the real code this mimics.
2. Change the code to:
client.managers foreach (manager => emailer.send(marketingTripe, manager.emailAddress))
.
3. Listen to the background thread in your brain, and blog about an automatic transform from the original version to option 2. Today I'm choosing option 3, as you can tell. To avoid ambiguity, I'll introduce some syntax to put around 'managers':
emailer.send(marketingTripe, ^(managers).emailAddress)
will be transformed to the code from option 2 above (though perhaps without a real variable name).
At this point, you might be seriously glad that I am not a committer on the compiler for the language that you use every day. But I think the above might actually be a good idea, and might even be a better syntax for a map with a lambda than what we're used to. The reasoning is: it's preferable to write code in a natural order, rather than the order that the language forces you to.