0

I'w writing a program in Rust that basically pushes data through a pipeline of steps that transforms it in different ways. The data is represented by an Entry, and I am designing a Step trait for the steps in the pipeline.

The trait should have a method that process the entry. My first design was this:

fn process(&self, entry: &mut Entry) -> ()

Later, I realize I wanted some steps to be able to drop the entry, i.e. somehow signal to the caller that the entry should not be processed any further through the pipeline. I am considering two different signatures for this:

fn process(&self, entry: Entry) -> Option<Entry> //Returns None if object is dropped.
fn process(&self, entry: &mut Entry) -> bool  //Returns false if object is dropped.

Which one would you say is the most idiomatic and cleanest? Is there any performance penalty in passing the ownership around as in the first option? Is there a third better alternative?

4

Although the Drop trait's drop() method is declared with &mut self, it is not actually possible to call that method directly. Instead you would have to use std::mem::drop() which takes ownership of the object.

This makes sense: once a value has been dropped it no longer exists in an initialized state. Accessing it afterwards would effectively be undefined behaviour, but that is exactly what Rust's lifetime system tries to prevent. Rust won't drop an object that is still owned.

This leaves your fn process(entry: Entry) -> Option<Entry> as the only declaration that will work, and would also be the safest option if there was a choice. Note that this means you won't have to drop explicitly: simply returning None instead of Some(entry) will implicitly drop the entry.

Moving ownership of an object might imply a tiny performance cost because this usually requires a shallow copy (like a move-constructor in C++, or a memcpy() in C). This is not an issue for most objects unless they are large structs. If you are concerned about this, use a Box<Entry> instead, which simply adds some pointer indirection to avoid moves.

  • Thanks! I realize my use of the word "drop" was a bit unclear - I was meaning it in a more conceptual way, not in the more specific Rust sense. Perhaps "discard" would have been better. With the second alternative, the entry would go out of scope and be dropped automatically anyway. But I get the impression you would still recommend the first? – Anders Feb 22 at 20:59
  • 1
    @Anders that's a pretty good point. Returning a bool might be workable if you annotate the return value as #![must_use]. This might even be preferable if you cannot take ownership of the original project. Otherwise the take-ownership-and-return-Option approach is better because it gives your processing function strictly more flexibility. And returning an Option or Result makes it super easy to chain multiple processing steps. – amon Feb 22 at 22:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.