DEV Community

loading...

My First Month (or so) With Rust

matheusrich profile image Matheus Richard Originally published at matheusrich.com on ・5 min read

I’m learning Rust and this is the first post about my experience with it. I’m a Ruby programmer, so you may wanna check out my post about the decision of learning Rust for more background.

I delayed this post a lot because I didn’t do a lot of Rust in my first month. I had several things going on in my life, so I couldn’t focus on Rust as much as I would like. Anyway, I know that I have to put on paper some of my impressions before I forget them, so here I am.

🔧 Setting up

Setting up Rust was very easy: rustup makes everything pretty straightforward, so I had no problems here. Cargo is also very good, and I had no problems installing libraries (crates) too! Well done, Rust!

📚 Reading

As I didn’t have much time to actually code Rust, I spent a lot of time reading about it. Regarding this, Rust is the language with best learning tools I’ve seen to this day! Not only it has a book (The Book, I must say 😅) that guides you in the first steps to know the language and its unique features, but Rust also has a Learn by Example book!

I think that this is a very nice pairing and both books are awesome in their way:

  • Wanna start from scratch and learn about a concept? Check out The Book.
  • Just want to know the syntax for creating an anonymous function? Here’s a book full of examples.

Chapter 04 (the one about Ownership) of The Book was especially great for me. My mind was blown after reading it. Not because it was hard to read, but because everything made SO MUCH sense! All the pain points in C++ seemed to be solved with this ✨magical✨ compiler. Well, that was in theory, let’s see how I did in practice, tho.

✍️ Writing

I know that I should pick a simple topic to get me started when learning a new language, but I can’t control my desire to create things. I don’t like to create build-and-throw-away things, either. They should be useful things (at least to me)! So, to learn Rust I started building an interpreter following Lisperator.net’s tutorial.

To be honest, my first 100 lines of Rust were the basic algorithms in Chapters 01 and 02 of The Book, just to test out my setup and get to know a bit of the syntax. Four-space tabs and semicolons everywhere were kinda weird for me, but at least Rust doesn’t require explicit returns (and can avoid semicolons in the last expression too). rustfmt was a neat addition, since I don’t have to care about how my code should be indented. 👍 for Rust here too!

I was looking for things that were different in Rust and Ruby. Here are some examples of what I found:

🔢 Underscores and numbers

Rust, like Ruby, allows underscores to separate numbers. The difference is that Rust allows multiple underscores (you can even have trailing ones):

// Both examples work like a charm in Rust
let a = 1_;
let b = 1 _____ 2;

// SyntaxError in Ruby: trailing `_' in number
a = 1_

// SyntaxError too
b = 1 _____ 2
Enter fullscreen mode Exit fullscreen mode

❓ Rust has no ternary operator

We can use if/else expressions — which I’m very familiar with, coming from Ruby —, so I didn’t care not having it in Rust.

Gimme ternary or die!
Although this feature may be very valuable for some users...

📏 Ranges are not inclusive

To me this was weird because it’s not the same I’m used to in Ruby.

  • Ranges in Rust:
println!("{}", (1..10).count()) // => 9
Enter fullscreen mode Exit fullscreen mode
  • Ranges in Ruby:
puts (1..10).count # => 10
Enter fullscreen mode Exit fullscreen mode

I guess I’ll do some off-by-one errors until getting used to this. I found out later that there’s an inclusive version of ranges too:

println!("{}", (1..=10).count()) // => 10
Enter fullscreen mode Exit fullscreen mode

All in all, it was not that different from Ruby. Yeah, Rust is a “curly braces language”, but with things like enums and impl, I could translate my OOP code fairly well. The Gentle Introduction To Rust chapter on OOP was particularly helpful for that.

The main difference from Ruby for me was that in Rust I feel like I have to think about memory usage in each line of code I write.

❌ Learning by error

Generally, Rust gave me really good compiler error messages. The fact I can run rustc --explain SOME_ERROR and see details for this error makes learning Rust (without leaving the terminal) much easier.

The stdlib documentation seems thorough and very modern: it has links for return types, traits, enums, tips, and examples.

🤝 The compiler is my friend

After a long time writing in an interpreted dynamic typed language like Ruby, Rust’s compiler was a breath of fresh air. It’s so good to know that I got a type checker having my back when I screw things up. I feel like I have to write fewer tests but still have the feeling that everything is working.

Another difference is the lack of null values 🙌. This is one of my favorite choices in Rust comparing to C++. Option types are much better IMO and having pattern matching makes dealing with them quite easy. About that, some constructors were really well thought out, like: enums, if let,while let. They are cohesive and fit the language like a glove.

🦀 Rusty Code

It’s funny to learn a new language because I can’t tell what is idiomatic or not yet. For example, while coding my interpreter, I created the following function:

fn is_punctuation(c: &char) -> bool {
    ",;(){}[]".contains(c.clone())
}
Enter fullscreen mode Exit fullscreen mode

I used clone to satisfy the compiler, but I had the feeling that it was unnecessary. Later I ended up refactoring it to this version (which I think is better):

fn is_punctuation(c: &char) -> bool {
    ",;(){}[]".contains(*c)
}
Enter fullscreen mode Exit fullscreen mode

I don’t know if having the string inside the function is a good idea or if I should extract it into a constant or something. And that kind of question happened a lot:

🤔 A lot of questions

As a beginner, I don’t know what are the best practices and idioms in Rust, so I had a lot of questions to ask. I had some classic beginner stuff like how to work with modules and the String vs str vs &str dilemma (which this blog post and my rustacean friend@PotHix helped me to understand), and I’m expecting to have even more questions about memory management and that kind of stuff.

I also don’t know when to move and when to borrow values, so I’m defaulting to borrow all the things and cloning defensively.

I just found out 📎 Clippy, which I think is kinda like👮‍♂️ Rubocop for Rust, so I hope it will help me to write better Rust code.

🔮 Future

I plan to keep writing my interpreter in Rust to learn more about this language. One thing I didn’t explore yet is testing. Since I’m a big fan of TDD I hope Rust has a good test support. I have an interest in digging a bit in game development with the Bevy game engine.

I’ll also make a post comparing Rust with Crystal showing my experience with both languages.

Oh, and if you’re a rustacean, feel free to give me any advice or tip you think is useful! Bye 🦀!

Discussion (2)

Collapse
jmccabe profile image
John McCabe • Edited

I don't know your background, but I wanted to share a couple of thoughts..

1) "semicolons everywhere were kinda weird for me, but at least Rust doesn’t require explicit returns (and can avoid semicolons in the last expression too)."

Have you ever learnt Pascal? It also (at least, when I learnt it in 1983) had this. There's differentiation between function and procedures. Both return at the end (i.e. no jumping out in the middle, which was frowned upon at the time as doing so isn't much different to 'goto'), but the return value from a function is set by assigning a value to the function name. Interesting, worth a look! Also semi-colons separate statements, rather than terminate them, so not needed if the next bit of code (end of a subroutine for example) doesn't count as a statement.

2) "Ranges are not inclusive"

I don't know Ruby, but your comment made me look, as ranges are inclusive in Ada (released to the public in 1983), and Ruby has adopted similar 's..e' syntax. However you didn't mention Ruby's 's...e' syntax, which gives you a range that doesn't include the end index (alternatively the ::new(s, e, true) version, where the last parameter is 'exclude_end'). It seems like, essentially, Rust and Ruby have just chosen the defaults to be opposite.

3) "Underscores and numbers"

Yes, Ada (1983) has this. Also various number bases can be easily specified. For example:

16#ABCD_EF01# - - hexadecimal 32-bit integral value.
2#1010_1011_1100_1101_1110_1111_0000_0001# - - same in binary
3#0.1# - - base 3 floating point, => 1/3rd

4) "Rust has no ternary operator"

Neither had Ada originally, but "if expressions" and "case expressions", which are similar to the ternary operator, were added in 2012. It looks like they're also similar to Ruby's if/else expressions, so....

5) "The compiler is my friend"

This is what Ada programmers have known since the early '80s :-)

Thanks for the article. I've had a cursory glance at Rust, but never got very far since a lot of the 'simple' stuff appears to be a reinvention of the wheel, with different syntax for no apparent benefit. Maybe I should try harder :-)

Collapse
matheusrich profile image
Matheus Richard Author

Thanks for your time writing this. Yeah, much of the things were quite similar between Ruby and Rust. Also, Ada was one of the languages that influenced Ruby, according to Matz.

Forem Open with the Forem app