I’m currently experimenting with ProcessNodes, Operations, and Pads in Gamma.
I’ve attached an example where the sequence of operations is designed to prevent any division by zero, yet the error still occurs. It seems as though the results of the intermediate operations aren’t being stored or updated correctly on the Pads.
I’m not sure if I’m missing something fundamental in the logic or if this might be a bug.
Meaning that you have some issue with understanding how stuff is executed…
Since I don’t understand what is your goal with this, can’t really suggest something on this stage, if you drop few words how this should work on your taste we might assemble something more reasonable.
When you define a process with multiple operations, keep in mind that there’s no guarantee that all of those operations are actually getting called for each application of your node.
For example in your case you defined the operations (in that order) SetIn, CalcRpow3, CalcOmega, Update to be part of the process. On the application side (caller side) the system calls each of those operations based on how they are wired up in the caller - which in your example is the main patch with one Update operation.
If we look closely (and that is what @antokhio pointed out) you’ll see that your SetIn, CalcRpow3 and CalcOmega operations are greyed-out - they are not getting called. You’d need to connect them to something for the system to pick them up.
OR
and that is new in the 7.0 release (and probably not well known), you can say on the definition side that an operation shall be part of the default assignment (like Update always is) by holding Ctrl when clicking on the checkbox - you’ll notice it being drawn slightly different now:
This way there’s no need to connect those operations on the application side (caller) because the system will put them (if not wired up differently) on the default operation (which is Update) right from the start.
Just ror reference: marking an operation to take part in the default assignment can also be done in C# using the FragmentAttribute.IsDefault property.
It wasn’t clear to me that operations are only called when data is connected to their corresponding input pins, even if they are marked as part of a ProcessNode.
Regarding the new Default Assignment, I’ve also noticed that if an operation has no input pins, you still need to manually enable it on the ProcessNode, even if it’s marked as a Default Operation.
In my case, the node PlanetSRT2 has every operation marked as default and no pins are grayed out, yet CalcR3 is only called when a Toggle is connected.
Basically your process has only one operation in the begining, the Update, the system checks your process and if something assigned to Update it calls it. You can visually see it by pins are lighter gray. So if pin is light gray this is evaluated every frame. When you expose Operations other then update the pins are dim gray, until they are incorporated in update, then they become light gray and evaluated every frame. The system only tracks exposed pins (seen from outside of node)
In the attached PlanetSRT2 node, the CalcR3 operation pin is light gray, but the operation is not being called (even though it is marked as a Default Operation).
The other Default Operations, SetIn and CalcOmega, are called even when no input pins are connected.
Can I assume that a Default Operation is only included in the Default Assignment if it has at least one Input Pin is connected?
Ah ok, that’s when you have no pins at all. In that case the system enforces an “Apply” pin - called the same way as the operation itself (it would otherwise not be controllable from outside) and sets its default to false. I think that particular exception was needed to still support nodes which are build like the LFO or Counter having a Reset operation without any pins. So yes, it seems you’re running into an edge case here behaving counter intuitive for your example.
To summarize, the exception you run into is:
Operation with no pins taking part in process → forced apply pin → defaults to false.
I remember we discussed this case for quite a while internally and settled with the above compromise. For operations like Reset it works fine, for your case it doesn’t. If there is a good solution which does not require another layer of configuration or introduces breaking changes - eager to here it - we didn’t find it (yet).
I’m not sure if it makes sense to push this reflection further, as this behavior has likely been agreed upon and changing it now could lead to side effects.
However, in my experience, the ability to break down a problem into smaller operations makes design much simpler, and Operations inside a ProcessNode are great tools. Therefore, having a system that adapts to all scenarios could streamline the design process and make patches more readable.
In cases where an operation has no InputPins, it seems to me that the behavior you described for LFO and Counter (for operations like Reset, Up, Down, etc.) could have been achieved by making the operation part of the process without forcing it to be a Default Operation. At the moment, if an operation doesn’t use any InputPins, it behaves exactly the same way whether it’s only part of the process or marked as a Default Operation; this can generate confusion and is counterintuitive because DefaultOperations behave differently depending on whether they have Input/Output pins or not.
I don’t know if this could be a solution, but it would just involve modifying nodes that use operations without Input or Output pins, specifying that the operation is not a Default Operation, but simply part of the process (in this case, I don’t know if nodes were automatically or manually converted when moving from 6.7 to 7.0).
Of course, my specific case can be solved differently; I was just making a general reflection on the design style that could be adopted, knowing that DefaultOperations are always executed by default by the ProcessNode.
By the way, I’m actually on the topic starter’s side here. This has always frustrated me.
Let me explain: I create something in a class or a process and start using it. Great, I’ve got Apply! I use it to call certain operations on the class. And then I decide I need to pass some data to that operation, and voila, the apply pin disappears! And now I have to wrap it in an if statement (which looks a bit ugly). What’s more, it happens so counterintuitively and randomly that it almost always feels like some sort of bug.
I’ve wanted to write about this for a while. Maybe it’s worth creating a separate thread?