Learning a dynamically typed language from a statically typed background

4 min readPublished July 05, 2018Updated May 02, 2022

After almost 10 years in the statically typed world, I switched over to exclusively writing dynamically typed code about 6 months ago. I started a new job leading a team that uses Rails and React, both frameworks that I didn’t have experience in. I had started my programming education with Java, detoured for a semester into Python, and got my first job writing C#. My career up to this point has been almost exclusively .NET with a little vanilla JS thrown in. Learning to code in dynamic languages has been a ride, and I’m still experiencing growing pains.

As a developer, I’m naturally language and tool agnostic. To be honest, I don’t get excited much by technology (I like solutions) so I never have strong feelings about Vim vs Emacs, React vs Vue, or even—gasp!—Windows vs Mac. And while diving deeper into dynamically typed languages, I’ve been trying to keep an open mind since I’m well aware of the bias 10 years of static typing could bring.

Let’s start with the difference between statically typed and dynamically typed languages. The difference is when the types are checked. In a statically typed language, the type is checked before runtime, which results in machine optimized code that is usually more performant. Dynamically typed languages check types during runtime while the code is executing.

As an aside, the static vs dynamic debate is often conflated with strong vs weak types or even compiled vs interpreted languages. While in a lot of cases, these debates go hand in hand, there are subtle differences.

A strongly typed language does not allow for variables to be implicitly converted to another (unrelated) type, whereas a weakly typed language will allow the implicit conversion.

A compiled language translates the code before runtime into the appropriate machine language, and an interpreted language translates code during runtime, usually delegating the translation to machine code to another program.

But back to static vs dynamic types. Here are my thoughts comparing the two and what I like about each.

Compile time errors

When coding in an IDE with a statically typed language, I'm alerted to typos and incorrect syntax right away. The code won’t run until I've fixed those items. I know some people find those red squiggles to be irksome and intrusive, but I find that they improve my workflow, because I spend less time running unit tests to find my typos and more time thinking about the structure of the code.

I also like the extra guard rails static types give me during refactoring. It’s harder to introduce unintended type side effects when refactoring in statically typed languages. If I rename a method or change its signature, the compiler will alert me to all of the places that I still need to update for the code to run again.

Design patterns

I’ve found that dynamically typed languages make design patterns and pattern recognition more difficult in every day practice. With Ruby’s duck typing, the interface of a class is almost completely obfuscated. Special attention needs to paid to coding to the interface to ensure that the code will run in all cases. Maybe I’m too accustomed to the explicitness of C#’s interfaces and people who start in dynamic languages find it easy to maintain a mental model of their classes, but I have to expend more mental energy in Ruby to make sure I’m coding to the interface than I did in C#.

I have also found that while working with a junior team who is interested in learning design patterns, it can be hard for those patterns to be visible within the code. Since the interface is implied, it can be hard to find the implementations or identify the places where implementation details are missing. Explicit interfaces and type safety help during the learning phase because it makes it very clear how the puzzle pieces fit together.

Related to that, I found that my Ruby code has a tendency to break object oriented best practices and trend more towards scripting. I know that OO has its drawbacks but I tend to be a purist if I’m writing OO code. It takes more mental effort for me to write pretty code when the language doesn’t care too much about types.

Generics

But, the switch to dynamic hasn’t been all bad. I used to spend an inordinate amount of time refactoring my C# classes to be generic and explaining generics to new developers. In C#, generics allow me to define a class with placeholders for the type of its fields, methods, parameters, etc. While it made my code more flexible, it did not make it more readable or understandable depending on the experience level of my team. Personally, I grew to love generics because they made me feel smart and accomplished but that’s usually the mark of an overcomplicated solution to a relatively simple problem. With Ruby and dynamic languages in general, generics are unnecessary. Since the language doesn’t type check until compile time, as long as the type can do what the code is trying to execute then the code will continue to run.

I think I’ll always be a static lover at heart, but expanding my horizons has been a good exercise for me as a developer.

Find related posts:Programming concepts

Well-Rounded Dev

Liked this post? Subscribe to receive semi-regular thoughts by email.

    I won't send you spam. Unsubscribe at any time.