๐งต Understanding @rustlang's newtype idiom, when and how to use it. ๐
Let's imagine we are building a mini-database for students and professors, here is our starting point.
๐
The idea is very simple:
* we keep track of professors using a u32 id
* we keep track of students using a u32 id
We are using a HashMap here, but eventually, this could be a trait with a real database behind it, so the ids are quite important here as this is how we find objects
Now, we want to implement course registrations. A student can register for the course of a professor.
Here is how the database looks now.
We've added a new course_registrations vector, and we use it to register students for courses and then check if they are registered.
So far so good, let's write an example and verify our code.
In this setup we have one professor: John, and two students: Bob and Sue.
Both Bob and Sue register for John's course, because John is amazing.
Now we write some code in main to verify our registrations.
But wait, we just added both Bob and Sue to John's course, but according to this Sue is not registered for John's course ๐ค๐คฏ
Let's zone in on the bug. ๐ชฒ
The bug here is we mixed up student_id and professor_id in the implementation of is_registered. Since they are both u32, it's an honest mistake to make.
The fix is easy, we swap student_id and professor_id, but let's think bigger. Can we improve our code to avoid it altogether?
1/ Attempt 1: Add a type alias for student id and professor id
This improves the readability of our code, but if we go ahead and we make the changes in the rest of the code you'll see functionally there is still no difference.
The code still compiles when we mix StudentId with ProfessorId and we still get the wrong answer.
2/ Attempt 2: Add a new type for professor id and student id.
This syntax is a little different, but basically, we define a new struct, with one unnamed u32 field inside it. This is called a new type. One of ProfessorId, and one for StudentId.
Let's see what happens now.
Now we run the same code, but this time the compiler pinpoints our bug ๐ชฒ and doesn't even allow us to run the code.
It also conveniently tells us exactly what to change.
And that was a quite long explanation of #rustlang's newtype pattern! ๐ฆ๐
As the pattern itself is very easy to implement, I decided to focus the thread more on the motivation and how/why it helps. Hope this was helpful!
Share this Scrolly Tale with your friends.
A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.