Dynamic Languages are Wrong
Dynamic Languages
Are Just Wrong For 99% of All
Development
There has been a flurry of excitement over ruby and a
few other dynamically typed languages in the last few
years, driven mainly by rails on the server side and
javascript on the browser. Rails is a great project
and is far better for most websites than the J2EE
stack, but that unfortunately obscures the fact that
the language it is built on, ruby, while superior to
Java in many ways, just isn't the right thing for
most developers.
This is a relatively new opinion of mine. You can
see previous posts of mine where I'm very
enthusiastic about ruby. And, at some level, I'm
still enthusiastic about it. Many of the features
Ruby offers we've translated into GScript at
Guidewire and I'm forever in debt to it for that.
But that doesn't change the fact that I think it
is wrong for most developers.
In order to prove this somewhat ridiculous claim,
I'll compare what I consider the key features of ruby
and how GScript matches up in its statically typed
world.
Terseness
Ruby is incredibly terse when compared with many
statically typed languages. As a motivating example,
a simple enterprise-y method definition might look
like this (Note: I intentionally include
an assignment to a local var in order to contrast
with GScript):
def
employees_over_age( age
)
emps = @employees.find_all { | e
| e.age > age }
emps
end
Compare that with the five to ten lines of java you
would have to write to accomplish the same task, with
all the generics and types you would have to
annotate. I can't even bear to write it all out.
But let's look at the same function defined in
GScript:
function employeesOverAge( age :
int ) :
Employee[] {
var emps = _employees.findAll( \ e
-> e.age > age )
return emps
}
I'll admit, it is more code. But not a ton more and I
think most of the additional code is pretty
reasonable: you have to annotate in and out types at
the method level, which is good because you can
restrict your implementation details from leaking out
of the method. You have to put an explicit return
statement in the code which I actually find more
readable. And you have a slightly more verbose but
also more consistent syntax for blocks.
So ruby wins in terseness but GScript gets pretty
darned close even though it is statically typed.
Open Classes
Ruby
elegantly (or hackily, according to tastes) solves
another common problem: what if someone hasn't
designed a class to your liking, omitting an obvious
method or two, and you want to add this functionality
to it. In java, this has lead to a proliferation of
*Util classes: StringUtil, ObjectUtil, DateUtil,
FileUtil, etc. There are thousands of these util
classes filled with static methods floating around
java code bases. Some code bases are so large
(*cough* Guidewire *cough*) that there are many multiple
different versions of these utility classes, often
with subtly different names.
In ruby,
you can simply add a method to a class like so:
class String
def my_method()
puts( "Holy
Crap!!! I've added a method to Strings!"
)
end
end
These are
referred to as "Open Classes." Pretty neat, eh? Well,
it's so neat that we decided we needed something like
that in GScript, so we added something called
Enhancements. Here is an equivalent Enhancement:
enhancement
MyStrEnhancement :
String {
function myMethod() {
print( "Holy
Crap!!! I've added a method to
Strings!")
}
}
Not bad, eh? And because GScript is statically typed
and because we provide an IDE for it, you will get
very nice code completion when you hit '.' after a
string object, with your shiny new method available
and quite discoverable.
So I think GScript actually wins here by a hair
because it formalizes the class extension mechanism
in a new language construct, but both are just about
equivalent. The point is that you don't need dynamic
typing for this very useful
feature.
MetaProgramming
The really killer aspect of ruby and what lets rails
clean J2EE's clock in terms of ease-of-development is
the metaprogramming ability you have available. This
allows you to dynamically generate classes on the fly
based on, well, whatever you damned well please. This
is how ActiveRecord builds classes based on your
database schema, with no code-gen phase in the middle
to gunk up the works. You change the schema
and, *bam*, your class is updated.
It's hard to contrast this with GScript's alternative
in a succinct, blog-friendly way, but I'll try.
GScript has an "open" typesystem allowing anyone to
implement a TypeLoader and custom Types in java
(which underlies GScript.) That TypeLoader can
construct its types based on whatever metadata is
wants to just like in ruby. At Guidewire we use this
feature to build type systems on top of our web-UI
files, on top of our internationalization properties
files and on top of our OR layer, to name just a few.
This allows GScript code to access these resources in
a typesafe way but without any sort of a code-gen
step.
GScript's Type System, therefore, is very flexible in
much the same way that Ruby's is: developers can
implement their API's in terms of types that they
create dynamically rather than statically, based on
whatever metadata they like.
An Anti-Feature:
DSLs
A lot of developers are excited about DSL's in ruby
that take advantage of the flexible nature of the
ruby langauge. I'm not sure they are such a good
idea. I think developers, on balance, would prefer to
program in one sufficiently powerful language. I
would imagine this is especially true in the
enterprise space. I also think language design is
pretty difficult and putting a bunch of people to
work churning out specialized languages wouldn't turn
out as well as we might hope. I think there may even
be a biblical story about that sort of thing.
Rather than domain specific languages, I think there
should be domain specific type systems: as I
mentioned above we have type systems for our web
layer, our OR layer, our permissions layer, etc. and
it all works out grand. You have access to all these
resources in a single language, GScript, presented in
(one hopes) a nice API shaped by the dynamically
generated types of the particular TypeLoader.
No new syntax to learn, just more libraries. Nice.
So Why Are
Dynamic Languages Wrong?
Really it boils down to two reasons: tools and static
verification. The first reason is far
more important than the
second one.
Being able to hit '.' and see what the hell you can
do with an object is priceless, particularly on
larger projects. I know some people say "don't get
involved in larger projects" but, well, sometimes it
happens. Refactor tools (yeah, yeah, SmallTalk, blah
blah blah) are far easier to implement correctly with
statically typed languages than dynamically typed
languages. And total-program analysis tools become
possible. If the syntactic and expressive price is
low enough (and in GScript, it is) then there is no
reason to give up all this functionality for a
dynamic language.
Static verification has gotten a bit of a bad name
lately and we often joke at Guidewire that "well, it
compiled, it must be right." Still, when you are
making big changes and you have tens of thousands of
tests to run, it is really nice to have something
relatively fast (a compiler) point out things you
have obviously missed at compilation time rather than
waiting to run a series of test suites (even on our
distributed testing cluster, it often takes up to an
hour to hear back about every test after a checkin.)
But really, I could have stopped at '.'
Good code completion pretty much QED's the argument
in my book.