Jump to content

Inheritance and Override Functions in Nested Classes


Recommended Posts

So this will seem fairly long winded but I believe some people here will find this to be an interesting question and hopefully people can point me in the right direction. To give you guys some background I am a process control integrator working with PLC's and CRIO's to create automated solutions for out clients. I have a background in Software engineering and have worked a great amount in the past in Object Oriented languages such as Java or C#. I have only been using LabVIEW for the past 2 years and this is the first time I have utilized the OO features of LabVIEW. 

One of the first things I looked into was if interfaces and abstract classes existed in the OO concepts for LabVIEW. I learned quickly they do not and after looking through the white paper I had a grasp as to why. Which is fine but it lead to the rest of what I am going to explain.

 

The end goal is to create some Equipment control modules based on the S88 standard that is used in process control. Typically an EM would have a Start(),Stop(), and Abort() function. We would like to create a library of these EM’s and keep with an overall good structure using inheritance in a OO style.

 

I can inherit information from a parent class, and I can override the functions from a parent class as well. What is giving me problems however is that I am encapsulating  a parent class object in the child object data area and I am attempting to utilize an override function on this encapsulated object. Our reasoning for an encapsulated object is to allow for dynamic creation of new EM’s that can be utilized by a previously created EM. I would like to be able to abort a parent EM and have that abort any cascaded EM’s that are children of it.

 

With my current setup that I would use in C# I am running into a recursion error. Picture should be attached. I believe I understand the reason for this error, which is that technically we are recursively creating these EM’s and therefore can have essentially an infinite amount in memory to interact with. This wraps into why I was wondering in the first place about interfaces and abstract classes. If my top Object was actually a interface instead of an actual class you would be able to declare it but it would not be instantiated until a constructor created the more lower down classes. This would get rid of this recursive error as I could check if the child EM is instantiated before I decided whether a function could be utilized on it.

 

So my question to everyone is, is there a work around that would give me the same result or is there a more LabVIEW acceptable way to do this?

 

Attached is my UML diagram, the error I am receiving, and the LabVIEW Project that I created to attempt to demonstrate the architecture I wanted. Thanks for any help!

 

 

 

 

Error Pic.PNG

ClassOOTest.zip

UML.PNG

Link to post
Share on other sites
3 hours ago, ARC5200 said:

So my question to everyone is, is there a work around that would give me the same result or is there a more LabVIEW acceptable way to do this?

I don't have LabVIEW 2015 on my home PC so I can't open your code, but I'll hazard a guess:

 

3 hours ago, ARC5200 said:

I believe I understand the reason for this error, which is that technically we are recursively creating these EM’s and therefore can have essentially an infinite amount in memory to interact with.

I'm not convinced that the error message is talking about recursive object creation, because it clearly flags Abort_EM.vi is the problematic VI. It sounds more like LabVIEW doesn't want to let you call a VI that eventually calls itself again. Do my 2 points above help?

However, if it is indeed problematic to include an Abstract Equipment Module instance as a member of the child class, try storing the member as a Variant instead of an Abstract Equipment Module. (You will need to convert the Variant back to an Abstract Equipment Module before running its member VIs).

Link to post
Share on other sites

I don't quite understand, Why do you need to store Equipment Module in a class that inherits from Equipment Module? Child classes can have access to the Parent's data through accessor functions and don't need to maintain a separate copy of the parent.

Also what is the difference between the Interface Equipment Module and the Abstract Equipment Module? As I understand it, neither an Interface nor Abstract class should provide code for the defined functions. I looks to me like that should be one class.

Link to post
Share on other sites

Ryan,

 

 

2 hours ago, Ryan Podsim said:

Also what is the difference between the Interface Equipment Module and the Abstract Equipment Module? As I understand it, neither an Interface nor Abstract class should provide code for the defined functions. I looks to me like that should be one class.

Interface and Abstract Equipment are different because of the nature of the class types in "most" object oriented languages. Interface is a class that basically contains empty methods and no data. Abstract classes can have data and can either leave empty methods or declare them. I say most because in Labview this is not the case because Interfaces does not exist. So you are correct in saying that it should be one class. The UML I provided was based on what I wanted to do based on what I would have done in other languages.

2 hours ago, Ryan Podsim said:

 

I don't quite understand, Why do you need to store Equipment Module in a class that inherits from Equipment Module? Child classes can have access to the Parent's data through accessor functions and don't need to maintain a separate copy of the parent.

 

The idea was not so much about data from the parent to the child but to have the ability to cast that Parent EM into it's own child EM that I can use later. Lets say I have a Valve EM and I have a request to have that Valve EM control a TC EM. Instead of having to drag another EM class VI onto my top Level VI's I would have the ability to dynamically create the object utilizing the internal EM. I hope that makes a little more sense.

 

JKSH,

 

I think I understand what you are getting at. Let me try a few of these things and then get back to this topic.

 

Thank you guys for your help thus far.

 

Link to post
Share on other sites

ARC5200: Here's another example similar to the linked list example written in LV 8.5.

What I did in that old example still works today, though there's some cleanup I could do on the code in a more modern editor... still, it should give you code you can load and look at for inspiration.

 

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Similar Content

    • By Marko Hakkarainen
      I had some time to learn about new interfaces and finally I could implement my collection class as I had envisioned. I didn’t want to use iterable and iterator names, because I thought that would have been too bold a claim.
      The original version of the collection class was (and is) used as a collection of sequence steps. Each element can be either a sequence command (send message, wait timer, wait complete etc.) or another collection of commands (sub-sequence). That’s the reasons for the labels and search method. Otherwise it is just a fancy (Rube Goldberg) array.
      Next method is recursive and it steps through all elements in the collection. Execute is only method, which requires override.
      For now, it’s at least an exercise in new interfaces. I don’t know if it’s useful enough to be in the code repository, but I can polish it up if needed.
       
      --
      Marko H
      Certified LabVIEW Architect
      www.optofidelity.com
      Iterable Collection LV2020.zip
    • By McQuillan
      Hi Everyone,
      I (re)watched James Powell's talk at GDevCon#2 about Application Design Around SQLite. I really like this idea as I have an application with lots of data (from serial devices and software configuration) that's all needed in several areas of the application (and external applications) and his talk was a 'light-bulb' moment where I thought I could have a centralized SQLite database that all the modules could access to select / update data.
      He said the database could be the 'model' in the model-view-controller design pattern because the database is very fast. So you can collect data in one actor and publish it directly to the DB, and have another actor read the data directly from the DB, with a benefit of having another application being able to view the data.
      Link to James' talk: https://www.youtube.com/watch?v=i4_l-UuWtPY&t=1241s)
       
      I created a basic proof of concept which launches N-processes to generate-data (publish to database) and others to act as a UI (read data from database and update configuration settings in the DB (like set-point)). However after launching a couple of processes I ran into  'Database is locked (error 5) ', and I realized 2 things, SQLite databases aren't magically able to have n-concurrent readers/writers , and I'm not using them right...(I hope).
      I've created a schematic (attached) to show what I did in the PoC (that was getting 'Database is locked (error 5)' errors).
      I'm a solo-developer (and SQLite first-timer*) and would really appreciate it if someone could look over the schematic and give me guidance on how it should be done. There's a lot more to the actual application, but I think once I understand the limitations of the DB I'll be able to work with it.
      *I've done SQL training courses.
      In the actual application, the UI and business logic are on two completely separate branches (I only connected them to a single actor for the PoC) 
      Some general questions / thoughts I had:
      Is the SQLite based application design something worth perusing / is it a sensible design choice? Instead of creating lots of tables (when I launch the actors) should I instead make separate databases? - to reduce the number of requests per DB? (I shouldn't think so... but worth asking) When generating data, I'm using UPDATE to change a single row in a table (current value), I'm then reading that single row in other areas of code. (Then if logging is needed, I create a trigger to copy the data to a separate table) Would it be better if I INSERT data and have the other modules read the max RowId for the current value and periodically delete rows? The more clones I had, the slower the UI seemed to update (should have been 10 times/second, but reduced to updating every 3 seconds). I was under the impression that you can do thousands of transactions per second, so I think I'm querying the DB inefficiently. The two main reasons why I like the database approach are:
      External applications will need to 'tap-into' the data, if they could get to it via an SQL query - that would be ideal. Data-logging is a big part of the application. Any advice you can give would be much appreciated.
      Cheers,
      Tom
      (I'm using quite a few reuse libraries so I can't easily share the code, however, if it would be beneficial, I could re-work the PoC to just use 'Core-LabVIEW' and James Powell's SQLite API)

    • By Zyl
      Hi everybody,
       
      I'm running into something I don't really understand. Maybe you can help me here !
      I've got a LVLIB that is used as an 'Interface': it exposes public VIs which wrap around public functions of a private class (see code attached) . The class is private because I want to force the users to use the 'interface' functions.
      In one of my interface VI, I create a DVR on the private class (Interface_init). The DVR is stored into a typedef (FClass_DVR.ctl) and this typedef is the 'reference' that link all the interface public functions.
      In TestCode.vi (which is not part of the lvlib and illustrates the standard code that a user can create to use my driver), I can call my public interface functions and link them without any problem.

      But as soon as I create an indicator on that reference (to create a state-machine-context-cluster for example), my TestCode VI breaks !

      The error returned is : This VI cannot use the LabVIEW class control because of library access scope. The LabVIEW class is a private library item and can only be accessed from inside the same library or libraries contained in that library.
      I understand that the class is private. But the DVR is contained into a public control. Using an In Place structure on that DVR into TestCode would not work, since the class is private. So why is the DVR control problematic at that point ? Creating it do not breaks any access protection...
      Am I missing something ?
      DVR Private POC.zip
    • By Brains
      Hi,
      Does anybody know the best way to make a copy of a byref object (open gds v4) at runtime and pass all the attributes values (including inherited attributes) to the new object?
      Thank you!
      Craig
    • By GregFreeman
      I currently have a project that I am refactoring. There is a lot of coupling that is not sitting well with me due to typedefs belonging to a class, then getting bundled into another class which is then fired off as event data.
      Effectively, I have class A with a public typedef, then class B contains ClassA.typedef and then class B gets fired off in an event to class C to be handled. Class C now has a dependency on class A which is causing a lot of coupling I don't want.
      For my real world example I query a bunch of data from our MES, which results in a bunch of typedef controls on the connector panes of those VIs. Those typedefs belong to the MES class. I then want to bundle all that data into a TestConfig class and send that via an event to our Tester class. But, now our tester has a dependency on the MES.
      I see a few ways to handle this. First is move the typedefs currently in the MES class, to the TestConfig class. The MES VIs will now have the typedefs from the TestConfig class on their connector panes, but at least the dependency is the correct "direction." Or, I can move the typedefs out of classes all together, but then I am not sure the best way to organize them. Looking for how others have handled these sorts of dependencies.
       
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.