Getting data for variadic nodes


#1

Is there a way to determine what the arity is for a node, or what level we are currently on?

The reason I ask is I’m looking to implement an LCD node with variable number of lines. I will need to know total number of lines selected to initialize LCD, and I need to know what level I’m currently on to know which line of LCD to write to. In my case, I need to get this info from my C++ code; I would imagine it would be quite a bit harder to provide the info in a std patch not using C++ code…

I guess I could use node state to determine line to write to, but I still need to know total # lines while still on line 1. I could add a pin that has to match # lines, but that seems tacky…


#2

Hello!

That’s a very interesting use case. If only we haven’t to know the total number of lines for initialization… I’d told you how it’s can be done right now. Back to reality. In its current implementation, the information you’re asking for is totally inaccessible to C++ because the expansion is performed on a stage preceding the stage of code emission. From the transpiler’s point of view, variadics do not exist, it sees just a bunch of regular nodes arranged as cascade like they were created by hand.

I thought a little bit about the problem, and technically the expansion stage could inject special pins bound to constants of the arity and the current level. Maybe it’s a good idea which requires investigation.

I will think more about it. Perhaps, there’s another way which is closer to what we have right now. Never know what you can do with XOD :wink:


#3

input-vlevel could be a hidden accumulator pin that gets initialized (to ?0 or 1?; 1 probably makes more sense since it would match variadic-* and arity #) on entry and incremented for each level. This could be simulated now with dummy pins that would show on node, but should never be used except internally by the node.

I suppose arity is known when you do the expansion, so input-arity could be a special shared pin.

Having these also lets you know if you are on the last iteration when that information would be useful, like for Average function (done totaling, now divide by arity).

Adding these special input pins make the data available to the node, but would not create visible pins when the node is used. Maybe this is where we need a new shape, like a diamond instead of circle for these hidden pins… We would never be able to manually set value for the pins, and there is really no reason to change the name of them. Both pins would be invalid on a node without the variadic-* flag & only one of each pin would be valid per node.


#4

Thank you a lot for expressing what’s on your mind. I’m so glad someone thinks about the core, not only shallow features. I’ve got a pause to ponder, so replying with a delay.

Exactly. So the current level is already accessible, although ugly exposing internals to an end-user.

So many new special rules to remember. Actually, my thoughts were quite similar :wink: And I’m not sure that’s an optimal way both in the sense of development and clarity. I’m scratching my brain to find alternatives which will introduce fewer and/or simpler concepts.

Consider variadic-pass node along with variadic-1, variadic-2, variadic-3. Only one of them is allowed on a patch. Then, if a node foo has the variadic-pass marker on it, all input terminals of foo, which are linked to variadic pins of other nodes contained in the foo become variadic themselves.

As I see it currently, the feature alone should cover most cases. It allows to use a pattern in which a single node is exposed to the public, but inside it is built up using other (possibly internal utility) variadic nodes.

For example, you know how to make a variadic node which outputs the total arity level, great, let’s name it arity-level. Now, we can make an average built from the add, variadic-pass, arity-level, and divide. The variadic input terminal inside average would be linked to the variadic input of add and arity-level at the same time.

Next, on LCD. You can easily make a variadic node to output a string on a given line. It would print, increment the line number, and bypass the next string to a downstream node in the cascade. But you also need the total arity. OK, take it as a shared input, and name the node text-lcd-internal (soon we’ll bring a mechanism to hide internals from Project Browser). Then simply create the public text-lcd built from text-lcd-internal and variadic-bypass. The public node will easily hide the line counter and utility outputs as well by simply not exposing them to terminals.


What do you think? Could it work?


#5

That is an interesting idea…

My 1st thought was that variadic-pass node would not be necessary since it could be implied by input pin tied to variadic input pin, but I guess you could connect input pin to add, etc. without wanting to allow variadic on your node. I guess if you had multiple pins & only wanted one to be variadic on your node, you might have to pass other pins through dummy nodes to hide the variadic inputs from your input pin.

I would think the “hidden” internal-only pins would be easier for not-really-programmer people to understand. Variadic-pass would provide a lot more functionality beyond this simple case, but require an extra wrapper node to get arity-level for many implementations (like your lcd example). I guess I’m saying that variadic-pass could be useful even if we have these internal-only pins. The inernal-only pins would be nice short-cuts for working with arity within the node even if we have variadic-pass. If you don’t want to do the internal-only pin short-cuts, it is easy enough to create documentation to explain how to get that info with wrapper nodes.

What if you have multiple input pins tied to variadic pins on different nodes with variadic-pass? Do you just assume all should have same arity-level? Will there be a way to adjust arity for each? One example would be a grid of LEDs with different arity for rows & columns… I could envision the node label truncated to the 1st variadic pin with a “grip” to the right of each variadic pin to adjust the arity of each one… This would not work for “normal” variadic nodes since you would not know how to cascade the data to expand, but for variadic-pass nodes, you are simply passing data on to normal variadic nodes. Not sure this would actually have a use case in the real world, but it seems like it would be useful…


#6

Thanks for sharing!

Oh, that’s what I was not able to figure out. Quite elegant!

:thinking: Well, maybe the marker nodes themselves could provide two values: the current level and total level.

That’s an interesting question. On one side it brings flexibility, on another side is extra complexity. Can’t now imagine a solution that is intuitive enough yet highly configurable. Not sure multiple grippers will be easy to grasp.


#7

That sounds like an obvious, elegant solution that took way too long to come up with… It would have the side-benefit of making the nodes wide enough to see the variadic count

I was thinking of something like this for 2 variadics:
image
The 1st gripper would change count for the 1st variadic pin. 2nd gripper for the 2nd pin. (This is just 2 over-lapping nodes, but it gives an idea what multiple grippers could look like. The 1st gripper could use a dotted-line to indicate mid-node instead of solid-line implying edge of node.) Most nodes would not show this since it only applies when using variadic-share AND multiple pins are tied to variadic inputs.


#8

Thanks for the feedback!

We have spent some time talking about edge-cases, implementation simplicity, etc and finally, I added an issue to our backlog. Although it contains nothing about the independent arity level adjustment and the “current” values, alone it should cover the vast majority of cases.

The things omitted can be added later as another sugar layer on top of the existing complete system. I think xoders should battle-test the variadic-pass and then it will become clear whether anything other is really required or not.


#9

Bummer. I liked the idea of arity-level & arity-total as output pins on the variadic-pass node. I guess adding them to the variadic-# nodes could also be useful & would eliminate the need for wrapper nodes in many cases.

I hadn’t thought of using variadic-pass-#. That should eliminate the need to hide variadic inputs from the node’s input pins using dummy nodes…

What exactly does this mean?
Not all variadic pins of an inner variadic node are linked to variadic pass input terminals; if such one is linked to a scalar input, it’s value is replicated to the arity level required

I can see two cases for this:

  1. A single internal node with 2 variadic inputs; one tied to wrapper variadic input & the other tied to a scalar. This might make sense to replicate the scalar, but might make more sense to cause an error… If the desire is to replicate the same value, it should probably be implemented as an Accumulator pin and passed through rather than as a Variadic pin.

  2. Different internal nodes with variadic inputs; one tied to wrapper variadic input & the other to a scalar input. Here it should probably be assumed that the internal variadic tied to the scalar input has already been sized correctly and the input should not be replicated. Just because I’m feeding a static pin to an add node (or other node that happens to be variadic) does not mean I want to replicate it to the arity total. It would be very confusing if my add function returned X + Y*(arity total) instead of X+Y… You would basically be over-riding the # in variadic-pass-#

Thoughts on edge-cases:
What happens if a variadic input in the wrapper is passed to a variadic pin on an internal node that has already been expanded (i.e. variadic wrapper input tied to 3rd pin of Add node)? Seems this would have to be an error unless you are going to have your expansion code create an extra wrapper to handle it correctly… If you allow this, can the variadic input be tied to 2nd pin of a 3-pin Add node? I guess technically, 2nd pin of 3 is not variadic, so this should not be allowed.


#10

Yep, it’s about this case. Your logic makes sense. Such behavior effectively demotes the inner variadic pin to a shared pin. But I can’t come with any practical example when it hurts. I can’t imagine where it can help neither. So this point is indeed arguable. Computers can’t decide for us, so we have to settle on either design decision.

Maybe, have you a practical example in mind when the scalar replication will lead to bad things? Or does it sound counter-intuitive enough to be forbidden? I’m in doubt an appreciate your help.

Yes, it will work this way. An inner node extends its arity level only when linked to a variadic input terminal.

That’s the case we have stumbled upon for a moment. A quite elegant solution is to add the arity level, not replace. In other words. If I have an inner add with IN1=10, IN2=50, and IN3 linked to a variadic pass input terminal, the final result will be the sum on the outer variadic inputs plus 60.


#11

It does seem counter-intuitive, but it seems like there might be rare cases where it might be useful… The only case I can think of is an existing node with multiple variadics, so you can’t easily use the shared pin; but existing cases we have of this are select, if-else, etc. where duplicating one of the variadic pins doesn’t make any sense… Seems like it might be safer to flag an error instead of duplicating the non-variadic input; accidentally tying a scalar to a variadic would be a difficult bug to track down if scalar is quietly duplicated (but it would also probably be hard to do accidentally since you wouldn’t have the expected pins to tie to for input when you expand).

I guess I can see it going either way, but I would lean toward calling it counter-intuitive without an example where it would be useful & not better implemented as a shared pin. The counter-argument is that not allowing it would block extra functionality “for no good reason”. I guess I’m not being much help on this one since I can argue both sides :slight_smile:

Yeah…that’s the same result of what I meant by extra wrapper. We could get by without this functionality (just manually cascade an extra copy of the node so wrapper variadic is tied to non-expanded internal variadic), but it would be nice to have & seems a logical extension.

Would you allow tying to a middle pin, or would you require the wrapper variadic to tie to the last pin of the expanded variadic? (i.e. do you allow the 2nd pin of an add node expanded to 3 pins, or does wrapper variadic have to tie to the 3rd pin?) If the latter is easier to program, I don’t see why it couldn’t be a requirement. If it doesn’t make any difference in your expansion code, then I guess you could allow tying to any of the expanded pins.


#12

OK, the decision is not obvious. I think we should forbid the case during the initial implementation and soften the rules later if the real use cases make it desired. The reverse will be harder to do politically.

I’m going to reword the issue accordingly.

That’s a good question. I’m not sure whether it affects implementation complexity anyhow. I see no reason why linking to the middle should be an error, so if we can make it easily, we’ll make it.