Rust

Let's Talk About Rust

Let's Talk About Rust

by Yehuda Katz

In this video titled "Let's Talk About Rust," Yehuda Katz presents an introduction to the Rust programming language at GoGaRuCo 2014. The talk positions Rust as a solution to the challenges faced by developers transitioning from high-level languages to low-level systems programming, focusing on the theme of combining safety with performance.

Key points discussed include:

  • Introduction of Rust: Katz emphasizes the aggressive timeframe for the presentation and encourages attendees to consider it as a launch point for further exploration into Rust. He mentions an upcoming blog post focused on integrating Rust with Ruby on Rails applications.
  • Performance vs. Productivity: Katz criticizes the traditional view of a trade-off between performance and productivity. He illustrates how programming languages have evolved to enhance both aspects, using JavaScript as a prime example.
  • Safety and Control: Rust attempts to balance high-level language safety with low-level memory control. Katz discusses how prior programming languages bifurcated between safe (e.g., Ruby, Python) and unsafe (e.g., C, C++) and how Rust offers a middle ground.
  • New Era of Programmers: The language enables new developers to tackle low-level problems with confidence, promoting accessibility in systems programming.
  • Zero-Cost Abstraction: Katz details Rust's zero-cost abstraction principle, which allows developers to introduce abstractions into their code without significant performance penalties, contrasting this with the performance compromises often seen in other languages.
  • Iterators and Error Handling: The talk highlights how Rust's features like lazy iterators and compile-time type checks enhance productivity and safety, enabling high-performance coding without common memory-related pitfalls.
  • Ownership Model: The concept of ownership in Rust is explored as a safeguard for memory management, providing performance advantages without the burden of manual management that can lead to crashes.

Katz concludes that Rust's unique combination of high-level productivity and low-level performance makes it an attractive choice for modern programming challenges. The language invites a new generation of programmers to explore systems-level programming without the fear of crashing their applications, fostering innovative possibilities in high-performance applications.

00:00:12.620 So, 30 minutes is a really aggressive timeframe to introduce a group of people who don’t have much context for this. I might go a little fast—hopefully not too fast—but you should think of this talk as a jumping-off point for your interest in Rust. If you become interested, there will be a few things mentioned that you could explore further. I’ll be writing a blog post over the next few weeks that discusses how to specifically integrate Rust into a Ruby on Rails application. However, I won’t be discussing that today because it's a whole other topic. But if you leave this talk feeling that you really want to use Rust for something practical, that blog post will be a good resource. So keep an eye out for it on the Skylight blog.
00:00:48.480 I think a lot of people view programming languages through this quadrant grid. You may have seen when they announced Swift, for instance, Apple created one of these grids. Despite its silliness, I don’t believe Ruby is faster or more performant than JavaScript, and I don’t really understand these quadrants completely. Yet, people do tend to think about the world in these terms. If I were to give a talk about Rust and I weren't me, I might try to place Rust in one of these quadrants. The reason I’m showing this is that I think it’s a poor way to approach programming in general. The only constant in programming is change. Many people have a fixed idea of a trade-off between performance and productivity, imagining that if you gain a bit more productivity, you must sacrifice some performance. However, if we look at reality—let’s say in 2005—JavaScript was a reasonably productive language, albeit not very fast.
00:01:42.030 Fast forward ten years, and one would expect that since JavaScript hasn’t really changed much in terms of productivity, it hasn't gotten faster either. But that’s not what actually happened. JavaScript became a bit more productive with ES5 and ES6 features, and it became significantly faster. In reality, every programming language that sticks around tries to find ways to improve productivity without sacrificing performance. So, instead of moving down and to the right, where you lose performance as you gain productivity, every language is actually striving to move up and to the right.
00:02:33.080 When a language evolves significantly, or when a new language emerges that's markedly different from others, it can enable a new generation of programmers to accomplish tasks they couldn’t tackle before. JavaScript is a great example of this: it initially started as a slow language, but as JavaScript became faster and more user-friendly, it paved the way for a new generation of frontend developers to write back-end code. You could say, 'I don’t want my jQuery developers writing back-end code,' but that perspective overlooks the shifts in the programming landscape that empower large groups of people to do things they weren’t able to do before.
00:03:00.930 Rust aims to achieve a similar effect. It is a new programming language trying to empower individuals who may not have previously felt confident to tackle low-level systems programming. Prior to Rust, programming languages essentially fell into two categories: safe languages, where your program was unlikely to crash if there are no bugs in the compiler or interpreter—like Ruby or Python, thanks to their garbage collectors—and unsafe languages like C or C++, which provided more control over memory but required a high level of expertise to avoid pitfalls such as segfaults. Rust attempts to strike a balance by offering the safety of languages like Ruby without the mandatory overhead of garbage collection, allowing developers to manage memory directly when necessary.
00:04:26.000 Eliminating the possibility of crashes represents a huge shift in programming ergonomics. If you can program without fear of crashing, it fundamentally reshapes what's possible. This leads to my perspective that we should always look for shifts in the programming landscape. With Rust, the combination of direct memory control and safety empowers new generations of systems programmers. It invites individuals who may previously have shied away from low-level systems programming to engage.
00:05:37.970 Before Rust, many people identified with high-level languages. We talk among ourselves about why we find these languages productive. A common refrain in the high-level programming community is 'YAGNI', or 'You Aren’t Gonna Need It.' This often is true regarding features we don't need, but I argue that performance should be an essential consideration. Sometimes, better performance is critical. For example, when someone says they need 60 FPS, or are concerned about jank, real-time systems, or high-frequency trading, they need predictable performance and control that surpasses what a garbage collector provides.
00:06:11.829 Whenever anyone mentions needing less memory or is writing a cross-platform library like LibSass (which is meant to be embedded in various systems), it's apparent that performance matters. Additionally, as you delve into programming language internals, when reading any C code or understanding JavaScript JIT, the true value of performance becomes evident. Not having to concern yourself with performance is a significant blessing in many cases, but when performance does matter, your ability to do so effectively becomes complicated without having expressive tools in your programming language.
00:07:02.350 The point of a programming language is to allow us to communicate our intentions with other individuals regarding our goals.
00:07:42.550 As Dave Herman, who founded Mozilla research, articulates, when performance becomes crucial, it becomes part of the communication domain for you and your collaborators. You require a language that expresses your performance needs clearly. It is true that not every situation requires concerns regarding performance. If the performance requirements are negligible, investing time in Rust for a specific problem may not be the best use of your time. However, when performance truly matters, such as projects like Skylight, where I ultimately became immersed in Rust, that explicit communication about performance requirements is immensely beneficial.
00:08:58.560 Now, delving into what Rust is, I can discuss low-level performance, but I'd like to focus more on high-level productivity, which may resonate more with a Ruby audience. One crucial principle in Rust is 'zero-cost abstraction.' This concept may sound a bit like snake oil, but it means that when you introduce an abstraction in a programming language, if you're not careful, you introduce some minimal cost. As the complexity of your abstractions grows, like in large frameworks such as Rails, that cost compounds.
00:09:54.080 The goal behind Rust is to identify abstractions you can enable without introducing much—and ideally zero—additional cost. This ability allows you to write fairly abstract programs without suffering significant performance penalties. This is an appealing aspect of Rust: even if you don't take safety into account like in programming languages such as C, the challenges presented by their complexities make abstraction difficult.
00:10:42.370 To illustrate this idea, consider the example of the blank method in Ruby string implementations, which I pulled from ActiveSupport. This method checks if a string is 'blank.' In Ruby, performance dictates certain decisions that involve regex checks, dynamic typing, and class certainty. In contrast, if you were to implement similar functionality in Rust, everything is statically typed. For example, if we want to define a 'blank' method, we might create a trait called 'IsBlank' and define an associated function, akin to defining a class method in Ruby.
00:11:55.660 To implement the trait for a string, in Rust we specify that it returns a boolean indicating whether the string is blank. This immutability aspect offers more sophistication in Rust. The implementation can further extend to check against fixed-size arrays and even utilize Rust’s options for nil-checking. In Rust, when you implement traits for user-defined types, it adds flexibility comparable to how Ruby handles its `'blank?'` check. But in Rust, the elegance lies in how flatly the traits connect without invoking costly allocations.
00:12:38.390 For instance, in Rust, implementing a blank trait allows you to create generic structures effortlessly. Hence, similarities between Ruby’s setups and Rust’s allow for a progression in usability and efficiency. You can perform similar actions without having to perform unnecessary lookups or allocations, allowing the compiler to generate optimal, runtime-specialized code.
00:13:31.640 What I find compelling about Rust is the iteration process: Rust's iterators and lambdas encapsulate powerful expressive features without sacrificing performance. If you’ve written Ruby or JavaScript, you know the strength of using blocks to abstract various processes. Rust provides lambdas alongside iterators, which you may liken to lazy enumerators in Ruby. For example, when you create a range from 0 to 100 and apply filters or mapping functions, you find Rust allows clean and concise abstractions.
00:14:29.710 Like dynamic languages, Rust enables you to operate at a high level while minimizing memory usage. The iterators in Rust are lazy as well, garnering no intermediate objects and avoiding additional allocations. Each operation of 'map' or 'filter' is treated as generating a specialized version of the underlying method or function based on the type of data it consumes, leading to efficient performance execution without the runtime complexity found in other languages.
00:15:15.050 Another interesting consideration is Rust's approach to error-checking and safety features. Rust's design assures that when you define a method that reads a certain type, it is specialized for that type at compile time. This process enables the compiler to optimize function calls without sacrificing performance or safety. It does not require additional memory for virtual method tables, as often seen in other languages. Its generics facilitate a powerful blend of flexibility and performance while keeping memory concerns minimal.
00:16:15.690 Reflecting upon the combination of the zero-cost abstractions, iterators, and traits, Rust offers high-level productivity alongside the robustness and performance of low-level systems programming. These features present a unique capability for programmers to engage effectively with systems programming across various applications.
00:17:13.160 As I previously alluded, the safety embedded in Rust is pivotal for programmers hesitant about delving into low-level programming. Ownership, in particular, is a core concept—it delineates the rules governing pointers and memory management. While this concept appears daunting at first, it safeguards robust memory efficiency that averts many common pitfalls found in languages like C or C++. When you follow Rust's ownership principles, you gain correct and efficient programs that are deeply engaging.
00:18:34.520 Returning to the importance of Rust in today's programming landscape, it opens the door for programmers who would otherwise hesitate to approach low-level coding—like myself. My previous experiences with C programming often led to anxiety about memory management, but Rust alleviates these concerns by enforcing strict ownership rules. With Rust, you can address performance-related areas effectively and experiment without fear of crashing your application.
00:19:39.900 When performance becomes a priority—for instance, in high-frequency trading applications—this ability to control your memory management without overhead becomes a competitive advantage. Ultimately, Rust presents a compelling framework to a new generation of aspiring systems-level programmers, erasing prior hesitations in tackling low-level code. It serves as an invitation to these developers to ask themselves what new possibilities they might unlock with this power.
00:20:52.660 In conclusion, I believe Rust's integrated safety and productivity features stand out in the programming landscape. The language encourages the integration of systems programming with a depth previously reserved for only the most experienced engineers, enabling the exploration of high-performance applications without sacrificing safety. Thank you for your time.