Back when I was giving my Ruby.MN and Groovy.MN* presentations on OCaml (blog post with video and handouts), one of the questions that came up (from Jesse of Refactr) was why I saw static typing and functional programming as being so tightly connected. After all, Erlang is a dynamically typed functional language, so what’s with the whole static typing hang-up?
At the time, I had an answer, but it isn’t the whole story. That answer was that dynamic typing doesn’t get rid of types, it just moves the type checks runtime (see Ruby’s “No such method” exception/”nil when you didn’t expect it” exception), you still have to be wrestling with type information in your code. When you start working at the higher level of abstraction that is functional programming, tracking types “in your head” becomes tricky, and so static typing helps identify bugs.
One of the big examples is point-free programming, which simple implementations of can be done in Groovy by chaining together functional operators.
results*.foo.collect { [it.bar, it.size() / 2] }.sort({ a,b -> a[1] <=> b[1] }).findAll { it[1] > 0 || it[0].name == "EMPTY" }.collect { [it[0].baz, it[1]] }.inject([:]) { hash,entry -> log.debug("Processing ${entry[0]}") hash[entry[0]] = entry[1] }
And so on. As you build up these kinds of constructs, it becomes easy to lose track of what you’re doing and where you’re at — they’re maintenance nightmares in a dynamically typed language, but they’re wonderfully succinct ways of expressing business processes. The dynamic typing situation gets even worse if you try to use closures which aren’t defined straight in-line, or which had previous processing (e.g. curry) done on them.
There’s another reason, though, which I’ve just recently bumped into while developing the BackgroundThread plugin for Grails. Consider this scenario.
let foo = "foo";; let x = (^) foo;;
The same thing (within handwave) in Groovy is:
def foo = "foo" def x = { foo + it }
So far, no big deal. Here’s a key difference, though — in Groovy, you could define x this way:
def x = { "$foo" + it } // Stringify foo
Or, if “foo” was a property on the owner:
def x = { owner."$foo" + it } // Access "foo" property in enclosing context
So, in Groovy, when you define a closure, you’re required to hold onto the entire surrounding context — the garbage collector won’t clean up any of those variables, because they may happen to be used. In the OCaml code, the only thing being stored with the closure is the “foo” variable itself, because OCaml knows you won’t be able to use anything outside of it. This difference becomes extremely relevant when you start dealing with long-lived closures (like in the BackgroundThread plugin), because a context that throws off a number of background tasks won’t be cleaned up until after all of those tasks have resolved themselves. And if you’ve got a list of 3000 domain objects in that context, that’s a non-trivial amount of memory you’re hanging onto.
So, if you’re going to be throwing off a closure which may be long-lived in a dynamically typed language, it is important that you try to use consume as much of the context as you can to minimize your memory footprint and allow the garbage collector to do its thing.
*BTW: I’m bummed that the .NC domain name registrar requires you to live in New Caledonia. So much for my dreams of Groovy.NC…
8 Comments
I had to go look up what Groovy’s “it” variable means, so maybe I’ll save somebody else time by linking it: http://groovy.codehaus.org/Closures#Closures-It .
Ha. Yeah,
itin Groovy is like$_in Perl. While I’m a huge fan ofit, Hamlet D’Arcy isn’t: http://hamletdarcy.blogspot.com/2008/09/improve-groovy-by-removing-feature.htmlI don’t like it only because “it” is ungoogleable. Language documentation should have a section for “things you can’t google”. When I come across a usage of $_ in some ruby, I curse because I have to remember how to look up what all those damn magic variables mean.
In python, I’d put things like the splat, the * and ** in argument lists, the conventional usage of “self”, all the operators and their magic __functions__, _ vs __ and probably a few more things like that in.
This thought is as old as (at least) the mid ’80s… when the “Real Programmers” essay was seen on rec.humor, containing this gem: Real Programmers don’t write in PASCAL, or BLISS, or ADA, or any of those pinko computer science languages. Strong typing is for people with weak memories.
So, yes, I agree that keeping all the types in your head can become tricky. If you’re writing a library in some language, then isn’t needing to reason about variable capture, garbage collection, and closure implementation on the underlying platform a sign that your language isn’t abstracted far enough away from the machine? I believe _good_ static types let you create more and more abstract entities, letting you code your most general ideas while hiding the details for you behind a compiler. Good dynamic typing let’s you jet past the productivity of those stuck with bad static typing (ie Rails vs Struts), but I suspect good dynamic typing might not approach good static typing (in some areas) for your reasons here.
Just a thought. There are of course no real answers to the debate.
I’ve often said — and I think it might even be on the video of the Ruby.MN presentation — that I’m astounded by people that do complicated functional programming in a purely dynamically typed language (e.g. Archaeoptryx). They simply have got to be smarter and/or much more patient than me, because I lose track and become so frustrated if I have to make changes: I always forget a spot I’m calling that function, and the bastard explodes at me. And then I fix it, and run my tests again, and it explodes on me a little bit further down in a slightly different way. And that’s the good scenario.
Jesse said that typoes and method missing exceptions weren’t a big problem in his life. For him, more power to him, and I totally see why a dynamically typed language is attractive. But they’re a big problem in my life, so I need the crutch.
And if that makes me stupid, so be it.
BTW, Hamlet, there’s a de facto tweet-up forming at CodeMash for F# people. I’m going to be part of that shindig, since you’ve sold me on F# and my frustrations with OCaml’s build system have outweighed my adoration of the language. Hope you can make it, too!
I am proud to say that I have absolutely no idea what a “de facto tweet-up” is. Code Camp (free, Twin Cities, 11 October 2008) has several F# related topics. Too bad you’re not here.
Wherever two or three are gathered with implied static typing, I am there.
And here’s the definition for you — a “tweet-up” is when a bunch of people on Twitter decide to all go do something, largely because of the hype about it on Twitter. The “de facto” part comes from the fact that nobody’s actually called it a tweet-up or acknowledged that it’s going on, but the effect is happening anyway.
In short: the tiny pool of people that are both F# junkies and Twitter junkies seem to be descending on Code Mash.
So God is a tuple- presumably with type ‘a * ‘b * ‘c?