Rust Extension Methods

by simbo1905

Seven years ago I was working on a system that had a fat client desktop app written in C# and a Java backend. I signed up for a week-long C# training programme. I was fascinated about the bits of C# that had evolved away from Microsoft J++. A lot of the differences that still stuck in my mind were all about boilerplate removal. One of those was C# Extension Methods. I have posted some sample code of Rust Extention Methods over on GitHub.   

Rust’s support for this techniques is out-of-the-box but there are some edge cases my demo code covers that I will outline below:

Rust Extension methods:. Traits can be used to extend an existing type (defined elsewhere) with new methods, for convenience, similarly to C#’s extension methods. This falls directly out of the scoping rules for traits: you just define the new methods in a trait, provide an implementation for the type in question, and voila, the method is available.

Why am I thinking about this so early on in my journey into Rust? In the last post I mentioned that I don’t want to generate serialisation methods onto my core message objects. Such methods would have an external dependency on serde. I don’t want to tie the users of my library to that dependency. Extension Methods let me enhance (aka “pimp”) my core message objects with serialisation methods. If a user of my library doesn’t like serde then they can write their own Extension Methods using their preferred library.

Scala also has this feature. I didn’t use it on Trex. Why? Because I didn’t use a 3rd party library to pickle my message types as discussed in my last post.

There was a little bit of complication to get things working in my Rust demo code. You are allowed to implement a trait on a struct or enum target as long as either the trait or the target are located in the current crate. The some_extention library fell foul of that rule as it wanted to apply the Serializer trait which comes from the serde crate onto the Shape enum in the some_library crate. To get round the rules it creates a wrapper called Shaper which contains the Shape. The wrapper is an example of the newtype pattern which should give zero overhead as the compiler can optimise it away. Happy days!