06-13-2018 06:38 AM - edited 04-02-2019 07:40 AM
NEW! Updated the code to be more understandable.
This might be nothing new to some of you but I decided to document a specific way how I solve the problem of interfaces in LV. Please have a look at this and let me know what you think.
Its essentially a way how to achieve the last two letters of SOLID design principles in LV. For those that are more fluent in text based I included a Python example doing the same thing.
Since I have not stumbled upon this technique before I decided to name it Class Translation. It is also knows as Twin Pattern on Wiki. There might be a better name, please recommend some.
06-14-2018 01:49 AM
Hello Piotr,
could you, please, downconvert LV example to lower version (at least LV 2017)?
Thanks a lot,
Sincerely, kosist90.
06-14-2018 01:55 AM
06-14-2018 02:32 AM
Thanks a lot!
06-14-2018 02:44 AM
Please let me know guys what you think, also if you have any questions, and I will try to answer all the questions in the video I will record soon.
06-14-2018 06:30 AM
Quite interesting topic, Piotr; but I miss example more close-to-real-world tasks...
For example, could I use this approach for the following task?
Imagine, that I have plugins for DMM and Switch, as separate devices. And now, I have physical device, which consists of DMM + Switch.
Device's drivers allow to logically separate DMM and Switch functionality. Thus, I wanted to reuse plugins to control this device.
I've asked on forum here, and I was adviced to create class, which will be composed of my two plugins, and reuse them there.
But as device had to be inited just once, I had to modify DMM and Switch plugins in a way, that I passed initialized reference into the plugins. Normally, these plugins initialize reference by themself, they don't have accessors methods to write this reference; but in this case it could cause initialization of communication reference twice.
And this is what I actually didn't like a lot - because such behaviour of plugins is application-specific, and in more general case I don't need to do it. So for sure I broke one of SOLID principles.
Could I solve the task using this classes mutations? If so, then how, please? What should be the approach then?
Thanks a lot,
Sincerely, kosist90.
06-14-2018 09:00 AM
Hey Piotr,
That certainly is an interesting approach. I can see how your turned the interface notion into a component with a finite lifetime, as we would treat it in some other languages. I can see the ISP principle being (partly - more to come) respected as you A class does not depend on MeasA until it implements From MeasA.vi and To MeasA.vi.
However I'm concerned about one thing: in the example, your interface is MeasA, not IMeasurement. And MeasA depends on A (contains A and will most likely use its members in Measurement.vi). I see it as a dependency inversion principle violation.
I also have a very LabVIEW-specific feedback. In From MeasA.vi, you will make an extra copy of A. One fork will lie into the MeasA object, and the other one is returned from FromMeasA.vi as its private data is different. In a case where a A object is very large, that could be a problem. Considering a Swap with a default A object might be a workaround for this - and makes sure your MeasA interface cannot be properly used after From MeasA has returned.
Honestly, about my first note, I don't have a solution, interfaces have been a very hot topic for the OO LabVIEW users, heh.
Eric M. - Senior Software Engineer
Certified LabVIEW Architect - Certified LabVIEW Embedded Systems Developer - Certified LabWindows™/CVI Developer
Neosoft Technologies inc.
06-14-2018 11:18 AM - edited 06-14-2018 12:53 PM
I agree with both points you made Eric. The relationship between the classes is complicated in this approach. MeasA depends on A, and A depends on MeasA. I see this as a necessary evil to be able to implement mutation mechanism. This dependency however is quite limited and does not, in my view pose any problems, other than a philosophical red flag. This is because in my view MeasA is in fact part of A i.e. you should consider them one entity, divided into two classes. Similar to partial classes being defined in two separate files. Or in fact similar to messages and actors in actor framework, where each message is defined for the actor and they are grouped in a library. If you see it differently please explain to me a hypothetical situation, where it would pose a problem.
In relation to potential memory duplication your solution is very good. In the end the mutation methods getting back the original should not return the interface class output.
06-14-2018 12:07 PM - edited 06-14-2018 12:49 PM
Hejka kosist90, you can certainly do the DMM+Switch with the mutation mechanism. You simply create two interfaces for DMM and for Switch. Your specific class will the have a total of 4 mutation methods: ToDMMInterface, FromDMMInterface, ToSwitchInterface, FromSwitchInterface. You can then have a wire in your design with your original object, and when you reach a place where it should behave like a DMM you call ToDMMInterface, run the DMM methods and mutate it back into original. Then you can turn it into Switch and back etc. The extra space taken on the diagram can be minimised by making the icons of the mutation methods much smaller than normal.
Second part of your problem is more related to session based nature of specific references, which is not directly addressed by the mutation mechanism.
06-14-2018 01:00 PM
Have you seen Andrei's AZ interface? How do this compare to that? It looks very similar.