A Question to You: the Reader

A curiosity hit me today.

What is the value of dynamically typed languages in larger projects?

Do they have unique benefits?

Do they have unique negatives?

Load up the comments.

:)

-d

About Dru Sellers

Sr. Software Engineer at Dovetail Software.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Guido Tapia

    In 

  • David Campey

    One great thing about dynamic languages for maintainability and readability is that they make code a little more dry ( don’t repeat yourself) and every bit counts.

    Duck typing also makes for much easier code reuse.

  • http://jclaes.blogspot.com Jef Claes

    Looking forward to the replies.. #bookmarked

  • http://domenicdenicola.com/ Domenic Denicola

    Maintaining anything like “good practices” across the codebase requires a lot more discipline. Since types are not rigidly defined, it is too easy for one programmer to say “I’ll just add another member” or to stick a method on an object when convenient, then start using this to complete their own feature. This leads to all sorts of architectural warts as poorly thought-out tacked-on additions to the system compete for developer attention and maintenance resources. So… code reviews, I guess.

  • Matt Walker Jones

    How is this any different than a statically typed language?  You can still just “tack on another method” or “just add another member” to an object and create architectural warts in c#.

  • Anonymous

    Curious. How does dynamic typing make the code more DRY?

    Also, how does duck typing make for easier reuse?

  • Anonymous

    agreed. :)

  • Michael Paterson

    I think dynamic languages, while very powerful and sometimes fun to work with, make it much harder to maintain large code bases and can make refactoring a nightmare.

  • Anonymous

    any specifics? 

  • Christian Bjerre

    That depends on what they are used for. If it’s as a
    replacement for more traditional languages then it can be the wrong road to go
    down. Here you end up in problems as the code typically is less readable and
    less supported by major tool providers and 3rd parties. So your smart people
    end up writing stuff like grep and ReSharper … and miss profilers.

    One unique benefit is that they hide lots of the
    implementation details that are more computer science than domain knowledge.
    Thus they make a good language where the domain experts are not likely to enjoy
    thinking about memory and floating point operations.

    One unique cost is that maintain good and readable
    code is harder than more traditional languages. The fun part is to write
    something compact and clever… it does the job, but doesn’t read well 3 months
    down the road.

    Another cost is simply to get enough people with
    skills in the language. Worst case is that you have to train all yourself. Even
    skilled CS professionals need lots of time to learn these types of languages
    and some don’t really get the concept.

  • Christian Bjerre

    Yes. I agree on that one. You lack the overview as well as standard tools to help with things like that.

    Even a basic question like “what’s a good estimate for the cyclomatic complexity of this piece of F# code or simlar”.

  • Christian Bjerre

    Sure, but more people with recognise this when you’re doing the code review.

    And NDepend will spit it out the next time you run over your code base…

  • http://domenicdenicola.com/ Domenic Denicola

    In JavaScript at least, you can add another method/member to individual instances without adding it to the “class”.

  • Anonymous

    Duck typing softens the constraints for code reuse. For example, in C#, a method that wants to operate on a sequence would require the input object to implement the `IEnumerable` interface. A similar method in ruby would only require that the method have an `each` method.

  • Markus Johnsson

    Actually, in C#, you can operate on any object as a sequence using a foreach loop, as long as it has a GetEnumerator method and the object it returns has a Current property and a MoveNext method. OK, maybe not as simple as ruby, but it does /not/ require IEnumerable.

    The same goes for alot of other C# language features, such as LINQ.

  • Anonymous

    That was simply an example. Ok, it was a bad example because of the special foreach hooks hardcoded into the C# compiler. Substitute ‘IFoo which has a DoSomething method’ in my example and the argument still stands.
    And if you ‘well actually’ me with reflection invoke, you are missing the point. We know C# and ruby are both Turing complete.

  • Chris Tavares

    From what I’ve seen, the code in dynamic languages can be significantly shorter than otherwise for the same functionality. As a result, they’re useful in larger projects because, when done in a dynamic language, they’re no longer larger projects, but potentially medium or small projects again.

  • Anonymous

    How does ‘typing’ , static vs dynamic, make a project shorter? So much shorter that they move from a large to a medium project. Are you requiring more items to be ‘inferred’ through usage? Just curious how this is actually achieved. 

  • Anonymous

    Does a traditional language mean a static language? If so, why is a static language the traditional one? I do feel that tool support for dynamic languages is lacking. But to what degree can the tool makers really get at everything since the types CAN change at runtime? 

    I am curious why you think dynamic languages are harder to read? I know that I can find them hard to write because of the ‘cleverness’ that developers can employ. Sometimes I wonder if its my lack of understanding the idiomatic use of the language features or not. I know that I am a big proponent of making things explicit and I feel like this concept is some what eschewed in dynamic languages because of monkey patching and type extensiblity. 

  • Anonymous

    How did the project fall apart? How did closure bring things back from the brink?

  • Anonymous

    So, not having to build out the proper interface (in C#) and then have the class implement that interface is what makes objects easier to reuse? 

  • Peter

    I have almost nothing to add to the debate, except that anyone who wants to define “strong/weak/dynamic/static” typing should read this: http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html

  • Anonymous

    Yes. Eliminating coupling to Types makes it easier to reuse a piece of functionality.

    Consider the log4net object renderers example you recently blogged about. A consumer of Log4Net has to take a dependency on Log4Net, and couple their custom renderer to Log4Net’s IObjectRenderer type. That custom type is now tied to Log4Net, and can only be used with Log4Net, as presumably NLog or some other logging framework has its own Type you need to couple with.

    With duck typing, you create an object that responds to render_object (or ‘to_log’ – something that makes sense to all logging frameworks) and it can be reused, without change, with any number of logging frameworks. The community for a duck typed platform will develop conventions, like to_log, that all logging frameworks can embrace, making it much easier for you to reuse your code with these other frameworks, without having to write Adapters, etc.

  • Anonymous

    I agree 100% there. Having to build an adapter for each logging framework is such a PITA. I can easily see how in simple situations like that it would probably be pretty easy to develop a standard like ‘to_log’ or whatever. 

    Coupling to the method signature is much less restrictive then coupling to a Type + Method signatures. All though in more complex scenarios I wonder how easy or often this happens with more complex scenarios.

    Josh, you just started working on a dynamic codebase. How has that been more generally?

  • Chris Tavares

    Well, the delta between dynamic and static languages are a lot more than just the type system. Dynamic languages tend to have much higher level standard libraries, for example, which are much less code to do, for example, an HTTP request from Python than it is from C.

    In addition, the more flexible type systems make it much easier to do things like automatic proxies, which can result in significant code reduction.

  • Anonymous

    higher level standard libs, while prevalent in dynamic languages can and do exist in both language types. So I don’t buy that. That said, I do agree that you can reduce the size of the code base by not having to write proxy/adapter style code. I question how much actual reduction that is, but the point is taken. :)

  • lefthandedgoat

    Pros:  The compiler doesn’t hinder you.

    Cons: The compiler doesn’t help you.
    Do you like type systems and code to take advantage of them, or do you dislike them and want to avoid them?

    Do you think consider monkey patching a good thing or dangerous thing?

    Are you writing scripts, or writing systems?

    Is it just you, or are there many people on your team? 

    What how quality are the other members of your team?

    What does your team currently know?

    etc…

  • Anonymous

    thanks for dropping by. have you ever worked on a dynamic language project? The questions that you propose are very generic and are great questions. I would be much more interested in hearing about any experience you had working on a dynamic language project. :)

  • Anonymous

    nice, I will have to read that now. thanks!

  • Chris Tavares

    Kind of ironic you say that, since refactoring and refactoring tools were invented in Smalltalk, as dynamic a language as you can get.

  • http://twitter.com/thefringeninja João P. Bragança

    It’s fine in the beginning, but as the project adds more and more features it will eventually turn into a big ball of mud. Solution wide refactorings are almost impossible.

  • Anonymous

    What about the dynamic language makes them almost impossible?

  • Anonymous

    Agreed, i wonder why we don’t see more of that in languages like Ruby and Python?!

  • lefthandedgoat

    I write Ruby all day (not RoR).  Automated Web tests and the associated framework that sits on top of Selenium.  Traditionally I am a C# developer.  When I get to choose the language I write things in F#.

    I ‘get’ static typing and as a result I don’t care for dynamic stuff.  Yes you can throw some stuff together really fast which is awesome, and that is why I asked about writing scripts or systems.  You can also do some incredibly hacky ‘bad practice’ type stuff too easily.  You lose resharper so traversing your code is done basically with grep.  Rubymine is nice but nowhere near as powerful as resharper because it simply can’t be.  
    You HAVE to write unit tests because you don’t get all the up front checking that the compiler provides.  I make tons of stupid mistakes in a dynamic language that bite me in the ass, that simply would have not happened in C#/F# etc.  Working on other peoples code is more painful too because the number of ways you can solve a problem is greater and code traversal/refactoring is less precise.  Just as an FYI, I am not good at Ruby.  I haven’t figured out how to write idiomatic Ruby yet, so that part falls on my shoulder.I personally use F# because I get to type a lot less, like in a dynamic language, but I get type checking.  I am also madly in love with first class functions and other functionality that functional languages provide, but that is not a static/dynamic thing.

  • Anonymous

    Thanks for sharing. :)

  • http://devtalk.net Dmitri

    One of the reasons why I considered dynamic languages (but didn’t go with them) is being able to change the program’s operation without having to recompile. However, in the end, I realized that I can instead throw an in-process editor, compile a temporary assembly from that file alone, and then instantiate the type (there’s only one) in to the IoC container.

    If anyone’s interested, you can read more about it here: http://www.codeproject.com/KB/dotnet/dynamic-prototyping.aspx

  • Anonymous

    I do like the concept of not having to recompile. And there are some really cool tricks that we can do in .net to make it happen for us, sort of…as you know. ;) Hmmm, I will have to read the article. Thanks!

  • http://twitter.com/seejee Chris Geihsler

    I’m a little late to this discussion, but since I work in C# 

  • Anonymous

    I would say that we use interfaces to facilitate testability, we use an IoC to facilitate composition. IoC or DI Containers do not imply using interfaces at all.

    A strong contract (interface) does not go away with ruby, you just can’t declare it in the language itself. So you just have to remember to do it correctly, which isn’t that big of a deal, since you have tests to pin it down.

    You do need to swap the actual implementation at test time, you aren’t running your tests against the database are you? (To be fair, you state later that you can easily swap out core classes, so clearly the need to swap doesn’t go away) In ruby you have many ways to swap out, but I would still argue for any decently large system, you will build some kind of abstraction that will allow you to easily swap items in the same fashion my IoC container does.

    Placing an element like DateTime.Now behind an abstraction, I believe is a good practice (big surprise right, I mean I a static language guy). If its a part of the business logic process, I don’t believe that its an unnecessary abstraction.

  • http://twitter.com/seejee Chris Geihsler

    Thanks for the reply, Dru.

    Yes, the need to swap out behavior exists in any language. However, in ruby, you have much more flexibility in HOW you swap out behavior.

    Rather than injecting a collaborator in the constructor as you would in C#, in Ruby that collaborator can in many cases just be used as a class method (aka static method.) At test time, the implementation for that class method can  be redefined with new behavior. That fact that  another class was used at all is enough of a seam to swap out its implementation. From a Ruby point of view, all of the interfaces that exist in a C# project that have only one implementation are superfluous.

    Much of what an IoC container provides is building up large objects graphs automatically. With fewer injected abstractions, building up objects is not as onerous in Ruby. Other IoC tasks, such as finding and registering all implementations of IHandle are handled with a few lines of metaprogramming code in Ruby.

    That IoC containers aren’t really used in Ruby doesn’t mean that systems written in it aren’t sufficiently complex. Rather, the language itself provides you with enough flexibility to do it easily without relying on an external tool to help you satisfy the type system. 

    FWIW, the longer I work in Ruby, the more and more frustrated I become with hoops I am forced to jump through in C#.

  • Anonymous

    Agreed, in any dynamic language you will have more ‘swap’ type options. :)  

    I agree as well with one of the main purposes of a container is building up large graphs.

    That said, and it is a Ruby idiom (that I am not used to), I do miss seeing dependencies declared in a central place (ie in the ctor). 

    I never said that systems built in Ruby weren’t complex. Rather, I said in any sufficiently complex system you will build an abstraction of some sort that will allow for you to swap things out. :) What I was really getting after, was that you need to swap things in and out in big hairy projects (no matter the lang) and that you will build an abstraction to do so. 

    Agreed, any hoop that I can’t find a value in, is like stepping on a lego brick with no shoes. No Bueno. 

  • http://twitter.com/seejee Chris Geihsler

    Good point about not seeing all the class’ deps declared in one place. I definitely miss it from time to time.

    -1 for lego injuries. :)

  • http://www.key-logger.ws/ keylogger

    Thanks for the useful information, I really need it.