A colleage recommended, last week, that I look at the Boo programming language.
There are certainly some lovely features. I’ve been writing lots of F# recently, and have developed a great love of Type Inference. Similarly, lambdas (albeit fairly immature ones – they look like anonymous delegates from C# 2) and their logical offspring, first-class functions.
I love the idea of a compiler that checks your spelling! It can be a maintenance nightmare to clean up after a colleague who can’t spell, and it’s quite necessary. FxCop helps if you make it a post-compile step, but it’s fiddly to do, and takes some time to reflect over your assembly. Much better to have something analyse your source.
But I can’t bring myself to like duck-typing. Simply put, duck-typing is an attempt to escape the strictures of static typing in a static language. You’ll hear enthusiasts saying things like “it’s my <thing>, why shouldn’t I be able to treat it as a <other-thing>?”. Well, the point is that it’s not your thing, it’s the compiler’s. And the reason you can’t treat it as a other-thing is because it isn’t one.
It’s true – I often find myself saying to the compiler “Just trust me for a second, ok?”. I’m sure we all do. My current gripe is that circular-dependency hell you can get into while editing a XAML document when the code behind (in the generated code) is incomplete. The XAML won’t pass type-checking because the generated code is incomplete, and the code won’t compile because, well, you can guess. Sometimes you just want to turn off a bit of time compiler, or do two runs for the thing to compile, like you do when you want a Table of Contents in your Latex document. On second thoughts, maybe not!
There are all sorts of issues of self-documentation, of course. Languagues like C# make it fairly simple for the next guy to work out what your intentions were from the code. F# moreso, I would argue, and part of that intention inference is knowing what kind of things you’re dealing with.
It’s slow, too – the CLR is implicitly statically typed (the DLR does a compilation-and-memoization stage at runtime as functions are called, so at the moment of invocation your method is static), and to get past the type checker your functions have to be called using reflection. Not Pretty.
User-defined languages extensions? Silly! Firstly, you have to know about (and code to) the internals of the language compiler to introduce something to the language. At first glance it seems like quite a nice model – we’ve sometimes wished that we could get a hook into the compiler to play some games with the syntax, but you lose the benefits of the IDE if you end up introducing language extensions. Unless, that is, the language service uses the language extensions you’ve defined, which I doubt.
Once you put some thought into it, though, most of the things you’d like to see in your favourite language either already exist in another one, or are so common that everyone would define them as Boo macros, at which point they should probably be introduced into the base language anyway. If your favourite language isn’t evolving, maybe it’s time to drop it?