Jump to content

GregFreeman

Members
  • Posts

    323
  • Joined

  • Last visited

  • Days Won

    5

Posts posted by GregFreeman

  1. I'll just explain my thought process and where I'm at now and you guys can let me know if there is a better or more flexible way to do this....

    I have a listbox with items, and each item will have corresponding information. For example, I may have a listbox of test step names and each test step has associated information about that particular step.

    So, my initial thought was have a "listbox item" class and as part of its private data it could hold a "listbox item information" object. The problem with this is, if I wanted to reuse this listbox functionality on an application which wasn't configuring test steps, but maybe was a list of users and their associated permissions (a class "user permission info"), I wouldn't be able to reuse the "listbox item" class and pass "user permission info" into its private data unless "user permissions" and "test step info" both inherited from "listbox item information". This doesn't really make sense and is too coupled because now if I want to move the test step information class or user permission information class to another project, they are tied to the listbox item information as their base class.

    Hopefully that makes sense up to this point. Lots of words and no picture or UML make it difficult, I know.

    So my next thought (and current solution) is to have a "listbox item information" class which is in the private data of the "listbox item" class. But, I'd create a class called "Test Step Listbox Item Info" which inherits from "listbox item info" and in this class's private data it would have a "test step information" object.

    Now, any time I want to use different item info with the listbox class I can just create a new "<name> listbox item info" class which holds <name> in its private data and everything else should take care of itself.

    (man, UML would help this haha, sorry if you're just as confused at the end as the beginning, I can try to reword...it's late).

  2. Typically abstract classes cannot be instantiated. Attempting to do so will result in a compiler error. In Labview there's no way to prevent someone from instantiating a class, so they don't exist in same sense as they do in text languages. I agree with Paul on what it means for a Labview class to be abstract--it's a regular class that is not intended to be instantiated at runtime. How you communicate that to other developers is up to you.

    Ok, I unknowingly used "abstract" classes, scratch interfaces. Thanks for the link to your IF though; I looked it over last night and that makes sense. I don't currently have a need for it, but like so many other things, it's an idea to have in my "toolbox" so some light bulb goes off the situation arises where I may benefit from the concept.

  3. I am curious why you're so interested in safety. Type safety is fine, but it costs development time to implement. Furthermore, the more safety you build into your app the more time it will take you to change the app when requirements change. Too much type safety will soon have you pulling your hair out every time your customer says, "I was thinking it would be cool if we could..."

    I'm not directly interested in only this, although I see why it came off that way. As I transition to using and fully understanding LVOOP, I just want to make sure I cover all of my bases, and there are certain points I understand more than others. So, some I may hammer home until I understand the best way, then move onto the next thing that I'll repeatedly ask questions about until I understand it fully :P . I assume it will be like learning LabVIEW; I'll just do it, ask questions, refactor it, ask more questions, refactor it then one day I'll realize I no longer have to ask questions and instead can answer them.

  4. As I study this more and adapt it to meet my general needs, I came up with another question. You mentioned providing type safety by passing the slave loop class to the event loop, which forces developers to write methods for the messages. But it seems that this same type safety doesn't hold true for messages sent back to the "master" because the slave loop can get the queue reference directly. Would it be safer to have a "master" class as well which holds the queue ref in its private data and then pass that class to the slave loop instead? Then it would force messages sent to the master to have methods defined.

  5. Command pattern messages (Do.vi) are arguably a more OOPish design, they are more efficient at runtime, and yes, they eliminate the risk of typos in the case structure.

    Name/Data messages (whether they are LVOOP or not) centralize the message handling code, are more familiar to most LV developers, support better natural decoupling, and (imo) require less work to refactor.

    Theoretically command pattern messages are "safer." However, in practice I've found typos to be a non-issue. I write my message handlers so the default case handles any unexpected messages (such as from a typo) and generates an "Unhandled Message" notice for me. On rare occasions when I do make a mistake it is quickly discovered.

    Neither is inherently better than the other. Name/data messages support my workflow and design requirements better. I'll use the command pattern only when I need it. Others swear by command pattern messages.

    Thanks for the responses, guys. Hopefully this will never turn into the OOP version of the string vs. enum debate! I try to keep in mind this is LabVIEW, not c++ or JAVA so sometimes things will not conform perfectly to the generally accepted practices in those languages.

  6. I'm curious if someone can speak to the benefits and drawbacks of having a case structure that takes a string from the message (as is shown in this example), versus something like the actor framework that has a Do.vi that is must override for every message. I feel the actor framework method of message handling is safer because the programmer is required to define a Do method for each message which defines how it is handled. In this example, the programmer still has the possibility of having a typo in his message name or case structure which would not be found until runtime. With the actor framework, it forces you to implement what to do when a specific message is gotten, and if this isnt' defined it is caught at compile time.

  7. Thanks Paul. I actually was just looking at your PDF from NI week yesterday and discussing it with one of my coworkers. Admittedly, it was a bit over my head but I'm taking it in slowly. I will look at the links you have provided when I have some time. I should also make a note that I didn't make in my reply to Asbo, I noticed that with the example link he provided, the concrete class is made to be an attribute of of the interface class. Is this always the case?

  8. Here's an older thread about interfaces in LabVIEW: http://lavag.org/top...0621-interface/

    Thanks! My follow up question to this is then: why have the interface there? It looks like you wouldn't lose or gain any functionality if you stripped out the interface classes, as they have the exact same methods as the top level observer class. If you just had player and spectator inherit directly from observer, you'd still have to implement these 3 methods so what do you gain by putting the interface class in between? Is it just for code readability, or is it to further define the classes that inherit from observer (just in this case they only have the same 3 methods) and then any concrete classes can extend functionality even further? I have attached the UML from the other thread for reference

    index.php?app=core&module=attach&section=attach&attach_rel_module=post&attach_id=406

  9. I have just been reading up on topics of OOP in general and although I've used things similar to Interfaces and Abstract classes in LabVIEW, I didn't realize I was doing it. Due to differences between different text based OOP languages and LVOOP I was just wondering if I could get some of you to speak to these two concepts, whether they both really pertain to LVOOP, and possibly provide some actual examples (not just vehicle, shape, cookie cutter examples, but something I'd actually use) of when you'd define an interface vs an abstract class? I'm basically just looking for general information to help strengthen my understanding of these concepts, and most, if not all, examples out there are text based. While I can figure them out, it's much more time consuming, still leaves me with some grey area, and my brain tends to understand LabVIEW much better in the first place.

    • Like 1
  10. Situation C: You have written a really intelligent XML-to-object parser in that subroutine that is always going to construct the correct child class of the class passed in in the original variant. In that case, this function works fine for all child classes and does not need to be dynamic dispatch at all and the Preserve Run-Time Class is not needed. Note: If you have a parent class of XML Config that is something like "Any File Config", you can then argue that you do need the Load to be dynamic dispatch since you're abstracting which file type is being read. If that's the case then you do need the code as written, but you should wire a constant to the To Variant node so that the conversion to variant will be constant folded and save yourself some performance overhead.

    Situation D: This one works with your code. You do have child classes of XML Config. You are opening the config file and doing enough parsing to extract the name of the class so that you know which child class to create. You create the object and then you read the XML file again using this function. It requires you to do double parsing of part of the XML file (once to get the class name and once to actually parse the data) or it requires you to record the class name twice (once for your pre-reader and once in the actual XML of the object). This solution requires that every class *must* override the parent implementation so that the type wired into the Variant To Data function is the exact right *wire* type for every single child class.

    I think I currently have something similar to situation C in the *note* and maybe situation D. The load method is set to must override in my base class "config". So, I can ensure that every class that inherits from this class will have this load method, so there is no chance the parent class's load VI will be called with a child object on the wire. Is this the point you were getting at?

    I need to digest situation D a little more before I comment on that one in much detail. Are you stating with this situation you could have a parent method which extracts the type of the class in the config file (possibly a child class) then reads the file and casts the variant to the specific data type? I'm afraid I'm not fully understanding this situation and the need for the implementation or the benefits/draw backs as compared to Situation C.

  11. Nice.

    If NI got off their arse and spent time on the event structure, they could easily have included this feature as a native part of the Event structure.

    This along with being able to capture every message posted by windows (which is what I think you are implying anyways). Why can't I get the Window Move message? Instead I have to get mouse down on title bar through the windows API, then register for mouse move within LabVIEW, then handle the mouse move event. Then, on mouse up, I have to unregister for the mouse move event. :angry: Unless, of course, someone has a better way.

  12. Edit due to miswording:

    I'm rooting for you! Let me know if you get it working. Sorry to Ned if I misunderstood. I thought I would still have to poll the DLL to get the user event dll to check for Windows messages, but I guess registering for this event in a DLL would remove that polling, as the DLL would manage the capturing of the message and posting the event in the background?

  13. Not with the Windows Message Queue library as is, but the use of LVPostUserEvent() as mentioned by ned would certainly make that easy. I'll see if I can have a go at it. It would in fact simplify the DLL part enormously, since the whole queue handling in the C code can go away, as the user event will handle that internally.

    I'm rooting for you! Let me know if you get it working. Sorry to Ned if I misunderstood. I thought I would still have to poll the DLL to get the user event, but I guess registering for this event in a DLL would remove that polling, as the DLL would manage the capturing of the message and posting the event in the background?

  14. Unfortunately I'm not very comfortable, but I could still hack something together. I was hoping there was some way to make things more transparent to the programmer, so I don't have to put a polling loop in at all. Similar to callback VIs, you register and then there is nothing else you have to do, the callbacks are captured for me and I can generate user events in the callback VI to feed to my event structure. I was hoping for something similar to that or similar to a message map in MFC. This windows message happened, do this. Basically, I was trying to capture the system messages without having to add any sort of additional loops into my software to monitor the message queue, but I don't think there's an easy way to do this.

  15. I know there is the windows message queue API that can be downloaded, and I have this working fine and am receiving messages. But unfortunately this requires polling the message queue in my application. I'd like to handle these messages as events in an event structure, and I can do that by having a polling loop to manage the message queue, which then fires a user event when the correct message is captured from windows.

    But, is there a way to do this any cleaner, similar to being able to register events based on callbacks?

  16. By using the Variant To Data, you've only guaranteed that the value you're returning is definitely an XML Config value. But I supplied a more specific XHTML Config value to your VI, it's not until you perform the dynamic run-time check with the Preserve Run-Time Class that you can be sure your XML Config wire has preserved the type across the entire VI.

    Does that clear things up?

    Yup, this is pretty much what I was getting at. I think I understood correctly but used improper terminology between object and class when stating "Is it because you could have a child class on the wire, but the variant to data doesn't recognize this". I should have said, "the actual object on the wire is not recognized by variant to data, only the wire type is recognized by variant to data"

    In my brain it made sense; writing it out, not so much.

  17. I can see the benefits and drawbacks of both ways, so I will just have to make a decision at some point. For now I'll leave it as-is.

    My follow up question is this. Why can't the compiler guarantee the classes are 100% the same? Is it because you could have a child class on the wire, but the variant to data doesn't recognize this? I'm just trying to understand what is happening in the background.

    In this case, I know preserve RT class is safe because this VI is must override. So, the only object that can be on this wire is an XML Config object. Therefore, I *should* be able to guarantee this will be safe.

  18. I have some config classes

    Base class: Config

    Child classes: XML Config, INI Config, CSV config, etc

    In the base class I have a load and a save method which must be overriden by all child classes. To read the XML config I am using GXML which returns a variant then I use variant to data to convert to my XML Config class. But, when I wire this output to the dynamic dispatch terminal coming out of the VI, I get a broken run arrow with the error run-time type not propgated from dynamic input to dynamic output terminal. So, I fixed this by using preserve runtime class (see screenshot)

    So my question is as follows:

    1.Is the reason I have to use preserve run time class because if I had another class inheriting from XML config (say class ThisApplicationsXmlConfig) and it didn't have this method implemented, the parent method (i.e. the pictured method) would be called and the variant to data doesn't know the runtime class on the parent wire is actually a child class, so I have to tell it explicitly?

    2. Side question: Does the output class terminal have to be dynamic dispatch or will this cause unexpected results? If I change the output from being dynamic dispatch to just recommended, how does it change the output?

    Thanks.

    post-15770-0-88442700-1345611536_thumb.p

  19. My OOP naivety shows again, but oh well, I'll learn, albeit slowly. I have a "network connection" base class and from it I have some child classes. I want to create a public method to check if a connection is valid. It seems like this is a method that should somehow go in the base class because it will be the same for all classes (check a connection refnum whether it's tcp,udp, etc, and see if it's valid). But, I am not sure how to best accomplish getting the connection refnum which is held in the child class, into the base class. I obviously don't want some sort of public accessor to call to return the refnum to be passed to the base classes method because I don't want the connection refnum available outside the class. But, I was trying to avoid having a "is connection valid" method in every single class also, when it seems a generic method would work fine.

    Suggestions?

  20. Yes, you answered your question correctly!

    In fact, we originally tried to create configuration objects, but

    1) Objects don't have front panel representations. (OK, it is possible to make friend XControls for this purpose, but we did not want to go there.)

    2) We could still put the clusters inside objects (and in a few legacy cases we still do that) but we found it didn't buy us anything--it just added complexity.

    So we just stick with clusters.*

    *For completeness: Note that clusters don't have the same version handling mechanism classes do. In practice, that has not been a concern for us in any way. We only deploy our applications at one site, though. If we had many versions in many places I could envision that we might need some way to convert configurations between versions, although even then I expect that wouldn't be much of a problem, provided the released versions were reasonably stable in the first place.)

    With regards to number 1, yes, that would get old quickly, creating X Controls every time you made a new class. I support your decision haha. And with regards to the "for completeness" part, the versioning built into the classes was the main reason I wanted some clarification on why objects were not used.

  21. The following is our approach, with which we are quite happy:

    We define configuration elements (usually in a cluster).

    Why not have your configuration elements as classes themselves?

    Edit: I may have answered my own question (in question format because I'm not 100% sure), but is it because you need them to appear in the config dialog? The cluster allows you to populate something meaningful to the user on the FP?

  22. I still find myself getting stuck in the "old" ways of coding and somewhat have trouble breaking out of them :angry: . I have a question regarding getting something like user preferences throughout code. The way I have done it for years is I have some preferences dialog and a functional global that manages the preferences xml or ini file. When the program starts, the FG loads the file, then if the user updates the preferences from the dialog and saves, the new data is set in the FG and written back to the file. Now, anywhere I need to access the preferences throughout my code I can just use a "get" case on my functional global to get these user preferences. I know I am only writing to the FG from one place (the actual dialog when the user modifies it), so I don't need to worry about race conditions and such.

    Now, with OOP, I would load all this data into a class. But, my question is, what is the best way to get that class everywhere I need it? I am guessing the general response will be, "it depends!". Is the best option to have the classes that need the preferences data have a preferences data member, and then send a "preferences updated" message to all processes that need it? What if I'm launching a new window that needs it; should it be set in the initialization of the class associated with that Window?

    Just curious what methods others have used. Thanks.

    • Like 1
  23. Just for the sake of my own curiosity, I was wondering if anyone knew what is "wrapped" in the NI builder in order to create installers? Is the .NET Installer class being used to create installers, or something else?

    I was also wondering if there is something like the OpenG MSI Installer Builder that can be used with newer versions of LabVIEW? It seems it can't be used after LV7.1. I really like the idea of being able to customize my installers to look a little less plain during installation. If not, I wouldn't mind throwing my own together if someone could point me in the right direction. Or, even if one does exist, I wouldn't mind writing my own for the sake of learning.

    Thanks.

×
×
  • Create New...

Important Information

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