[Originally published on 2018-07]
Malleable VI – is cool feature, which was introduced in LabVIEW 2017. As LabVIEW help tells (http://zone.ni.com/reference/en-XX/help/371361P-01/lvconcepts/malleable_vis_intro/):
A malleable VI (.vim) is a VI that is inlined into its calling VI and can adapt each terminal to its corresponding input data type. With malleable VIs, you build a VI to perform the same operation on any acceptable data type instead of saving a separate copy of the VI for each data type.
At the first look, malleable VI acts as polymorphic VI, because it adapts its terminals to input data types. But in case of polymorphic VI, it consists of multiple VIs, which implement particular data type. Malleable VI works differently – it is a single VI, and decision to which data type it must be adapted is done at edit time, when particular data type is connected to its terminals. The simplest shipping function – and I believe it is/will be – from now and on mostly used function, is Stall Data Flow.vi, and a bit more complicated functions could be found in Array pallete, and others.
But, in LabVIEW 2017 SP1 was introduced new feature of malleable VIs – class adaptation. What is it about? Let’s take a bit closer look on it.
The most common example, which you could find in different blog articles and LabVIEW shipping examples – is interface implementation. It means that now it is possible to implement interface class, which will have some methods, and implement corresponding malleable VIs for them. Then, one could implement other classes, which are out of interface class hierarchy, but they could use its malleable VI. Condition is simple – they should implement method with the same name and connector pane pattern, as malleable VI calls. Let’s check the example.
Class nameInterface.lvclass has method Get Data Name.vi. Also, malleable VI Get Data Name.vim calls method Get Data Name.vi.
Then, we create class dataPayload.lvclass, and add there method Get Data Name.vi. After, we connect dataPayload.lvclass to malleable VI Get Data Name.vim – and it works!
Moreover, we could create childs of dataPayload.lvclass, and they could call malleable Get Data Name.vim without any issues.
Thus, our class nameInterface.lvclass (by the way, please, don’t ask why I’ve called it like that) acts as interface – because we could decouple our dataPayload.lvclass from application, by calling “just” nameInterface.lvclass method.
Figure what happens under the hood? Let’s convert malleable VI to standad VI (by right click -> Convert Instance VI to Standard VI).
As we could see, there is added Disabled Structure, and its Enabled page has method Get Data Name.vi of dataPayload.lvclass. So, at edit time, LabVIEW could decide which method to use. And if such method would be dynamic dispatch, this decision – which particular child’s method to use – would be done at run-time.
Of course, in this example we just use parent method; but on the other hand, we could create such methods just in child classes, and it would work also.
Also, we have now the same connector pane data types – in both cases, string is returned.
But, as it is described in LabVIEW example for class adaptation, class methods should have same connector pane pattern – means, that data type could be different. And this is already more interesting, because we could create kind of “universal” data accessors methods.
Usually, classes maintain their data internally, but at some point we need to read it, and write it to class. For this purpose, we need to create static methods, which could be used just for this class (or its childs), because they handle different data types at input/output terminals.
But, malleable VIs could help us to solve this issue.
Let’s add to interface class two more methods, and two more malleable VIs, which will call those methods – Set Data Value and Get Data Value.
Its implementation of malleable VIs is like the following:
And, Set Data Value.vim has additional code in Ignored case – if not accessible data type will be connected, VI will not be broken, but would generate an error message.
Now, let’s create accessor methods in numericPayload and stringPayload classes. Note, that as accessors will have different data types, we can’t have such a method in parent class – because either it will be dynamic dispatch, or static dispatch, LabVIEW will not allow us to create such a method. In one case, dynamic dispatch methods will force to have same connector pane; in the second case – child classes will try to override parent’s static method, which is also not allowed.
Thus, we need to create Get Data Value.vi and Set Data Value.vi just in child classes. Let’s create them like this:
Now, if we will connect numericPayload.lvclass to input of Set Data Value.vim malleable VI, Data input will not change its type:
But if we will connect numeric data type, input type will changed accordingly:
Now, we could finalize the example in the following way; and it will work nicely:
Personally for me, such accessors VIs seems to be confusing. First of
all, one could connect there really any data type (in this case, to variant
input), and it will not be broken. Thus, it is not kind of API, it does not
leads me to keep proper data types maintaining.
But also, I could change connector pane pattern, for example, of Set Data Value.vi of numericPayload.lvclass – and it will still work! Just check it:
And it is something weird, isn’t it? Or do I understand/so something wrong with all this malleable VIs stuff? Connector pane patterns are different, but still LabVIEW could compile the code into working VI.
So, actually that’s it. No doubts, that malleable VIs are powerful mechanism, which will do life much easier, but for sure, if it’ll be used in wrong way, it could cause more mess/unexpected results in the code. But it worth trying it, and investigate it deeper than this short blog article =)