Dynamic Languages: A Separation of Concerns

I saw Nick Muhonen give a talk on the new language features in C# 4.0 last night at the Portland-Area .NET User Group. He did a good job in spite of the constant questions I asked. He showed one example that I found especially compelling:

object GetConfig() {
  return new {
    WindowSize = new Size() { Width = 100, Height = 200 },
    ConnectionString = "...",
    ...
  };
}

Of course, you wouldn't hard code settings in your application -- you'd load them from somewhere (ideally a database, but that's another story : ). Anyway, in C# 4.0, I can write code like this:

dynamic config = GetConfig();
mainWindow.Size = config.WindowSize;
...

Notice the use of the dynamic keyword -- this means I don't have to know the type at compile-type -- I'll check for the WindowSize property at run-time ala .NET Reflection, COM IDispatch or VB "Option Explicit Off". Of course, this is the cornerstone of all dynamic languages, e.g. Perl, Python, Ruby, etc. These languages have been gaining in popularity for the last few years and I didn't understand why. Tim Ewald, my close friend and compadre, kept trying to explain it to me, but I'm just too slow to get it and I didn't ''til last night watch Nick do his thing. It wasn't looking at the code that Nick typed that made the point for me, it was looking at what he didn't type.

When writing dynamic code, there is no requirement to define a type.

That is, when I inevitably add another property or 10 to my app config, I have to write code to use the new properties, but that's all. I don't have to write a class and I likely don't have to update the save/load code either, because it's also going to be dynamic and just expose whatever data is part of the serialized config. Or, to put it another way:

When writing dynamic code, I only have to write the part I care about.

In the case of dealing with application config, that's about 2/3rds of the code I no longer have to write. Of course, this isn't a new idea -- Stuart Halloway has been talking about embracing essence (the code you care about) and rejecting ceremony (the code you don't) for a long time now. It just took Nick's concrete example for me to understand it.

And not only does this make dynamic code good for reducing the code you type, it always makes it good for the code you're generating, e.g. COM interop assemblies, database mapping code, XML mapping code, etc. In general, I find that most of the code we have generated for us in the .NET programming environment is code to map to foreign type systems, i.e. COM, databases, XML, web services, etc. With dynamic languages, you can write that code once and just use it. In fact, in C# 4.0, there's no need to use Primary Interop Assemblies (PIAs) anymore -- those can just be mapped to a sub-class of the "DynamicObject" type that .NET 4.0 ships to provide that dynamic mapping bridge.

When writing dynamic code, you don't need generated code layers to map to foreign type systems.

This means I don't have to do the mapping to databases per query or to XML per XSD -- I can just have an implementation of DynamicObject, point it at my configuration and go -- no muss, no fuss. Of course, purely dynamic languages have a construct for DO built right in, so it's even easier.

Around the table after Nick's talk last night, someone was complaining that with purely dynamic languages, I give up the benefits of the compiler doing static type checking (I think it was Nick : ). I argued that this was a good thing. The compiler is really just one kind of unit testing -- it's testing names. It can't do any of the other unit testing you need done, however, so you still need unit tests. What that means is that, with static languages, you've got some unit tests separate from your code and some baked into the code via types, casts, etc.

When writing dynamic code, you can separate unit tests completely out of your code.

Of course, as software engineers, we already know that separating concerns leads to better, more readable and more maintainable code, which is why we've long separated our applications into tiers, separated our view from our data, our interfaces from our implementations, etc. Dynamic languages let us do another complete separation of concerns with regards to unit tests that static languages don't allow. In a static language, the ceremony is required, thereby obfuscating the essence.

And all of this is great except for one question -- how do I get my list of possible code to write when I type "." if I'm using a dynamic language or dynamic features of a static language ala C# 4.0?

When writing dynamic code, I don't get Intellisense.

My name is Chris Sells and I'm an Intellisense addict. Admitting I have the problem is the first step...



Comment Feed 9 comments on this post

Luke Hutteman:


Not only do you not get Intellisense, it also makes refactoring virtually impossible to implement correctly in all cases.

Those 2 downsides together are enough for me to continue preferring statically typed languages for now.

I do find it interesting that C# 4.0 will allow for combined static and dynamic typing though, allowing someone like me who prefers statically typed languages to use static typing most of the time, with dynamic typing used only in those few cases where it may allow for more compact code or makes that code just more readable, maintainable, intuitive and well... dynamic.

Wednesday, Jul 8, 2009, 9:45 AM


Daniel Pratt:


After spending a lot of time looking at Haskell (a functional programming language), I've come to realize that "type verbosity" does not necessarily go hand-in-hand with statically typed languages. Haskell is perhaps more strongly typed than C#, yet most of the code looks very dynamic due to the lack of explicit typing. I find Haskell's handling of "generics" to be particularly elegant compared to .NET languages.

Wednesday, Jul 8, 2009, 11:09 AM


Jeremy D. Miller:


You know there are IDE's that have Intellisense for dynamic languages right? That's not quite the black and white situation it was a few years ago.

Wednesday, Jul 8, 2009, 12:27 PM


Matt Katz:


There is, in fact, intellisense for ruby. After all, the code has to work, right? And the objects, they get defined, right?

Aptana and netbeans provide intellisense in the IDE, and there are a few automated refactoring tools out there.

I imagine there are similar tools for other dynamic languages. What is interesting is why there are so few users of the intellisense and automated refactoring tools.

My suspicion is that the communities have emphasized some best practices, plus there is much less language cruft to type.

Wednesday, Jul 8, 2009, 12:52 PM


Nick Muhonen:


Thanks for the post Chris.

Two strange things occurred after the discussed presentation given by me:

1) Deduced via an email response, I convinced someone inadvertently that I am the 24 year old second coming of Scott Hanselmann/Rick Strahl by my presentational "fabulousness"- and have a shining career ahead of me. (Hint- I am really 37- and my career now is actually my career ahead of me- and I probably have one less fan now that that the cat is out of the bag :( ).

2) Deduced from reading this great post, I have inadvertently helped Chris Sells find new religion -albeit, I must admit myself, arguably sound religion- in dynamic language development.

So here's my obligatory windy counter argument to the points discussed:

I have always been a RISC over CISC guy, meaning I like to have as little rules/features as possible imposed on me in a platform when creating something (Another similar analogy: I prefer clay to legos). Yet still when it comes to middle tier dev, my day to day bread and butter, even after Chris' incredibly compelling argument- I still prefer statically typed languages.

This is because I am true pessimist at heart. Yes, I do hope for the best out of my dev comrades, but I expect the worst and try to judge as little as possible- contextually meaning, in my experience, unit testing (TDD/BDD) as a standard operating practice is still slowly making inroads, even some 10 years after the "Agile/XP revolution", if not occasionally abandoned completely because of fanaticism (yes, although rare, I have seen this happen!). And I expect that to continue. Reason: statistically speaking- developers of all ages, shapes and forms are generally independently thinkers who like to not follow or break "the rules"(ie non automated policies)" (refer to the "Agile/XP revolution" as an example). The philosophy of XP/Agile and TDD worked when better when it acted as an emotional/logical rebellion against Waterfall and its evils as the dominant methodology. It seems everywhere I contract to now- except maybe the public sector- Agile is now the dominant methodology, I think you're getting the point here...

So I still like to know that when complex types in particular are being passed to a method, I can define an API contract that is both self documenting (VIA intellisense- yes I too am an addict) and regulating in how types are passed- particularly complex data types that have many specific fields and methods. This way- team members can know immediately- to a very basic degree whether they are using this correctly or not, and given compiler guaranteed rules to do so without a single test to be written. Unit tests rely on commitment- the quintessentially over quoted "80/20" rule insures that this will never happen for 100% of the developers in the "world" team- professional or not. I like to have some personal guarantees for sensitive highly utilized server code that people might expand or refactor in the future when I am not there. I hope it will have some robustness built in for the users who depend on them, even with out unit tests, just by well crafted restrictions of the defined server architecture.

I think is a great discussion, and after reading the posts I can see the dynamic view- they are good arguments as well, whether I agree with them or not. And, last plug, despite my stated pessimism, please do code with automated unit testing or some BDD- it really does save you time/money in the end!
 

Thursday, Jul 9, 2009, 3:07 AM


Chris Sells:


I never said I was a convert to dynamic languages, Nick, only that I now understand the attraction. Still, I think I'd like to try to use C# 4.0 as a purely dynamic language and see how it goes.

Thursday, Jul 9, 2009, 7:17 AM


Nick Muhonen:


I stand corrected and relieved.

Thursday, Jul 9, 2009, 2:58 PM


Tim Ewald:


Hallelujah!

To be pedantic, you do still define a type, albeit an unnamed one. In some of the languages you mentioned, like Ruby, you would still name the type, or use a hash. (And once you have a direct syntax for hash, you'd be surprised how many types vanish from your world).

The observation about testing can't be underestimated. I've worked on systems where 2/3 of the type abstractions were to support unit testing. This is a direct result of working in a language where I have to name all my types, have typed references, and can only substitute mock behavior by types related by (interface) inheritance.

Yes, intellisense is an issue. I haven't missed it. (Note too that some IDEs are providing it now - Ruby in Steel, which is VS based, is rumored to have very good Ruby intellisense.) If this feels like a big price, trade it off against the big step forward for testing.

The danger for you now, of course, is that you might want to use this a lot. One of the downsides of C# evolving in this direction, instead of starting there, is that you can't mix this feature with other useful ones, like lambdas. Since the lambda syntax uses type inference to know what sort of delegate to build, you can't use dynamic references with lambdas (at least the last time I looked). It's a slippery slope! :-)

Tim-

Friday, Jul 10, 2009, 8:12 AM


Craig Andera:


My IDE (emacs w/ SLIME) and preferred dynamic language (Clojure) provides completion in both the "Intellisense" manner (hints like function names and arguments based on knowledge of the program structure), but also in a more important manner - based on what's in the other text buffers I have open.

So I might be typing in a variable name like "numberOfIterations", I've typed "num" and I just hit the hotkey and it'll cycle through "numberOfIterations", "numericIndex", "numbSkull", etc. All based on what else is in my code.

This turns out to be super useful in practice, and emacs does a pretty good job of guessing which one you want first. If not, it's trivial to cycle through two or three more guesses. It's called dabbrev-mode, and it would be nice if VS added it.

As for the question of refactoring, this is where Lisps like Clojure really shine. Because it is nearly trivial to parse program text (homoiconicity FTW), it gets really easy to write tooling that consumes your program and does interesting stuff with it.

As a final note to this only semi-coherent set of ramblings, I have no idea at all why you would want to write dynamic C#, unless you're a masochist. It's roughly akin to discovering that band saws are cool because they're good at resawing, and then deciding because of that, you're going to do all your resawing on a table saw because it's what you have. It'll work, but the main thing you're going to discover is that it sucks when you use the wrong tool.

Sunday, Mar 21, 2010, 5:18 AM





comment on this post

HTML tags will be escaped.

Powered By ASP.NET

Hosted by SecureWebs

Mensa

IEEE