Implement Only and Exactly The Needed Methods

This post covers the practice of using functions to return struct instances that have implemented a specific trait that is needed in that context.

First; Separate the entity from the methods it needs

a graphic of a personified box looking at a camera, an arm, and a wheel as options to accomplish some task.

Craft the best trait set for the job; exactly when it’s needed

Imagine a metal box moving around on a conveyor belt. It’s zipping around the belt system until it gets diverted into a station where some robotic arms get attached to it.

It moves the arms, testing them and verifying the procedure worked. Then it uses its arms to reach up to grab a handle that is attached to the bottom of another convert system, to move itself to another station.

At the next station, its arms get removed by the station tooling, and a camera gets attached. It starts recording some video data into itself as it rides around on the conveyor belts.

This imagery could continue on forever, but the idea remains that the package is one thing, and its ‘implements’ are another.

This concept is how we will be imaging our structs and traits, where the box is our struct, and the traits are our robot arms and cameras.

A freshly initialized struct with trait implementation

a graphic of a box with robot arms is meant to represent 'outfitting' struct instances with traits to give them only the tools they need

There are plenty of scenarios where this is relevant, messages, short-life-cycle sprites, etc. I’m just going to create a bland Person struct and show how Traits can be used to interact with the Person struct.

Let’s use an example program flow:

 

Create + Implement Function Pattern

  1. Create the new Person struct

  2. Implement a trait that is relevant for that struct in two different scenarios

  3. The two traits will make it possible to interact with two different areas of the struct

  4. The struct can now use only the tooling it needs, whenever it’s relevant to do so

 

So the new instance we create will exist long enough to be populated and then published via a function out of this context, where the borrow-checker can then clean up its used memory. Cool!

Example Code:


Example Code Unit Tests:

Existing Struct Instances; Gear Up!

a small platoon of identical cartoon crab-like robots looking angry.  This is just a goofy example of the idea of instance duplicaton

Don’t anger the data

I was able to create a pattern I can conditionally invoke a function that implements a desired trait for creating clones of existing objects. I’m imagining something crazy like in a video game where an enemy character is capable of creating duplicates of themselves and you have to defeat them.

This feels close to factories or even abstract factories depending on the application.

More Example Code:

Testing:

Conclusion

Creating new instances of structs when you need them is cool. Creating new instances of structs that have only exactly the methods you want when you need them is even cooler.

Angering the data is not cool. Don’t do that.

I’m still learning a lot, so I don’t feel that this post adequately covers the inspiration I’m getting right now. I’m very impressed with Traits and after this kind of week-long foray poking and prodding the compiler to see what I can do, I admit that I’m really starting to enjoy coding in Rust.

The discovery that I need to work with the compiler was a huge one. I began to want to ‘think how it thinks’, vs. trying to program how I have been for the past 10 years. It’s doing exactly what I wanted, which is broadening the abstract ideas I have about programming, architecture, and patterns.

Previous
Previous

An Exercise To Understand Rusts Trait Bounds Syntax

Next
Next

Quasi-Fuzzy Function Parameters Using Rust Traits