Objects & XOD: Chaining Best Practices?

What a discussion! :nerd_face:

Yes, this is a weak point in XOD docs. The main reason is in the fact we did not settle on a “right” concept when those docs were written. There are several orthogonal variants of doing things on this planet, thus the confusion. For quite much time (:grimacing: ) XOD employs the functional approach where data-to-pulse should not possible at all (albeit it is technically achievable now). This way is chosen to make XOD accessible to Pete.

So if you have a node which has a number output the scenario of outputting “five-five-five-five” is indistinguishable from “fiiiiiiiiiive” to downstream nodes. Again, it is not enforced in C++ currently to save a few clock cycles by skipping the check of whether emitValue indeed changes the value and so should we notify downstream nodes.

If you want to run some side-effects on demand with parameters kept constant, add an input pulse to your node. A rule of thumb: if a node makes side effects (it is impure), there should be an intput pulse to trigger it.

In yet other words: a node will evaluate (a) on boot and (b) whenever an input value changes or a pulse input receives a pulse. Whether the node will be evaluate’d in other moments or not is unknown, the behavior must not depend on it.

The mentioned lan-ip node violates nothing, it is pure. It extracts an IP from the connection object. When the object changes it gets re-evaluated. Think of it as of red component extractor from a color object.

Because the nature of each particular method in an Arduino C++ library is not generally known in advance, adding a trig pulse looks fine to me.


Even in this paradigm, some creative tricks are possible. You can “bake” some state changes to the object passed around and react to these changes. For example, the adafruitneopixel custom type might be

struct Type {
    Adafruit_NeoPixel* neopixel;
    int seqStep;
    int erroredAtStep;
}

Then each method can take such value, do its job, and make a copy of this value with seqStep incremented, then emit it down effectively producing a new value to be consumed by a downstream node. :thinking: looks like we’re inventing the Haskell IO monad or JavaScript Promise.

I said it is possible, but I’m not sure whether it will work well. I’m watching at Pete.

So, for the low-level wrapping, I would stick to pulses on the nodes. A clever layer, if required, might be built on top of these nodes by hand then.