Scott presents some interesting thoughts on his new podcast about Dynamic vs Compiled Languages. He also mentions Castle with great enthusiasm, although I can’t help but think he didn’t go much further than a cursory look on our web site.
He foresees big changes in the Microsoft fence about dynamic languages. I’m not so optimistic. Exposing a compiler which can be extended is a great thing - that is all we’re seeing in C# 3.0 + some type inference - but having the kind of dynamic capabilities that Ruby (and other languages) has to offer is another thing. While I was researching and spiking on the Rook initiative the biggest challenges were on the abyss that separate the dynamic and static worlds.
An illustrative example. In Ruby you can do something like
class MyClass
def foo
"hello"
end
def method_missing
"whoops"
end
end
and use it like this
x = MyClass.new x.foo x.bar
which will output the whoops message. This can be simulated in a static compiled world, that’s true. My idea was to make the compiler smart enough to check two tables, the static scheme (in compile time) and a dynamic one (outputing code to make the checks in runtime). A pseudo code:
DynamicObject x = new MyClass() x.foo <-- early bound if (x.has_method(:bar)) x.invoke(:bar) <-- late bound else x.method_missing(:bar) <-- allow the class to handle end
Creating this kind on “hybrid” compiler is very difficult. The CLR doesn’t help you on anything (although now we have the dynamic methods), it would be better to create a runtime on top of the CLR and that should be a improvement on MS’ to-do list.
In Ruby you can also add or redefine method in runtime (well, as a matter of fact everything is in runtime!) like
class MyClass
def calculate
@x = do_calc()
def calculate
@x
end
end
end
This method redefines itself. Think about supporting this in a “static world”. I’m not saying it’s impossible, but sure it’s difficult. You can make the method implemention go to a separate type, or you can make callers dispatch to different method, once the definition is overriden.
Now consider a program in C# using a library in, I don’t know, Rook which (ideally) support this. C# is statically compiled, there’s no way to make the calls redirect to a “redefined method”.
This is just a pinch of the challenges involved in the construction of a truly dynamic language on top of a runtime that is, in essence, built for static languages.
About his consideration on TDD and test cases, I need to say that having tests cases and doing TDD are completely different things. TDD is a practice, it kinda forces you to define your API and contracts by thinking and implementing the tests fixtures. On the other hand you might be more comfortable adding test as you code the feature (not TDD) or when you finish them (not TDD). There are plenty of situations that I code test cases for new features I add to Castle after completing the feature. I’m clearly not doing TDD, but my test cases still have good assertions and good coverage.
Also, I couldn’t agree more that a dynamic language/environment forces you to have test cases for everything. I worked a product using RoR a long long time ago, RoR had too many bugs at that time so I decided to switch to .Net and start Castle on Rails. Yes, compilers make you think everything is fine when no errors or warning pop up in your face, and that’s not necessarily true. In a dynamic world there’s no such thing, so you have to make yourself comfortable with your code, and the only way is by coding test cases, plenty of them. I didn’t miss the compiler or types at all.
A truly dynamic language will quickly gain adoption in the .Net. I can’t wait to working (and even contribute) with one. The language alternatives can be quickly be label as C# with some neat things and improvements (boo), functional (nemerle), or something I’d never consider for something serious (ironpython). There’s a void.
August 17th, 2006 at 1:18 pm
Very valid point on TDD versus good tests. I did ‘mix’ the two, because I’m a fan of TDD. However, you’re right on - good test coverage, regardless of how it got written is the real key.
On the “methodmissing” stuff for C#, in C# 3.0 they add “extension methods” that give “bolt-on” style methods on a per type basis that can be either private or public.
Some details:
http://www.interact-sw.co.uk/iangblog/2005/09/26/extensionmethods
http://blah.winsmarts.com/2006/05/18/demystifying-c-30–part-3-extension-methods.aspx
http://www.developer.com/net/csharp/article.php/3592216
It’s not as elegant as Ruby, but it’s a start.
Microsoft is deeply (IMHO) invested in making dynamic languages work on the CLR and they will change the CLR to make it happen. IronPython proved a lot of those points. Also, remember that Wilco Bauer has Ruby compiling into IL and is working hard on that project.
Why wouldn’t you consider IronPython for anything serious? I got the impression from a number of MSFT insiders that they’d love to make it a first-class language in the IDE.
August 17th, 2006 at 1:38 pm
Thanks for the links, I’ll check them.
About ironpython, I hope they are kidding. I’ve spent like a day studying and debugging the source code (long time ago). It’s a total mess. There are plenty of compilers with a better design and better implementation. I personally like Groovy on this matter. The ironpython seems like a big hack with Microsoft name on the header… I truly hope it does not reflect the average quality of MS’ projects code.
I also didn’t like a statement from the author saying that ‘Ruby is smalltalk with a funny hat’, but anyway, my arguments are totally technical, not personal.
August 17th, 2006 at 5:55 pm
You can use trickery to redefine methods at runtime in C#, if you really want:
http://www.ayende.com/Blog/2006/05/18/MoreDynamicThanThou.aspx
While C# 3.0 has some interesting ideas, extention methods aren’t really useful for anything that you didn’t code before hand.
Adding something like IQuackFu from Boo to C# is something that I am willing to put someone (else) in prison for
I estimate the cost of adding it to the language in about two weeks max, and that includes documentation. I could add that to Boo in a weekend if it wasn’t there already.
But the more important issue is in the CLR itself. A class is not an object, and that can drive me crazy at times. I want something like Cx00 contraints.
August 18th, 2006 at 10:59 am
I’ve been thinking about this quite a bit from another direction. As I’ve read about how users are using Windsor it’s become increasingly clear to me that it’s being used as substitute for an approperiate dynamically typed language.
e.g.
* Switching implementations on the fly.
* Run time reconfiguring of components.
These are things that are all trivial in Ruby/Python etc - but require reasonably complex architectures in C# (mostly because of static interfaces - i.e. the lack of method_missing).
It’s interesting really - good programmers will always end up doing this because it’s the “easiest” way of building software - but look at the hoops we end up jumping through because of C# language restrictions. It reminds me of Greenspun’s Tenth Rule of Programming:
“Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified bug-ridden slow implementation of half of Common Lisp.”
(clarified as “that complex systems implemented in low-level languages cannot avoid reinventing and/or reimplementing (poorly on both counts) the facilities built into higher-level languages. Like garbage collection in OLE or keyword arguments in X.”).
See also - http://norvig.com/design-patterns/ - design patterns in dynamic languages.
August 22nd, 2006 at 3:06 pm
[…] The dotnetlanguages.net blog has made a nice review on the Lang.Net event. John Gough, pascal lover, author of Compiling for .Net, and the one leading the Ruby on the CLR work seems to share my thoughts that the CLR need to be dramatically improved to support truly dynamic languages. Excerpt from the report: The next presentation was done by John Gough, who talked about his work implementing Ruby on the CLR. First, he covered the essentials of Ruby. This really wasn’t an introduction to Ruby per-se; it was focused on the history of Ruby. He then moved to his Ruby.NET project, which he said is a compiler, “not an interop wrapper, or a…standard interpreter”. Specifically, he talked about the problems and issues he’s run into - the main one being “there is no authorative definition of the language semantics”. In Ruby, everything is an object with a well-defined class. However, Gough warns that Ruby classes shouldn’t be mapped to System.Type as class definitions can be changed at runtime. Gough talks about their own built-in Ruby classes (e.g. Ruby.Object, Ruby.Class, etc.). The method binding issues seem pretty complex at first due as methods can be attached to one object of a given class but not another, so even though both objects have the same class, they don’t have the same features. The tree that is generated to represent a class with a mixin is quite daunting - I don’t envy the work it takes to get Ruby to work on the CLR! He mentioned that he did not use delegates to implement the methods; rather, he defined a class called MethodBody to represent every method, which he said allows for method specialization. A lot of the implementation details hint at what Jim Hugunin talked about at Compiler Lab 2006 relative to IronPython. For example, Gough mentions a “activation frame” to support closures - IronPython has a FunctionEnvironment. At the beginning of the talk, Gough mentioned that the CLR needs a standard API to support a lot of the features that dynamic languages share, and this seems like one of those. I wished Gough would’ve had more Ruby code examples - it was hard to follow his talk at times when he talked about implementation details (a good example of this is when he talked about blocks and what happens during a return - I really couldn’t figure out what he was getting at). Gough ended with the current status of Ruby.NET. It currently does not have support for continuations and threads, although he states it passes “all 800-odd tests of the basic test suite”. He said there’s currently lots of room for performance gains, but right now his group hasn’t spent a lot of time on performance tweaking. He also mentioned some spin-off projects/tools from Ruby.NET, like a PE-file reader/writer (PERWAPI), a C# parser generator (GPPG), and a scanner generator which emits C# (GPLEX). […]