LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Follow-up questions from "G Interfaces in LV 2020" webcast (May 1, 2020)


@jordankuehn wrote:

The previous way you would address this in a low coupling method would be to have all types of callers inherit from an empty common parent that has all the methods that are common that I would want to invoke via a message defined in the ancestor and overridden by each caller. It it accurate that this is a problem when the callers would prefer to inherit from something else and makes the inheritance tree messy?


So for a zero-coupled previous implementation, you might instead have considered creating an abstract Message (not Actor) and having each of your calling Actors create a Child of that Message that called one of their messages and used To Specific Type to their (Actor) class type in the Do.vi.

If you wanted to have two of the callers implement it in the same way, you'd still (without inheritance) need to implement the Do action (i.e. the VI being called by Do.vi) twice, once for each class (you could create some public VI that wasn't a class member to do the core bits though, if you wanted). The alternative in that case would be to have two (or more) of your calling Actors inherit from some other Actor, and have that parent provide the child Message from the Abstract Message (in this case, your calling Actors share that behaviour, so making them have an "IS-A" relationship with the parent isn't as likely to cause problems).
Finally you bundle the child Message class into the callee Actor and use that when you want to send the status to the caller (because the caller provides the concrete message).


@jordankuehn wrote:

Now Interfaces are supposed to help with this correct? [...] So then to use interfaces to make this better I would create an interface that holds the common methods, *and then* I would generate and call messages to the interface's methods and not the caller's?


With Interfaces, you can create an Interface with "Receive Status Report.vi" (or however you feel like your calling Actors would like their VI to be called) and have all of the callers inherit from the Interface. Since this isn't a parent-child relationship, you don't contort your inheritance hierarchy (or have to worry about "IS-A status receiver" like concerns)
Then you create just a normal message that can be sent to the Interface. In the Do.vi, you use To More Specific Class to cast the incoming Actor to the Interface, then call the Interface method (Receive Status Report.vi) in the no-error case.

If your caller doesn't inherit from the interface, you'll get the same type of error as normal when you send a message to the wrong type of Actor.

Even though my paragraphs are a little wordy, hopefully the second one is noticeably shorter/simpler than the first!


GCentral
Message 41 of 50
(1,707 Views)

@jordankuehn wrote:

Or have I bungled it all up?


You got it right. Go forth and code! 🙂

0 Kudos
Message 42 of 50
(1,667 Views)

@cbutcher wrote:
Since this isn't a parent-child relationship, you don't contort your inheritance hierarchy (or have to worry about "IS-A status receiver" like concerns)

You will find that LabVIEW *does* call this a parent-child relationship, and that is in part because you *do* have to worry about is-a relationships when inheriting from an interface. The is-a relationship has to be considered in all languages with interfaces... it is weaker than the is-a relationship with an inherited class (because there's no internal state to worry about keeping consistent), but it is still there (because the methods' intended usage do impose limits on behavior). The Liskov Substitution Principle still has to apply for interface to be applied correctly.

 

The similarity of requirements drove LabVIEW's terminology. LabVIEW says a class can have 1 parent class and as many parent interfaces as it wants -- but they are all parents. The Interface Decisions Behind the Design document goes into detail about why we depart from industry terminology here.

0 Kudos
Message 43 of 50
(1,660 Views)

Thank you both! Already most of the way done with this particular refactor.

0 Kudos
Message 44 of 50
(1,634 Views)

I'm jumping into my first interface-based HAL here and I'd like some tips on disk layout.

 

A rough example: let's say I have a need for a generic "voltage source" device. I'd like to be able to use either a programmable power supply or an NI DAQ card. My initial plan is:

 

-a Voltage Source interface

-a Power Supply abstract class that implements the Voltage Source interface

---Concrete child classes e.g., Agilent x12345

-an NI DAQ device abstract class that implements the Voltage Source interface

---Concrete child classes e.g., NI-6366

 

If I want to reuse both the Power Supply and NI DAQ classes in other projects, they both need to reference the Voltage Source interface, correct? How would you lay this out on disk or in SCC? If I have another project that needs Power Supply, it'll still need to know about Voltage Source.

 

It's feeling like (for reuseable interfaces) I should put the interface in vi.lib or at least in c:\dev\interfaces. Basically, it doesn't feel "right" to store the interface in the project folder... but maybe I'm overthinking it.

0 Kudos
Message 45 of 50
(1,593 Views)

@BertMcMahan wrote:

It's feeling like (for reuseable interfaces) I should put the interface in vi.lib or at least in c:\dev\interfaces. Basically, it doesn't feel "right" to store the interface in the project folder... but maybe I'm overthinking it.


This question is independent of interfaces. What you're asking applies to any reusable code that you have between projects. In general, I recommend that you do not put anything in to vi.lib\user.lib\instr.lib (VUI) that is not "finished" -- by which I mean you've published the latest version. Then other projects can use that finished version.

 

My recommendation that feels the most like the way you're thinking about your code is this: You develop all your code in a project that saves *somewhere else*, test it there, and when you're ready, you package that code and deploy it into VUI. That makes the code available for other projects to use. If you package it right, you've made it available for distribution to other machines at the same time.

 

The alternative recommendation I would offer is to use your source code control system and sync down the files from many different "modules" into one place and use them all in one project. By syncing the same SCC source into different places on your disk, multiple projects can use the same files. The same single-sourced code is not be owned by any specific project, and you can easily check in changes to the shared code from whichever project you happen to be working in that day. Generally this solution requires a more sophisticated test plan, ideally integrated into your software gate. This solution avoids VUI entirely.

 

There are other variations for developing modules that will be shared among projects, but these two should be enough to get you thinking about how you want to manage your code.

 

Is it an independently developed module that is independently revised and propagated out to clients? Then choose option 1.

Is it a concurrently developed module owned by lots of clients jointly? Then choose option 2.

If neither option fits your development process, think about who owns the code and what the deployment schedule is, then find a process that works for you.

 

0 Kudos
Message 46 of 50
(1,586 Views)

@AristosQueue (NI) wrote:


This question is independent of interfaces. What you're asking applies to any reusable code that you have between projects.

 


It's confusing me here due to the decoupled nature of the class and the interface. Generally I use your option #1, create a VIPM package, and install it into VUI. This works fine for my current reuse code- but the trouble (for me) comes from having multiple reuse packages using another common reuse package... "two levels" of reuse so to speak. It's probably just me not quite getting it yet.

 

Basically, when I go to reuse part of this library (say I just want Power Supply), I'll need to pull in code from two different repository locations. I'm not quite sure how I want to implement that... I haven't delved into externals yet in SVN, but maybe that's the way to go. It would be good if I can have a "single location" that I can use to get reuse code, rather than having to manually select both the Interface reuse code and the Object reuse code when you're pulling from SCC.

 

Basically having the

0 Kudos
Message 47 of 50
(1,579 Views)

"Bold Italics indicates a redundant parent declaration on this class".

 

 

(FYI This happens (for instance?) when a class has declared a parent interface, and it's child declares the same parent interface. This is visible in the Class properties>Inheritance tab.)

 

Just wandering. Is this bad or just slobby? Are there severe consequences to having redundant parent declarations?

 

I started toying with interfaces, and have to find good morals. Things like location on disk, naming, etc.. I haven't had a real need, but they feel better than inheritance in a few places.

0 Kudos
Message 48 of 50
(1,539 Views)

wiebe@CARYA wrote:

Just wandering. Is this bad or just slobby? Are there severe consequences to having redundant parent declarations?


No consequences... everything works the same in both cases. But I found it confusing when I removed an interface on a child class and then found the interface methods were still listed in the override dialog. My team decided that we should flag it so a user would be aware that one remove wasn't enough, if removal was the user's goal. We discussed whether we should break the child class in this situation, but a) there's no reason for it to be a breaking situation other than pedantry, and b) allowing it does allow some useful parent refactoring without having to edit all the existing child classes. So we let it happen and just make the dialog acknowledge it.

 

So, given that, it definitely is not bad, and it may not even be slobby. If you can clean it off the child classes, I think you should just so future developers don't somehow get the wrong impression about where an interface is introduced, but there's no requirement to doing so.

Message 49 of 50
(1,535 Views)

About the AF projects built with PPL modules. They had to be based on same AF PPL so that you could interact actors (launching nested etc) till now.

In short, all actors of your project had to be based on the same PPL.

Am I right that having an interfaces over Actor Framework classes now, then inheriting from this interfaces in both PPL AF and default AF lvlib you could have actors based on both in the same project and still interact them? (some actors depending on PPL, some on lvlib)

0 Kudos
Message 50 of 50
(1,415 Views)