For the past few years I have been interested in learning more about the Rust programming language. It has generated quite a bit of buzz and is often touted as a favorite amongst those who choose to use it. I like to learn a new programming language every now and then. Especially if the language can teach you a new way to think about how to program. For example, I picked up Haskell a while back and it really helped me dive into the deep end of functional programming. It pushed my understanding of how to use functional programming ideas in my usual day-to-day coding.
It’s been a while since I wrote any Haskell code and I am long overdue to start a new learning experience with a programming language. I decided I’d give Rust a go and see where it leads me. I think it has a lot to teach me and I’m excited and ready to learn.
Rust is described by many as a low level systems programming language. You get a high degree of performance and safety out of the box. You do end up paying for that performance, safety, and productivity, in the form of a steep learning curve.
With Rust, there is a lot to learn. I have been working on learning Rust over the past few months and I still feel like I’m just scratching the surface.
Why spend all this time learning Rust in the first place?
For me, I’ve been really wanting to get back to a statically typed, compiled, native language. I’ve been using Python as my main programming language for a long time. Python is great, but for anyone who has used Python for complex projects, or in production, its runtime dynamic-ness can come out of nowhere bite you when you’re least expecting it.
I like having to think about the types I’m using. When to use which ones, and how to do that effectively.
I’ve also been really drawn to more performance oriented languages lately. It seems like software is unbelievably slow these days. Computers are blazingly fast, and yet our applications still feel sluggish. I think there is a lot of performance left on the table and too many applications that are overly hungry for system resources. It would be nice if we made better use of the hardware available today.
I really like C, but it’s missing some modern comforts. C++ just seems overly complex, packed with modern features that are more trouble than they’re worth. I want to see if Rust can provide a modern feel without throwing in the kitchen sink. So far, I think they have done a decent job.
One of the other forcing factors for taking a look at Rust, is just how many other developers are excited about it. I know, like moths to bright light, us developers get drawn to shinny new tech. Sometimes that light turns out to be burning flames that hurt, more than help. We want to try to learn it all. Of course, learning everything is unrealistic. So, you end up developing some sense of when it’s worth it to learn new tech or not. I don’t know if I’ve fully mastered that art yet, but I have a feeling that Rust will be well worth the time spent.
I want to feel comfortable writing programs in Rust. When starting, I knew I’d need a good strategy to make sure my understanding of the language, is solid. For me, the best way to get started is to find a good book. Luckily, the Rust Book is a great starting point. Plus, it’s the official book of the language.
My plan was to read the book front to back, doing any coding exercises that the book presents. I’ve currently finished the book and in doing so, I’ve also translated many of the coding examples into my own small programs. This really helps me understand what the book is trying to teach me. Copying examples verbatim (or not at all) usually doesn’t make anything stick. It’s also really nice having that code as a reference once you’ve moved on to bigger projects.
My main goals were to finish the book, create a basic, but real world project/program, and contribute some code to existing open source projects. I’ve also been working my way through the Advent of Code problems in an attempt to get more Rust programming practice under my belt.
Progress, the good and the bad
I’m happy to say I have learned quite a bit since I started this journey. I’ve gone through the entire book, and created a cli project that converts binary or text data into Base64. You can see my example code/notes/projects here.
I’m not done with my Rust journey, but given what I’ve learned so far, I felt it was time to reflect on the progress made, and re-evaluate my feelings towards the language.
I’ll start off with what is going well. The documentation and books are great. It is really nice to see the Rust community put so much effort into having good docs. New languages don’t have the luxury of thousands of examples online so it’s imperative to get the docs right, I think Rust nailed it in this department. Rust’s packaging story is also quite good. Cargo has been easy to work with. It’s nice coming to a language that has a definitive build tool included, which is also supported by the core language community. I haven’t dug too deep into external dependencies but from what I can tell, Cargo makes integrating with other projects/packages and publishing very simple.
I find myself having higher confidence in external Rust dependencies than I have with other languages. I think this is partly due to all the compiler checks that need to pass before you can package any Rust code. There are always going to be packages of varying quality that are available for use. However, it feels like the Rust language itself helps raise the bar for quality, giving end users more confidence in the dependencies they adopt.
Rust seems to promote more thoughtfulness around how you structure your data. Usually Rust makes it difficult to have your data laid out poorly. On a few occasions, I’ve been really fighting the compiler only to realize, if I just changed how my data is laid out, the program becomes more straight forward and easier to compile.
The Rust type system, matching, and error handling are all great parts of the language. Working with enums through the Rust matching system felt strange at first, but once you’re used to it, it becomes intuitive.
Learning Rust has, overall, been great. However, there are a few areas which have been a bit of a struggle. Rust adds a lot of friction to the development process. It takes me much longer to solve problems in Rust than it does in Python. This is a bit unfair since I have more experience with Python, but I do think there is a higher cognitive load on the programmer when writing in Rust. I’m not sure if this is good or bad. It hinders rapid iteration but should produce better more robust code in the long term. This gripe may just come down to using the right language for the problem at hand. I expect, and am hopeful, this friction will be greatly reduced as my comfort with the language increases. I’ll have to wait and see how that goes.
Another low point is being able to find more specific answers to problems I may be having. I think this is mostly due to adoption. Because of the lack of specific examples, I find myself reading through the docs, tracking down how to get the functionality I need out of the language. This also makes it difficult to know if I am producing idiomatic Rust code or not. I am planing to look more into Clippy, a popular Rust linter, which will hopefully help on this front.
Rust lifetimes can be confusing. Sometimes it’s really hard to figure out what the compiler is trying to tell me when lifetimes are involved. Many times, I end up just refactoring the code until the problem goes away without fully understanding why there was a problem in the first place. I’m hopeful, understanding these types of issues will come with experience, but it’s been a bit of a struggle starting out.
My final concern is, while writing code, I find myself wondering if I am relying too heavily on the compiler. I will usually write a program to the point that I think it should work, compile, then work through the errors iteratively until I can compile successfully. The compiler will say, ref needed here, de-ref there, and so on. I will dutifully update until it is happy. At this point, it’s difficult for me to tell if I can avoid these compile errors before they happen (once I know the language better), or if it’s just common operating procedure in the Rust world. I use the C compiler in a similar way, but for some reason it just feels like I rely on the Rust compiler more, to help me write code. I don’t fully understand if this is good or bad yet. It just seems a little strange, which is probably okay.
I’m happy with how things have gone so far while learning Rust. I made it through the book, wrote some programs, and have been practicing more consistently. I still feel like I have a ways to go before I’m truly comfortable writing Rust code. I have some goals I’d like to reach for my next steps in this journey. Finishing the advent of code (2018) and contributing to open source Rust projects will be what I am going to focus on in the coming months. Of course, continuing to practice will be key. It would be nice to get Rust into production at work, however, knowing our current stack it’s probably not likely.
So far, things are going great. I’m excited about taking my Rust learning to the next level. Once I’m there I plan to do another post to update my progress.