Packing my bags for a new blog
If you're here, and you want to see my more recent stuff, you might want to check out Bits, Books, and Bikes. I decided to switch from Posterous to Tumblr because it feels like a more cozy place to write.
If you're here, and you want to see my more recent stuff, you might want to check out Bits, Books, and Bikes. I decided to switch from Posterous to Tumblr because it feels like a more cozy place to write.
Originally written September 8, 2005, updated December 27, 2005.
One of the big new features of Java 5.0 is a new syntax for iterating over collections. Instead of tediously typing the following:
for (Iterator i = c.iterator(); i.hasNext(); ) {
String s = (String) i.next();
...
}you can now, thanks to the fabulous new iteration syntax along with the introduction of generic types, substitute the following code:
for (String s : c) {
...
}That’s clearly a lot less keyboard pounding. But a question begs to be answered: Why did it take ten years to introduce this feature? Let’s forget about that important question for now and look at another programming language, Python.
Python is in many ways a much nicer language to program in. And it evolves more quickly than Java. For example, generators were introduced in Python 2.2. A generator is a function that can produce multiple values, maintaining state between each call. Here’s a simple example:
def counter(n):
while True:
yield n
n = n + 1Because this function definition contains the keyword yield, Python knows it’s a generator. You use the counter generator like this:
c12 = counter(12) c12.next() c12.next()
The first line creates an instance of the generator that starts counting at twelve. The second line tells the generator to run until it yields a value. The third tells the generator to resume running until it yields another value. The first two values yielded by this generator are the integers twelve and thirteen.
This is a cool feature: It lets programmers write simple code that without generators would be complex and error-prone. Why can’t Java be more like Python?
Lets put this second question aside and think about how me might implement Python’s generators in a language used by some of the most smug weenies in the world, Scheme. Scheme is a dialect of Lisp that’s been around in one form or another for about thirty years. Lisp has been around in one form or another for almost fifty years.
Here’s the best Scheme implementation I could come up with that works like the Python counter generator:
An aside for experienced Lisp programmers: The procedure I’m about to show you is far more complicated than the canonical example of an accumulator, because I’m duplicating the semantics of Python’s generators.
(define (counter n)
(letrec ((generator
(lambda (yield)
(let counter ((n n))
(call-with-current-continuation
(lambda (continue)
(set! generator (lambda (k)
(set! yield k)
(continue n)))
(yield n)))
(counter (+ n 1))))))
(lambda () (call-with-current-continuation
(lambda (yield)
(generator yield))))))“OMFG!” you must be saying to yourself. OMFG indeed! In the original version of this scrap, I said writing this wasn’t so so difficult. I then found a bug that would lead to an infinite loop when the counter was used in certain non-trivial ways. So I’m going to come out and admit it: People shouldn’t have to write procedures like this if they simply want to write a function that acts like a Python generator. On the plus side, this monstrosity can be used very simply by client code:
(define c12 (counter 12)) (c12) (c12)
The first line defines c12 to be the result of the procedure counter called with twelve as its sole argument. The second and third lines call c12 with no argument and return, just like the Python examples, the values twelve and thirteen. But this is all academic, because no sane person would write procedures like this on a regular basis.
Writing procedures like counter regularly leads to cramped fingers and a head ready to explode. But it’s interesting to note that it is possible to write counter, and that, to the outside world, the Scheme generator is easier to use than the Python version, because the Scheme version returns a procedure, which can be called like any other procedure, unlike Python generators, which return generator objects, which require programmers to call the next method.
(An aside: The designers of Python’s generators could have opted to implement generator objects in such a way that the next value could be retrieved via c12() and c12.next(), but they didn’t. The decision doesn’t make any sense to me. And while I love many things about Python, there’s a sort of ugliness that pervades the non-trivial corners of the language.)
Back to Scheme… The error-prone tedium of writing these generators in Scheme would seemingly make them impractical, but they’re not, because Scheme includes a feature that Python and Java lack: the ability to extend the syntax of the language. If you can manage to write the Scheme version of counter, it isn’t much more effort to create a macro that makes this feature available in an accessible way. Here’s the macro code I wrote that does just that:
(define-syntax define-generator
(syntax-rules ()
((define-generator (NAME ARG ...) YIELD-PROC E1 E2 ...)
(define (NAME ARG ...)
(letrec ((generator
(lambda (yield)
(let ((YIELD-PROC
(lambda v
(call-with-current-continuation
(lambda (continue)
(set! generator (lambda (k)
(set! yield k)
(apply continue v)))
(apply yield v))))))
(let NAME ((ARG ARG) ...)
E1 E2 ...)))))
(lambda () (call-with-current-continuation
(lambda (yield)
(generator yield)))))))))Once you have this macro, the Scheme version of the counter generator looks like this:
(define-generator (counter n) yield (counter (+ 1 (yield n))))
Not bad, eh? The only thing that bothers me about this version is that I need to specify the name of the yield procedure. But one could argue that it gives programmers flexibility to give the procedure whatever name make most sense given the context of the code. (Again, experienced Lispers will know that this “feature” could be fixed by using non-hygenic macros, but we’re sticking to standard, R5RS Scheme here.)
If you compare the first and second versions of counter, you might notice that I did something tricky in the new, define-generator version: the yield procedure returns the value that it yields, so it can be used in the recursive call to counter. And you can’t do that with Python’s generators.
So why can’t Java be more like Python? The answer is Java is a lot like Python: Python users had to wait around for about ten years before they got generators. I added support for generators in Scheme in a few hours of playing over three days. We can argue that generators, as well as other recent features of Python, like list comprehensions, make Python a more pleasing language to work in — and I wholeheartedly agree with that argument — but fundamentally, Java and Python are alike in that you can’t modify the language itself.
Java, Python, and nearly every other non-Lisp language in existence put you at the mercy of language designers. You need to wait for them to implement the language features at the top of your wish list. And when they do manage to scratch your itch, who’s to say you’ll like the result?
So why did it take ten years for the enhanced iteration syntax to make its way into Java? It took so long because in Java, as in most other programming languages, syntax is a big deal. You just don’t go changing a language’s syntax. It’s hard to do, and only a select few have the skills to do it. And when it happens, expressiveness and clarity take a back seat to preserving backwards compatibility.
In Scheme, adding syntax is relatively easy, and can be done on a per-problem basis, so you don’t have to worry about coming up with the ideal-for-all-time solution. This ability to build the language up to a problem trumps any concern over writing in a language that uses a lot of parentheses.
Schemers.org
Scheme resources
Lisp resources
Python Generators in Ruby
As has been reported, Microsoft has all but taken over Nokia. The gist? Both companies recognize that a vertically integrated approach is a necessity for anyone who wants to make products that matter—product ecosystems that matter—in the mobile world.
But isn't Nokia notorious for being an engineering focused organization, and doesn't Microsoft have to keep up the pretense of the arms-length, just-another-partner relationship? How is this going to lead to the creation of game-changing products, even if there are world class engineers, designers, and business people on both sides of this collaboration? And a game-changing product—a series of products, really—is what's needed if either of these companies hopes to be even remotely relevant.
The Next crew was able to charge the gangplank and take over the Apple mothership, because Next was the seat of Apple's government in exile, Steve Jobs's Saint Helena (to mix metaphors). Mid-nineties Apple had lost its mojo, its soul, and the prospect of a takeover was invigorating.
If anyone believes that there's any analogy to deploy with Microsoft and Nokia, they're crazy. I didn't even want to put that sentence in the previous paragraph, the idea's so crazy.
There's also the small problem that is Microsoft's doomed-to-fail iPad-response-slash-tablet-strategy. What are they going to put there in the middle, between their dominant Windows PC operating system and their relatively well-reviewed most-recent phone OS? That iOS, previously "the iPhone OS," could Provide a good user experience was an open question, and I'd need to be convinced that Windows Phone 7 can work on a tablet. (Does anyone seriously think it would?)
I was staring out the window at the southeast corner of Broad and Sansom, wondering where I was going to get my mid-afternoon americano—not my early afternoon or late afternoon americano, my mid-afternoon one—when I noticed the food cart below. It makes good, inexpensive breakfast sandwiches; you should check it out.
But it was not the cart's food that caught my attention, it was the umbrellas. It occurred to me that customers probably spent plenty of time gazing, dazed and hungry, at the inside of those umbrellas. A wonderful communication opportunity. Was this opportunity seized by those who had paid for, or at leash subsidized, these umbrellas? Capogiro, that is where I would go for my americano. Coffee. That's the important thing. Stay focused. Maybe swing by—swing under?—the umbrellas on my way to liquid mental clarity. And so I did. And it turns out that they didn't. The umbrella subsidizers, they didn't print anything on the interior of the umbrellas. How could they. It's almost as bad as forgetting to put something on the butt of a pair of girl's sweatpants. What is wrong with America?