00:00:00.160
Hi everyone! Thank you so much for having me here. I'm absolutely delighted to be here.
00:00:05.359
I'm going to spend a few minutes talking to you about static typing. It's a big subject, and I can only really sketch it here, so I've written up a more detailed version of this talk on my blog. If anything I say sounds interesting, you can find out more at that URL. It will be on the last slide as well.
00:00:11.520
In November, I was at RubyConf in San Diego, where Matz used his opening keynote to talk about what might come next for Ruby. In particular, he said that Ruby 3.0 may happen in the next ten years and that it might see some new concurrency features, a just-in-time compiler, perhaps the LLVM JIT, and static typing. That's right, static typing!
00:00:30.800
A lot of people were worried when they heard that, and that's understandable because in the Ruby community we don't get much direct exposure to static type systems. They immediately make us think of languages like C and Java. So, I want to unpack Matz's remarks a little bit and provide some context and vocabulary around them in the hope of encouraging a productive conversation about static typing in Ruby.
00:01:05.439
To cut to the chase, my interpretation is that Matz was proposing three specific ideas beyond just ‘Ruby should have static typing.’ Those ideas are structural typing, implicit typing, and soft typing. These ideas provide an important degree of subtlety beyond the term 'static typing,' which would steer the language toward something very different from just Ruby that feels like Java. If you already know what these terms mean, I don't have much to tell you, but if they're new to you, I'd like to convince you that they represent interesting ideas that go beyond the features of the static type systems you might have used in the past.
00:01:43.520
As a way to get you into this subject, I'd like you to think about how computers handle values. Imagine you could crack open your laptop or your smartphone, zoom into the microscopic level, and look deep into its memory to see what was stored there. You'd see something like this: an undifferentiated soup of ones and zeros, binary data. What do those patterns of ones and zeros mean? Well, you can't tell just by looking at them; they don't have any inherent meaning, at least not an interesting one.
00:02:03.360
At the lowest level, every value inside a computer looks the same—just this pattern of ones and zeros. But when we write code to manipulate a value, we usually have a specific interpretation in mind. A given pattern of ones and zeros being used by our program might represent an unsigned or signed integer, a floating-point number, a letter of the alphabet, or the integer address of a memory location where we can find some data structure, and so on. The primitive operations inside a computer generally just assume that the values they're given are supposed to be interpreted in a particular way.
00:03:01.200
This brings us to a fundamental problem in constructing computer programs: how do we, as programmers, avoid values being accidentally misinterpreted? If we store in memory some data that represents an unsigned integer and then later retrieve that data and accidentally use it as though it represents a floating-point number or a pointer, the result of our program is going to be junk.
00:03:40.879
The type systems are a programming language technology designed to prevent this kind of error. The idea is that by incorporating a type system into a programming language, we can reduce or perhaps eliminate completely the ability of the programmer to accidentally write code that misinterprets a value. Broadly speaking, a type system is a set of rules that expect some of the things in our program to have pieces of metadata attached to them.
00:04:08.400
This brings us to the general idea: we want to take the implicit information about value representation out of the mind of the programmer and make it explicit metadata, so that it can be systematically checked for consistency with the operations used on those values. The design of type systems can get very complicated, but there are three big obvious questions to answer: first, where does the metadata go? What are the things in your program that it gets attached to? Secondly, what does the metadata look like? What information does a type tell us about how to interpret a value? And finally, where does that metadata come from? Who decides how values should be interpreted?
00:05:21.440
To answer the first question, there are three main answers that we see in the wild. The simplest possible answer is that the metadata goes nowhere; we don't have any metadata at all. This is the case for assembly language and BCPL. Programming languages that do this are usually called untyped languages, while a certain kind of person refers to them as uni-type languages. Another popular answer is that the metadata goes on values, meaning our actual in-memory representation of values includes extra information about how they should be interpreted.
00:06:32.080
This is how Ruby works. Every Ruby object begins with a structure that contains flags, allowing the programming language's operations to check it to make sure they have been given compatible arguments. Lastly, the third answer is that the metadata can be attached to pieces of source code, as exemplified by languages like C, where keywords like 'int' and 'void' declare the types of variables and functions.
00:07:40.880
So, those are the three main ways of answering the question: either there is no metadata, there is metadata on values, or there's metadata on pieces of source code. If your program misinterprets the value, a static type system can alert you to your mistake at compile time, while a dynamic one can do it during execution. An untyped language will never tell you; it will just silently produce garbage.
00:08:57.120
All else being equal, safer is better. The second big question is about what the metadata looks like, and this is independent of whether the types are static or dynamic. It’s about deciding what information we want to record regarding how to interpret values, regardless of where we record it. Most type systems you've seen are nominal ones, meaning the types are just names, such as 'int' or 'void.' However, an alternative represents that instead of types being names, they can be structures, and implicit to that idea is that you can compare types by comparing their structures and deciding whether they're compatible.
00:10:21.120
This raises a fourth question: where does that metadata come from? In statically typed languages where information must get attached to code, the most obvious answer is that the programmer provides this information by explicitly annotating the code. Alternately, we could let the computer, usually meaning the compiler, add type annotations itself through a type inference algorithm that works of pieces of information and joins it together—a process sometimes known as implicit typing.
00:11:45.840
The point of this talk is to unpack what Matz said and explore what Ruby 3.0 might look like through speculative examples of code, which Matz showcased during his keynote. He sets the variable 'a' equal to 1, commenting that the type of 'a' is integer. He also defines a method called 'foo' that requires x to have a method called ‘to’ and shows two uses of 'foo', one valid because the object passed in has a 'to' method, and the other invalid because it does not.
00:13:59.360
He states at one point that a type is represented by a set of methods, noting that you could use a class name as shorthand. Taken together, it’s clear that he’s discussing Ruby’s type system being static—beyond just dynamic metadata—and that it will use structural typing, not solely nominal typing. Instead of checking just what class an object is, the focus will be on what messages a value responds to. This preserves some of the feel of duck typing.
00:15:19.040
The real challenge lies in how to implement this implicit structural static type system while ensuring that it integrates well with Ruby’s open classes. Matz refers to a paper from 1991 describing soft typing, which attempts to apply a type inference algorithm to reconstruct static types at compile time and inserting dynamic checks where type reconstruction fails. This could assure that values are interpreted correctly by raising an exception at runtime if they're not.
00:16:17.680
While intriguing, I hold reservations about the soft typing paper since it outlines an idealized functional language that doesn't account for Ruby's complex features. It also appears to lack structurality and indeed doesn’t hold the promise of safety per se. Given that Matz emphasized the lack of need for static typing from a performance perspective, I remain unsure of what soft typing would offer Ruby.
00:17:46.080
As the Ruby community considers static typing, we face a significant challenge in bringing the safety and performance benefits to Ruby while preserving its flexibility and friendliness. Personally, I believe it's possible, and it's vital for Ruby to maintain its competitiveness over the next decade, especially as languages like Rust and Flow are rising due to enhanced static type systems.
00:19:27.360
In conclusion, I hope the insights and points I've discussed today can spur conversations within the Ruby community toward a productive exploration of static typing. Thank you very much!