Ali Sartawi

Thoughts

The Beauty of Rust's Function Signatures

You're building a simple database... maybe an in-memory database... and, of course, you need to execute queries or commands.

Let's say that you have a class or struct that resembles the parsed query or command... and there is a method called execute or run that will perform the query.

trait CommandTrait {
  async fn execute(self, store: ConcurrentStore) -> Result<Response, Error>;
}

Let's start fanboying about Rust now.

A trait is like an interface... think of it like that. It can be implemented by a struct... think of it like a class.

What does this function signature tell us?

It's async, so it's non-blocking and has to be awaited if you want its result. It might give you a success response and it might give you an error response.

But it also says something very important... very very important.

It says that once this function is called on the Command, the Command will be freed from memory and cannot be used again.

This will already prevent a bug that a command is executed more than once, if some spaghetti code is written.

But this function signature prevents that spaghetti code from ever being written as the compiler will complain.

But, how did we know that from the function signature?

Notice how the first parameter is self and not &self.

&self means that the function will only take a reference to the command.

self means that the function takes ownership of the command. And once the scope of the function has ended, the command is dropped from memory.

The more your function signature tells you and guides you, the safer, faster and cooler it is to code.