Not in that instance, no.
In the case you’ve provided here, you’ve created an object that is maintaining state about the current process.
Just so everyone is following along at home, what @dee0xeed has created is a converter that reads from standard in, XOR’s a byte, and the writes it to standard out. The converter object is just a convenience wrapper to make this happen.
Here’s why I don’t think this example is a pass-by-value issue (and, additionally, one of my problems with the fluent interface).
In the example that @IntegratedQuantum was providing (applying an affine transformation), there is a defined outcome of that step that creates a unique and well-formed object. For instance:
x * y + z where all variables are f64.
x * y → f64 that is the product of x and y… we’ll call him u
u + z → f64 that is the addition of the former product with z.
At each step here, there is a defined, well-formed outcome that we can use independently of the next operation.
In your case, what’s the use of reading the bytes if we aren’t going to XOR them? And then, what’s the use of XOR’ing them if we aren’t going to write them somewhere?
Each individual state represents an incomplete part of a total process. You need to preserve that state between calls.
NOW… the fun part
The example you provided is one of the reasons I personally do not like the fluent interface. It strongly couples an interface to an operation and each operation assumes something about the previous state. I would much rather see a function like
readWriteXOR where everything you’re doing is the product of one function.
In essence, the fluid interface encourages us to plug-and-play; it’s flexible and allows for easily making your own sequence of events. Sounds good, right?
Well, in most cases I’ve seen, it turns out that people do a lot less plug-and-play than you would expect. They actually do a few things that need to be done in order and depend on the last step. In other words, we have a lot of flexibility when in reality, there is a very simple process that needs to exist and should not be modified.
For instance, let’s take your example:
_ = conv
And let’s just change one thing (we’ll swap the order of two functions):
_ = conv
Well, that doesn’t make sense now, does it? I’m XOR’ing a byte after I wrote something? That seems idempotent.
In fact, there are many orderings you can come up with that do not make any sense. So now, we need to add controls to make sure validity is maintained. Great, more state lol.
Let me play devil’s advocate here for a moment. Where could this maybe be a good thing?
If you are creating an interface that genuinely needs to maintain state between operations AND the operations can be reordered to give many valid combinations AND you have guard rails for operations that must be only called at a specific point… okay then, this could work.
Otherwise, just write a function lol. Thanks for the great example, @dee0xeed, and thanks for reading my rant.