LabVIEW Idea Exchange

cancel
Showing results for 
Search instead for 
Did you mean: 
wiebe@CARYA

recursive malleable VIs

Status: New

There! I said it 😎.

 

The problem

 

Here's a simple vim that replaces ',' with '.' in a string (half the world uses ',' as decimal separator):

wiebeCARYA_0-1710762498195.png

To support 1D arrays we have to (ouch) duplicate the code:

wiebeCARYA_1-1710762534293.png

To support 2D arrays, we need yet another duplicate:

wiebeCARYA_2-1710762568649.png

So, to support scalars, 1D arrays and 2D arrays, we get:

wiebeCARYA_3-1710762615934.png

I don't advocate nD (n>2) arrays, but duplicate code is undesirable. And this is just a trivial example.

 

You typically run into the lack of malleable recursion when you do serialization (to\from string, (un)flattening, to\from variant) very quickly.

 

Recursive malleable VIs

 

If we could call the vim in the .vim, we wouldn't have any duplication:

wiebeCARYA_4-1710762720925.png

 

So what's stopping recursive malleable VIs?

 

Well, there's a 'minor' issue of infinite recursion.

 

There are 2 relatively simple ways to deal with this.

 

1) Limit the nesting level and break caller if it's reached.

 

We don't need 9D arrays, and certainly not 256D arrays.

 

2) Check if the .vim prototype has been used before and break caller if it is.

 

Let's say the .vim "V" is called with a string 'A'. V" turns 'A' into an array, that in a for loop call 'V' again.

 

That would be a use case for normal VI recursion (calls, managed at runtime), but it shouldn't be possible with malleable recursion (inlined code).

 

 

Spoiler

At least not at first. The compiler could inline each prototype and when called repetitively, use normal recursion. But that would be next level, and maybe not even desirable.

wiebeCARYA_6-1710763869721.png

The scalar string input is simply not a stable input for this malleable VI. It will always result in infinite recursive compiled code. So, this should break the caller.

 

Of course, it should be perfectly legal to have a disabled type specialization case that calls the same prototype. As long as it's not actually compiled, that's perfectly valid:

wiebeCARYA_8-1710764136302.png

2 Comments
fefepeto_kb
Member

In my opinion, there are two separate problems discussed here. One is supporting a scalar method, and then allowing that method to be called by another vim that handles arrays. That is very possible by nesting. See the example: Creating a Custom Sorting Function in LabVIEW. - NI.

 

Having recursion would be a nice feature, but goes slightly against the idea of the inlined code. The compiler does the inlining, meaning that at compile time LabVIEW decides which case shall be baked into the code, without the subVI call overhead.

Calling recursive code is never inlineable, since the number of iterations is not known (even if the VI can be configured to be inlined, the compiler actually won't inline the code).

To solve the problem it might be worth trying to implement a while loop, instead of recursion. On the other hand it results in less readable and less maintainable code. Also, inlining big complex code will likely result in the whole subVI being copied in place, which will end up in huge VIs after compilation. That is also undesirable.

 

Of course, if I got something wrong feel free to correct the information provided.

wiebe@CARYA
Knight of NI

>Of course, if I got something wrong feel free to correct the information provided.

 

Yes, I will try to rebuke some things 😁.

 

>One is supporting a scalar method, and then allowing that method to be called by another vim that handles arrays. That is very possible by nesting.

 

That's not recursion. That's nesting, indeed.

 

You can't make a nested solution that doesn't duplicate code when recursion is required.

 

For instance, To String.vim. You implemented "Double To String". In the [Double] To String, you cannot create a nested vim without duplicating the "Double To String" code.

 

With recursive vims that would be trivial.

 

>Having recursion would be a nice feature, but goes slightly against the idea of the inlined code. 

 

No. That's wrong. The code will be inlined code by the compiler.

 

>The compiler does the inlining, meaning that at compile time LabVIEW decides which case shall be baked into the code, without the subVI call overhead.

 

All the recursive vims will be inlined.

 

That's why the prototype needs to change between recursion levels. If they don't change, there's a loop, and that loop will be infinit.

 

Let's extend the To String example. Let's assume there's a 2D array of a cluster with an array of doubles.

 

These are the prototypes of the recursively inlined vims:

[[ Cluster { [Double] } ]] To String

[ Cluster { [Double] } ] To String

Cluster { [Double] } To String

[Double] To String

Double To String

 

No duplicate code 👍, 100% inlined 👍.