Making it Hard, and Soft
Mar 30, 2024
The title of this blog post is just a peek of what we are going to do today.
Let's get started
Today, we are going to see some tips and tricks regarding the usage of Rust language.
Why are you choosing rust it's a language used by blue hair personalities
I know people often consider Rust to be an extremist language, because many of them are not trying to get things done rather just fighting with a borrow checker by banging the Future on their toes just for simple asynchronous executions.
But, that doesn't mean Rust itself is bad, or it doesn't have potential.
Rust is the middle ground for both competitive coders and Project builders, competitive coding is done by all of them, the opponent is borrow-checker, but the project building is done by only some of them.
Considering you know basics of Rust, let's dive into it…
The match and its magic
Consider you had a task to create a subroutine, which is an initializer for a database client.
“db refers to database”
Ideally you will require a name/namespace, and the host endpoint(with credentials).
And tadaww you got yourself a client. In theory, it's just simple.
Now the code part,
here we will be using Surreal as a database and its lib surreal db as our rust client,
Note: Tokio is used as an async runtime
the above might look like a normal subroutine in the first glance but under the hood if you look closely you would find out that it has slight wisdom to it,
firstly, we have a level of abstraction over a client, some argue it to be good, others argue it to be bad. Nonetheless, it gets things done. In our client we have a field db which is of type Surreal<Client>. Here, Surreal is an Arc pointer to a web-socket client. So it is straight forward.
Then we have our impl block, which has init subroutine to initialize our client with some parameters, really simple.
Then, we have our juiced up magic match expressions, let's understand them one by one,
First match expression accounts for a Result<Client, Error>.
Second match expression accounts for a Result<(), Error> which runs only when the first match expression resolves to be ok.
Inside our second match expression we have db.signin which also returns Result<(), Error>.
So one would think there are too many conditions to check, here's where the Rust's pattern matcher comes to rescue.
Inside every match expression, we previously accounted for an Ok variant, but there is also another variant in Result, the Error variant.
Info: Result is an Enum in Rust, for more info
Surprise‼ we are not accounting for the Error in every match expression instead we are just returning the Result like e => e.
There are multiple benefits of this,
firstly, we are squashing multiple errors into one without making borrow checker angry.
Secondly, we don't care what happens to the underlying expressions, we just bubble up those results.
Thirdly, the most important part, we get back a single Result with which we are satisfied in this scenario.
And at last we return an Option type of our client.
But, how will you handle individual error of the Results, is it not a good practice to handle it?
Yeah kinda, it is a good practice to acknowledge the expressions which can result in error, to handle it or not solely depends on the developer.
For e.g., in JS:
Not knowing that the above expressions might throw an error, is a major skill issue but knowing it and voiding it, is whole different scenario.
Stop making too many abstractions and branching of code, just to make your code come under a good coding practice.
Coding practices are a Myth, they are present to make it easy for developers who have skill issues, understand your code. But, I strive for my code to be efficiently understood by the machine it runs on, not the developer who sees it.
I think I conveyed my point :P
The first part Making it Hard is done.
Now it's time for the second part,
The soft part
If you do know Rust to at least to an extent that you can get things done, then you probably might be thinking the above is just an engineer flexing the match expressions.
Yeah, True!
And also not true here's why,
There is a method called and_then on the Result type, which does all of the above error squashing.
But, here's the point you should not blindly use something other people created without trying it out yourself first. This is where you will actually learn things.
Whenever I try to create something, let it be a simple subroutine, I always make it “by my way”. In this process I will know what tradeoffs I am making and what are the weak points of the subroutine.
Then, even in the future if I try to change it to convince some people on the internet, I will have a full context of what is happening under the hood.
Conclusion
If you are just learning or just new to what you are doing, try to make many mistakes as you can by doing it your way (Hard way).
Mistakes make you think better, they broaden your thinking process.
If you just go the road of Soft way, as long as you are in that fairy tale dream land, you will never encounter the mistakes. Which will result in major skill issue.
Only, when you get proficient in your hard way, you should be deciding to go soft way.
Indeed, with hardships there will be ease.
If you have feedback regarding this blog post, click on this
Thats it in this post, In case I don't see ya, Goodafternoon, Goodevening and Goodnight.