Static Typing

Roasting the Duck - A Talk About Ruby and Types

Roasting the Duck - A Talk About Ruby and Types

by Paolo "Nusco" Perrotta

The video titled "Roasting the Duck - A Talk About Ruby and Types" features Paolo "Nusco" Perrotta at the RubyConf TH 2022 in Bangkok, Thailand. The main theme revolves around the evolution of programming languages, specifically the shift towards integrating static typing in dynamic languages like Ruby.

Key Points:

  • Technological Evolution:

    • Technology evolves quickly, but sometimes we see a reversal in trends, particularly in programming languages.
    • There's a current movement back towards static languages after a previous emphasis on dynamic languages in the early 2000s.
  • Ruby's RBS and Static Typing:

    • Ruby has introduced RBS (Ruby Signature) to add static type checking while maintaining its dynamic nature. Many programmers are yet to embrace RBS fully due to its perceived complexity.
  • Understanding Type Systems:

    • The terms "static" vs. "dynamic" refer to when type checks occur (before or during runtime) rather than the language itself being static or dynamic.
    • Static typing helps catch errors before execution, while dynamic typing offers flexibility during runtime.
  • Strong vs. Weak Typing:

    • Strong and weak typing relate to how strictly a language enforces its typing rules, which is a separate concept from static and dynamic typing.
  • Integration of Static Typing in Dynamic Languages:

    • There has been a trend where dynamic languages incorporate static typing benefits, with TypeScript being a notable example, allowing type annotations that compile down to JavaScript.
    • In Ruby, Sorbet is employed to facilitate static typing while keeping the dynamic advantages, allowing for better documentation and tooling.
  • Benefits of Mixed Approaches:

    • Each typing approach has strengths. Static typing can lead to fewer runtime errors and better tooling, whereas dynamic typing provides flexibility crucial for distributed systems.
    • Learning and incorporating both approaches can enhance programmer skills and benefit software development.

Conclusions:

  • The ongoing debate in the programming community about static and dynamic typing suggests that both offer valuable advantages.
  • Understanding and utilizing both static and dynamic types can lead to more robust and maintainable software.
  • Encouragement is given to explore RBS for larger projects and provide clear type annotations for libraries to improve code clarity and user experience.
  • The key takeaway is that static and dynamic type checking are best utilized according to the specific requirements of a project, allowing developers to leverage their unique advantages effectively.
00:00:17.359 We almost always focus on how fast things change and how quickly technologies evolve. It's hard to stay on top of things. However, things do not always change in the same direction. There are aspects of computing, and programming in particular, that tend to swing back and forth over the years. If you disagree, it might be because you haven't been in programming for long, as the pendulum can take a long time to return. Eventually, someone in the room will say, 'Hey, this is how we did it 20 years ago!' One thing happening now is a shift back towards static languages after a significant push for dynamic languages around the 2000s. We're seeing a lot of effort to incorporate static type checking into dynamic languages.
00:01:08.700 Many people are excited about this trend, including Ruby, which is often regarded as one of the most dynamic languages. Ruby introduced RBS, a way to add some static typing into Ruby. How many of you are using RBS or at least have tried it? A few hands, not many. That's understandable because RBS can seem somewhat suspicious. It raises the question: Are we turning Ruby into a static language? It’s easy to forget the importance of duck typing in Ruby. So let's talk about types in particular because they are confusing. If you look up type systems on Wikipedia, you'll find many categories and terms. Unfortunately, many of these terms can lead to misunderstandings, such as 'static' versus 'dynamic'. We all use these terms, but the distinction gets hazy.
00:01:50.800 When we talk about static languages and dynamic languages, if I were to be a nitpicker—though I typically am not—I would argue that these terms don’t mean much in a meaningful way. It's not the language itself that is static or dynamic; it's more about the typing. Moreover, if I were even more pedantic—which, again, I'm not—I would say it’s about type checking. What matters is when your language checks the types. So, essentially, every modern language is going to check that the method you're calling accepts a string. The timing of the check is what distinguishes static from dynamic typing.
00:02:30.900 Static type checking occurs before runtime, meaning the language checks your types before executing the code. Usually, this is done by a compiler. Now, this doesn’t imply that you have to declare the types of variables upfront; it just means that someone needs enough information to check the types, typically requiring you to provide type signatures.
00:03:00.300 For example, in C#, you often see type signatures and type declarations clearly outlined. While in some cases, like deducing variable types, the compiler infers that the variable is an integer without explicit declaration. Some languages, such as Crystal, push the idea of type inference further. Crystal is statically typed but allows for type declarations to be inferred. That's static type checking as opposed to dynamic type checking, which occurs at runtime. Dynamic type checking, for instance, is common in Python, where you typically don't need to declare your types. In Python, the interpreter checks the values during execution and raises an error if a type mismatch occurs.
00:04:03.720 So what's the difference? Static type checking often leads to fewer runtime errors and can improve the development experience. It can make your code easier for the computer to understand, which in turn aids in better auto-completion, navigation, and tooling. On the other hand, dynamic type checking allows for greater flexibility—especially in distributed systems where you might be working with diverse data types. It facilitates tolerance to unexpected data, which is crucial in a networked environment. Overall, static and dynamic type checking serve different purposes and contexts in programming.
00:05:24.000 One major difference and a very confusing aspect is the distinction between strong and weak typing. Many programmers mistakenly use these terms interchangeably with static and dynamic. To illustrate this, imagine a hypothetical language that does no type checking whatsoever. In contrast, many modern languages do a degree of type checking, hence being more strongly typed relative to those that do not check at all.
00:06:57.360 The terms strong and weak typing concern how strictly a language enforces its type system once it is established, while static and dynamic refer to when the type checking occurs. It's also worth mentioning that while people use these terms, the confusion surrounding them often results in miscommunication. There has been a significant shift in the past decade towards adding static type systems to languages designed to be dynamic, aiming to combine the benefits of both approaches. Transpiling is one method of implementing static typing in dynamic languages, with TypeScript being a prime example.
00:08:21.840 TypeScript allows for type signatures while still compiling down to JavaScript, making it a remarkable tool for modern development. Another method is to use annotations, where you don't necessarily have a dedicated type checker built into the language, but you can still provide type information in the form of inline annotations within your code. In Ruby, this is facilitated by Sorbet, the most popular type checker for Ruby, which requires you to use annotations to define types in your Ruby code. This method maintains the dynamic nature of Ruby while incorporating static type checking through Sorbet.
00:09:40.320 For instance, if you define a class in Ruby, you can also create a parallel RBS file that outlines the type information without needing to include the actual implementations. This allows for the types to be checked while keeping the dynamic flexibility of Ruby intact. By loading RBS files into IDEs, developers gain enhanced documentation and navigation capabilities, improving their overall workflow within Ruby. The RBS system is a somewhat new experiment for Ruby aimed at merging the advantages of both static type and dynamic type checking.
00:11:09.840 Now, the question is whether such a shift is beneficial or not. Some might argue that it resembles static type systems too closely for languages like Ruby, which are traditionally built around dynamic typing. There is, indeed, an ongoing debate within the programming community about the merits of static versus dynamic type checking. To be candid, I find that this debate lacks depth and often devolves into unconvincing arguments for either side. Proponents of static typing often tout its ability to catch bugs early, whereas advocates for dynamic typing highlight its flexibility.
00:12:40.380 However, it's become increasingly clear that both approaches bring invaluable benefits to programming over the years. In my humble opinion, learning and mastering a mix of both static and dynamic languages can significantly enhance a programmer’s skill set. For example, static typing aids in more complex software development, suggesting that it can foster better tooling and overall development experience. Conversely, dynamic type checking is indispensable when designing systems that are heterogeneous in nature—like those that run across different environments on the internet.
00:14:25.680 Looking toward the future, I encourage you to explore RBS, especially if your projects are large and you find types confusing. Using tools that support RBS can improve clarity and maintainability. Similarly, if you're working on a library that will be consumed by others, providing clear type annotations will enhance user experience. Ultimately, mastering a blend of static and dynamic approaches can be quite advantageous.
00:15:57.600 As a final note, while these concepts may seem contradictory at times, they are not mutually exclusive. We should embrace both static and dynamic type checking as they are suited for different scenarios. The essential takeaway is that each approach fulfills a distinct role within the realm of programming, and it’s crucial as developers to leverage the strengths of both to create robust and maintained software.