Olivia πŸ¦€

Olivia πŸ¦€

@iolivia.me

πŸ‘©β€πŸ’» staff eng πŸ¦€ post a lot about rust and rust gamedev ✍️ wrote https://sokoban.iolivia.me πŸ”₯ blog at https://iolivia.me 🧡 weekly #rustlang threads every Thursday - subscribe here https://forms.gle/Tcm7cAkLt4NF9ZCZ9

717 followers76 following996 posts

Pinned

Hey all πŸ‘‹ This year I'll try to stick to Thread Thursdays, which is every Thursday I'll post a thread about #rustlang fundamentals πŸ¦€ My goal is to help you learn 1% more Rust each Thursday, so follow me if you'd like to read them πŸ¦‹ Here are some of the best threads so far πŸ§΅πŸ‘‡

One year in, time to reflect on the #rustlang threads! I wrote 44 total threads, many of you read them, and liked them and almost 100 people subscribed to the newsletter! I couldn't be more thankful for this. But unfortunately, I will stop writing these for now. Why? πŸ‘‡

Olivia πŸ¦€@iolivia.me

Hey all πŸ‘‹ This year I'll try to stick to Thread Thursdays, which is every Thursday I'll post a thread about #rustlang fundamentals πŸ¦€ My goal is to help you learn 1% more Rust each Thursday, so follow me if you'd like to read them πŸ¦‹ Here are some of the best threads so far πŸ§΅πŸ‘‡

View full thread

While reddit has a very large engaged audience, they are also very particular about content, so every other comment I get (for the free content I spend ages to write) is "arghh this format sucks". Which makes the newsletter very difficult to grow, since my goal is to share this with as many people

In addition to this, I have another rust project that I'm very excited about working on, and doing both at the same time plus other personal and work commitments is pretty hard. So, to wrap it up, thank you everyone who read and enjoyed the threads, you are the best!

One year in, time to reflect on the #rustlang threads! I wrote 44 total threads, many of you read them, and liked them and almost 100 people subscribed to the newsletter! I couldn't be more thankful for this. But unfortunately, I will stop writing these for now. Why? πŸ‘‡

Olivia πŸ¦€@iolivia.me

Hey all πŸ‘‹ This year I'll try to stick to Thread Thursdays, which is every Thursday I'll post a thread about #rustlang fundamentals πŸ¦€ My goal is to help you learn 1% more Rust each Thursday, so follow me if you'd like to read them πŸ¦‹ Here are some of the best threads so far πŸ§΅πŸ‘‡

They take ages to write, even for topics that I am already familiar with, and if I'm not I have to spend extra time learning the topic before I can write about it. Growing the newsletter is a whole different game, the bluesky community and traffic is pretty small, so it requires posting to reddit.

πŸ•°οΈ Async Basics in #rustlang Send, Sync, Future, tokio, Pin, I'm sure you've heard a lot of intimidating terminology when it comes to async Rust, so this thread is about explaining the basics in a simple way. We'll build a transcript generator to understand async/await, Futures πŸ§΅πŸ‘‡

View full thread

6️⃣ Conclusion - Futures are lazy state machines - Async provides concurrency, not necessarily parallelism - Cooperative multitasking: tasks yield at .await points only - Send = safe to move between threads - Sync = safe to share references btwn threads - Use async for I/O-bound, threads for CPU-bound

πŸ•°οΈ Async Basics in #rustlang Send, Sync, Future, tokio, Pin, I'm sure you've heard a lot of intimidating terminology when it comes to async Rust, so this thread is about explaining the basics in a simple way. We'll build a transcript generator to understand async/await, Futures πŸ§΅πŸ‘‡

View full thread

5️⃣ When to Use Async vs Threads Async is perfect for I/O-bound operations where you're waiting for external resources, use async for concurrency with I/O. Use threads for CPU parallelism!

πŸ•°οΈ Async Basics in #rustlang Send, Sync, Future, tokio, Pin, I'm sure you've heard a lot of intimidating terminology when it comes to async Rust, so this thread is about explaining the basics in a simple way. We'll build a transcript generator to understand async/await, Futures πŸ§΅πŸ‘‡

View full thread

implementations for Send and Sync, and if they don't it's because most of the time they are not safe to send across threads. In practice I think you'll find most of the time in basic cases it will just work out of the box.

4️⃣ The Runtime Async code needs a runtime to execute. The runtime manages the state machines, decides when to poll futures, and handles task scheduling. A main function in itself can be sync, with a runtime inside, or you could use #[tokio::main] to achieve the same with less boilerplate.

πŸ•°οΈ Async Basics in #rustlang Send, Sync, Future, tokio, Pin, I'm sure you've heard a lot of intimidating terminology when it comes to async Rust, so this thread is about explaining the basics in a simple way. We'll build a transcript generator to understand async/await, Futures πŸ§΅πŸ‘‡

View full thread

3️⃣ Sync Trait Sync trait is automatically implemented for types for which it is safe to share references between threads. A type cannot be Sync unless it is Send, which of course makes sense as you wouldn't be able to share a reference to an "unsafe" object. Most types get automatic ...

πŸ•°οΈ Async Basics in #rustlang Send, Sync, Future, tokio, Pin, I'm sure you've heard a lot of intimidating terminology when it comes to async Rust, so this thread is about explaining the basics in a simple way. We'll build a transcript generator to understand async/await, Futures πŸ§΅πŸ‘‡

View full thread

But what if we used `Rc<String>` instead of String like this? This won't work because Rc doesn't implement Send, which means BadTranscript doesn't implement Send, which means we actually can't move this value between threads and use it as an output of the async task.

πŸ•°οΈ Async Basics in #rustlang Send, Sync, Future, tokio, Pin, I'm sure you've heard a lot of intimidating terminology when it comes to async Rust, so this thread is about explaining the basics in a simple way. We'll build a transcript generator to understand async/await, Futures πŸ§΅πŸ‘‡

View full thread

1️⃣ Futures When you write async fn, Rust creates a Future - a value that may not be ready now but will be later. Futures are lazy and do nothing until you await them. Behind the scenes, Rust compiles your async function into a state machine that can be paused at each await and resumed later.

You can check out the Future trait, or more importantly the Poll enum which shows you exactly how this works under the hood. Basically each Poll is either Ready which means the future has finished running and we have the output T, or it's Pending which means it's still executing.

πŸ•°οΈ Async Basics in #rustlang Send, Sync, Future, tokio, Pin, I'm sure you've heard a lot of intimidating terminology when it comes to async Rust, so this thread is about explaining the basics in a simple way. We'll build a transcript generator to understand async/await, Futures πŸ§΅πŸ‘‡

View full thread

We can expect the transcript generation under the hood does multiple steps like: * call an API over the network to get the student's data * do some CPU intensive work to calculate averages and totals based on that data * generate a PDF in memory * save PDF file This means not all those ..

3 seconds are real work, some of it is waiting for a network or IO call to come back. This is a perfect example to use async to handle all transcript requests concurrently and optimise resources. While we wait for that, we can do other work from another task.

πŸ•°οΈ Async Basics in #rustlang Send, Sync, Future, tokio, Pin, I'm sure you've heard a lot of intimidating terminology when it comes to async Rust, so this thread is about explaining the basics in a simple way. We'll build a transcript generator to understand async/await, Futures πŸ§΅πŸ‘‡

0️⃣ Blocking vs Async Code Let's see what happens when 3 students request transcripts using traditional blocking code. Not only is everything sequential, so each student needs to wait for all transcripts to finish before getting theirs, but also if we are on the main thread we'd be freezing the UI

β›” Error handling in #rustlang with anyhow and thiserror Error handling in Rust can be a complex topic, especially since a lot of the patterns are different from other languages. Let's explore some basic options and then go deeper into using anyhow and thiserror crates πŸ§΅πŸ‘‡

View full thread

πŸ’‘ This is the key difference: anyhow is great for applications where you just need good error messages, while thiserror is perfect for libraries where consumers need to handle errors programmatically.

That's it, we looked at how to do basic error handling in rust and then improved it using anyhow for context and thiserror w error types. Hope it helped you learn 1% more Rust today, follow me for more threads like this and subscribe to receive these threads over email forms.gle/vY6zXE21Dkwa... πŸ¦‹ πŸ¦€

forms.gleRust Threads NewsletterGet bite-size Rust Threads about fundamental concepts and practical usage right in your inbox every Thursday. Checkout this for a sample of previous threads:…

β›” Error handling in #rustlang with anyhow and thiserror Error handling in Rust can be a complex topic, especially since a lot of the patterns are different from other languages. Let's explore some basic options and then go deeper into using anyhow and thiserror crates πŸ§΅πŸ‘‡

View full thread

Then, we change all instances of anyhow! to return the appropriate EnrollmentError variant, and change the function signatures to return Result<T, EnrollmentError>. Note that we can no longer use `.context()` since that's an anyhow feature, but the errors themselves need to be descriptive enough

The error messages are now cleaner and more structured. With custom error types, library clients can: - Match on specific error variants to handle different cases - Access error fields programmatically (like student_id, course_id) - Make informed decisions based on the error type

β›” Error handling in #rustlang with anyhow and thiserror Error handling in Rust can be a complex topic, especially since a lot of the patterns are different from other languages. Let's explore some basic options and then go deeper into using anyhow and thiserror crates πŸ§΅πŸ‘‡

View full thread

3️⃣ Custom error types The course enrollment is a pretty representative complex example, and the solution with anyhow context is normally good enough for internal application code where you don't need to worry about exposing error types to external clients However, if this was a library ...

and we wanted to expose more specific error types that clients can match on and handle differently, we need custom error types. We can use the thiserror::Error derive macro to easily create a custom error enum with different variants for each error case.

β›” Error handling in #rustlang with anyhow and thiserror Error handling in Rust can be a complex topic, especially since a lot of the patterns are different from other languages. Let's explore some basic options and then go deeper into using anyhow and thiserror crates πŸ§΅πŸ‘‡

View full thread

You can see in the last error the top level error message is "Failed to add student with id 2" and the cause is "Name cannot be empty". This additional context is super helpful for complex chains of function calls.

We could extend this to a more complex example like course enrollment with a deeper chain. Here's how the process_enrollment function uses context at multiple levels. Notice how each layer of context provides additional info about where in the call stack the error occurred.

β›” Error handling in #rustlang with anyhow and thiserror Error handling in Rust can be a complex topic, especially since a lot of the patterns are different from other languages. Let's explore some basic options and then go deeper into using anyhow and thiserror crates πŸ§΅πŸ‘‡

View full thread

This is already better than the plain result because: - anyhow::Result can hold any error type, not just String - We get better error trait implementations (Display, Debug, etc.) - We can return different error types from the same function - It sets us up to use anyhow's powerful context feature

2️⃣ Anyhow context Let's add new functionality that also validates the student name before adding them to the db. First, we need to import the Context trait and then use .context() to add context to the error returned from validate_name.

β›” Error handling in #rustlang with anyhow and thiserror Error handling in Rust can be a complex topic, especially since a lot of the patterns are different from other languages. Let's explore some basic options and then go deeper into using anyhow and thiserror crates πŸ§΅πŸ‘‡

View full thread

Version 1 - Naive approach with panic-crashes the whole program on a simple error Version 2 - Returning bool to indicate success/failure but no error details, we know what failed but not why Version 3 - Using Result to return success values and error details, a good compromise and the rust default

1️⃣ Using Anyhow Building on top of this, let's explore how anyhow can help improve our error handling from here. We first switch Result<Student, String> to anyhow::Result<Student> and use the anyhow::anyhow! macro to create errors with messages.

β›” Error handling in #rustlang with anyhow and thiserror Error handling in Rust can be a complex topic, especially since a lot of the patterns are different from other languages. Let's explore some basic options and then go deeper into using anyhow and thiserror crates πŸ§΅πŸ‘‡

0️⃣ The evolution from panic to Result Let's explore error handling approaches using a university database with Student and Course structs, and a Database holding students, courses and an enrollments HashMap. Now let's explore 3 implementations for error handling: V1 - Panic V2 - Bool V3 - Result

Thursday Thread Preview β›” Error handling in #rustlang with anyhow and thiserror πŸ‘‰ In this thread, I’ll break down how to handle errors cleanly and how/when to use Result vs anyhow vs thiserror Stay tuned, coming out Thursday on πŸ¦‹ and πŸ“€

#rustlang Thursday Threads recap Organising larger projects w workspaces bsky.app/profile/ioli... Memory layout bsky.app/profile/ioli... Panics bsky.app/profile/ioli... πŸ‘‰ Subscribe to receive these threads over email πŸ¦‹ πŸ¦€ forms.gle/vY6zXE21Dkwa...

bsky.appbsky.app
Olivia πŸ¦€@iolivia.me

😱 Panic in #rustlang What is a panic in Rust, how should you handle it when it happens and when should you use it intentionally in your code? Let's explore panic in more detail πŸ§΅πŸ‘‡

πŸ“ File IO in #rustlang File system handling is a core building block of using a language effectively, and Rust makes it pretty ergonomic with the std::fs module. Let's take a look at how to use File IO APIs in Rust with a real-world example: a grade manager for students and courses πŸ§΅πŸ‘‡

View full thread

πŸš€ Quick recap: - Use fs::write or writeln! for writing files - Use create_dir_all before writing to nested paths - Use fs::read_to_string for reading small files and BufReader for larger files - Use remove_file/remove_dir to delete files and directories

πŸ“ File IO in #rustlang File system handling is a core building block of using a language effectively, and Rust makes it pretty ergonomic with the std::fs module. Let's take a look at how to use File IO APIs in Rust with a real-world example: a grade manager for students and courses πŸ§΅πŸ‘‡

View full thread

7️⃣ Reading larger files For larger files, it's better to use a buffered reader to avoid loading the entire file into memory. Here's how you can do that. Notice we use the BufReader and BufRead trait.

The reader acts as an iterator over the lines in the file, which means it never loads the full file into memory at once, but rather reads it line by line or chunks

πŸ“ File IO in #rustlang File system handling is a core building block of using a language effectively, and Rust makes it pretty ergonomic with the std::fs module. Let's take a look at how to use File IO APIs in Rust with a real-world example: a grade manager for students and courses πŸ§΅πŸ‘‡

View full thread

5️⃣ Parsing contents into structured data Technically not part of the std::fs API but another common pattern is to read a file and then parse its contents into a structured format. Here's how we can read back the grades file. We could also use JSON/CSV+real parser, this is just a simple example.

6️⃣ Deleting a file After we saw how to create, write, and read files, let's see how to delete a file, pretty simple! We could also use the equivalent for directories with fs::remove_dir or fs::remove_dir_all.

πŸ“ File IO in #rustlang File system handling is a core building block of using a language effectively, and Rust makes it pretty ergonomic with the std::fs module. Let's take a look at how to use File IO APIs in Rust with a real-world example: a grade manager for students and courses πŸ§΅πŸ‘‡

View full thread

3️⃣ Reading to string We can use fs::read_to_string to read the entire contents of a file into a string. This is super handy for small files. Again, we handle the Result to manage errors gracefully.

4️⃣ Creating directories Another common task is creating directories. You can use fs::create_dir_all to create a directory and all its parent components if they are missing.

πŸ“ File IO in #rustlang File system handling is a core building block of using a language effectively, and Rust makes it pretty ergonomic with the std::fs module. Let's take a look at how to use File IO APIs in Rust with a real-world example: a grade manager for students and courses πŸ§΅πŸ‘‡

View full thread

1️⃣ Writing to the file with writeln! Let's improve the error handling and handle the Result and write some data to the file. Notice the use of `ref mut` to get a mutable reference to the file inside the match arm and that the writeln! macro also returns a Result which we handle with expect.

2️⃣ Writing to the file with fs::write We can also use fs::write to write to the file, which is a bit more concise for small files. the write call will both open the file, write to it, and then close the file. Pretty neat!

πŸ“ File IO in #rustlang File system handling is a core building block of using a language effectively, and Rust makes it pretty ergonomic with the std::fs module. Let's take a look at how to use File IO APIs in Rust with a real-world example: a grade manager for students and courses πŸ§΅πŸ‘‡

0️⃣ Creating files Let's start by creating a file. You can see that File::create is used to create a file, if the file already exists it will be truncated. The file is opened in write-only mode and the API returns a result which makes error handling explicit.