00:00:11.840
Good morning, good evening. Welcome to this presentation!
00:00:15.440
In this presentation, I'll talk about TypeProf IDE, which brings the modern development experience to Ruby.
00:00:21.680
Before diving into the main topic, let me introduce myself. My name is Yusuke Endoh, and my Twitter handle is @mameta.
00:00:28.320
I am a Ruby committee member working at Cookpad. Our company employs two Ruby core team members: Sasada, the author of the previous VM, and myself.
00:00:36.960
My main contributions to Ruby include the design and implementation of keyword arguments. I first implemented keyword arguments in Ruby 2.0 and was involved in the redesign for Ruby 3.
00:00:58.320
Additionally, I implemented coverage.so, which is Ruby's test coverage feature you may have used through SimpleCov, which uses coverage.so as a backend. My recent contribution is the implementation of TypeProf, which is today's topic.
00:01:31.680
Before we get into the main topic, I'd like to share a recent small improvement for Ruby called Highlight.
00:01:40.880
Consider this code: it attempts to extract a value from JSON. However, the type is misspelled as 'b-a-l-l'. When running this, an unhelpful error message is thrown. In the case of debugging, there are two possible exceptions that could arise, making it difficult to distinguish these possibilities solely based on error messages.
00:02:05.119
Since Ruby 3.1, the error message now provides more detailed explanations. For example, it indicates that a NoMethodError was raised when leading a Buzz. Hence, we can understand that 'leading' is returning without 'lila'. This feature was originally created to enhance debugging, and I completed the implementation. It is already included in the development branch of Ruby and will be released as part of Ruby 3.1 this December.
00:02:31.599
Now, let's move on to the agenda of this talk. First, I'll introduce TypeProf and some tools related to typing for Ruby 3. Then, I will discuss its integration with IDEs, such as Visual Studio Code. Finally, I will provide a brief explanation on how to use TypeProf for IDEs and conclude this presentation.
00:03:35.840
So, what is TypeProf? This is a static type analyzer for Ruby. The basic feature of TypeProf is typing the classes in Ruby code.
00:03:43.760
For example, consider this Ruby code that defines a User class with an initialize method and creates its instance. This code is quite plain, lacking any type annotations. When analyzed, it generates method signatures and outputs them in RBS format. In this instance, the generated signature indicates that there is a class called User that has a method named 'initialize', which accepts a string instance as an argument.
00:04:28.160
I will not delve into how TypeProf analyzes Ruby code; if you're interested, please refer to my previous talk at RubyConf 2019.
00:04:42.880
If you've heard about the type system for Ruby 3 before, you may be confused by the various names, such as TypeProf, RBS, Steep, and Sorbet. To clarify, RBS is Ruby's official type definition language. TypeProf and Steep are both static type analyzers for Ruby, while Sorbet is also a static type analyzer. Please remember that RBS is a dedicated mini-language meant to describe class and method signatures for Ruby code, while the others are names of static type analyzers.
00:05:56.559
Next, you may wonder why there are so many type analyzers for Ruby. This is because they hold different philosophies. The goal of TypeProf is to analyze Ruby code without requiring modifications to the language. In other words, we do not want users to write an abundance of type annotations in their Ruby code. Therefore, we put significant effort into typing friends. On the other hand, Steep and Sorbet require users to write type annotations either as comments or using a dedicated DSL language.
00:07:05.280
Steep and Sorbet typically report very little about existing code that lacks type annotations. This can be a bit cumbersome; however, if you add type annotations to your code, their error reporting becomes very accurate. Additionally, their approaches are notably fast—especially Sorbet, as it is written in C++, which is beneficial for users. Conversely, TypeProf's approach is slower, potentially leading to false positives and false negatives, which is a drawback compared to Steep and Sorbet.
00:07:56.960
TypeProf, Steep, and Sorbet all accept the same RBS files and utilize the same definitions for Ruby core features, such as Array and String. However, Steep and Sorbet use their own DSL language. For a long time, TypeProf did not have IDE integration. But this year, I focused on developing this feature, and it is finally functioning.
00:08:36.959
I previously showed you an example of TypeProf's use case. There are many ways to express Ruby code in TypeProf, but I will omit the extensive details during this presentation. The most notable characteristic of RBS is that it resides in a separate file from Ruby code. This design choice was made to avoid embedding any type annotations directly into the Ruby language.
00:09:27.360
Some people critique this design, arguing that separate files complicate things. However, the challenges can be resolved, in part, by using TypeProf for IDE, which I will demonstrate shortly. Next, I would like to introduce TypeProf for IDE.
00:10:32.800
TypeProf for IDE is a VSCode extension for Ruby that uses TypeProf as its backend. Assume you are editing Ruby code in VSCode—TypeProf monitors changes and notifies TypeProf in real-time.
00:11:00.320
For instance, TypeProf recognizes that an operation, such as attempting to add a string with a number, will raise an exception when executed and an error message will be reported to VSCode.
00:11:50.400
Now, let's demonstrate TypeProf for IDE. Here is some Ruby code that defines a User class and features an initialize method, accompanied by a simple test. Let's enable TypeProf. Notice that gray lines indicate method signatures. For instance, the signature of the initialize method indicates that it accepts a string and returns an instance of User.
00:12:40.080
Let's try calling the User constructor with an excessive number of arguments. An underline appears beneath the method call, and hovering over it will display a familiar error message indicating that too many arguments were provided.
00:13:16.640
Next, we can use the 'Go to Definition' feature by right-clicking a method name and selecting the corresponding option. This will navigate to the line where the method is defined.
00:13:20.640
Alternatively, you can click on the method name while holding the Control key. This feature conveniently streamlines navigation within the code.
00:13:41.280
Now, let's explore the completion feature. If we define a variable named 'user' and begin typing a method call, the editor will display relevant suggestions. For example, if I type 'user.s', it offers 'say hello' as a completed suggestion. The method 'say hello' returns a string, indicating that the variable has a string type.
00:14:31.520
Additionally, if you hover over any method, you will see a list of candidate methods. This confirms that TypeProf has accurately inferred the types.
00:15:21.600
The last demonstration involves hints for method arguments. If we write an open parenthesis after a method name, a pop-up will appear showing its expected arguments. This is particularly useful when the method accepts both required and optional parameters.
00:15:38.960
By indicating one argument, it shows a second optional argument. As you type arguments, the emphasized argument changes accordingly, which provides a clear context for the expected parameters.
00:16:10.960
In summary, what I wish to convey through this demonstration is that a modern development experience is feasible, even when working with non-type annotated Ruby code.
00:16:44.000
TypeProf displays informative descriptions by passing them into RBS files. I believe that this provides one solution to the issues surrounding typing in Ruby.
00:17:15.200
Next, I will explain how to configure TypeProf for your codebase. This slide outlines the steps needed to set up TypeProf.
00:17:40.320
First, you need to utilize the development version of Ruby since it depends on Ruby's internal API. Next, you must add TypeProf to your Gemfile as usual. Additionally, configure the RBS collection to enable TypeProf to read RBS files of any gems that your code uses.
00:18:08.160
Then, search for the VSCode extension for TypeProf and install it. Finally, open your project folder in VSCode. It should work, but keep in mind that TypeProf is still in development, and there may be cases where it does not work properly.
00:18:30.720
Unfortunately, TypeProf might not function correctly even when configured properly. There are two helpful tricks: one is to write a simple test in each file, and the other is to write obvious code. These strategies will help TypeProf in analyzing your code effectively.
00:19:16.640
In the example I demonstrated, there is a test at the end of the file, which helps guide TypeProf in making accurate type inferences by ensuring that the code is executed when the file is run directly.
00:19:47.040
Removing the test can cause TypeProf to fail in correctly identifying method signatures. This behavior arises because TypeProf's analysis relies on the presence of method calls to infer types involved.
00:20:11.920
This analysis method leads to some interesting behaviors. For example, if you mistakenly pass an incorrect argument type to a method, TypeProf will adjust the method to accept both expected and unexpected types.
00:20:39.300
While this behavior may be fitting for some situations, in others, it might be confusing. Thus, to accurately convey expected method signatures, you may need to write RBS definitions.
00:21:03.680
In conclusion, TypeProf aims to enhance the Ruby development experience without necessitating major changes to the language itself. TypeProf is still maturing, so I encourage developers to stay tuned for further improvements.
00:21:36.160
Thank you for your attention! I appreciate any feedback regarding TypeProf's integration and functionality.
00:21:49.680
I would like to acknowledge the contributions of various individuals who helped implement and enhance TypeProf, particularly Yuta Saito, who played a vital role in developing the TypeProf IDE as an intern at our company, QuickPad.
00:22:07.680
His contributions, including the go-to definition feature, performance improvements, and packaging the VSCode extension, were completed in just ten days!
00:22:33.280
Without his collaboration, the TypeProf for IDE project would not have been possible. Thank you again for attending this presentation, and I hope to hear your thoughts on TypeProf.