Jump to content

LVOOP and Message Objects (LapDog mainly)


Recommended Posts

Hello everybody, I hope Daklu can add some input to this question but it may apply to LVOOP in general so here goes.

Background: I am using LapDog messaging to send Objects as messages. I have classes which are children of Message.lvclass. The DeQueue message element is, I believe, an object of Message.lvclass

Problem: It is not possible to direclty wire the message output from "DeQueue Message" to the input of a Message child class object's vi.

Here is how I wired it with failure:

post-15786-0-75148400-1329246094.jpg

This was a success:

post-15786-0-66051000-1329246487_thumb.j

Is there a more correct way of doing this? Ultimately, I would like to have dynamic dispatch vi's that DO based on the class of message from the DeQueue vi. Thus avoiding much of the need for the case structure. Actor Framework-ish without the strict overhead.

Edited by jbjorlie
Link to comment

The DeQueue message element is, I believe, an object of Message.lvclass

Close. DequeueMessage is a method, not an object, of the Message class.

Problem: It is not possible to direclty wire the message output from "DeQueue Message" to the input of a Message child class object's vi.

Correct. That gives you a compile error (broken run arrow) because there's no way for the compiler to guarantee the object on the wire during execution will be a LaunchView object.

Is there a more correct way of doing this?

That's what I do when I'm casing out based on message name. I wouldn't say there's a "more correct" way of doing it, but there are "different" ways of doing it, from wrapping the DequeueMessage and downcast in a sub vi to subclassing the MessageQueue class.

Ultimately, I would like to have dynamic dispatch vi's that DO based on the class of message from the DeQueue vi. Thus avoiding much of the need for the case structure. Actor Framework-ish without the strict overhead.

That's the command pattern and it's easy to implement in LapDog.

1. Create a class called "Command" and make it a child of the Message class.

2. Add a single dynamic dispatch method named "Do."

3. Change your messages to inherit from Command.

4. Add a Do method to each message with the appropriate execution code.

You'll still need use the To More Specific Class assertion to downcast the Message wire to a Command wire before connecting to the Command.Do method. If that really bothers you there are various things you can do to hide the downcast from users, from wrapping the DequeueMessage method and downcast in a sub vi to creating a new CommandMessageQueue class.

  • Like 1
Link to comment

Thank you, that pretty much clears everything up! I do already have this "Command" class except I named it "Messages". Hope that name is OK...

Not really a problem adding the downcast & I understand the "why" better now. Could I put the downcast into the Command class Do.vi and then override it for all my child Do methods? I have trouble understanding the override in general vs. the Dynamic Dispatch. For example, in the Actor Framework, there is an ActorCore.vi override where the parent ActorCore.vi unbundles xxxQueue from the parent class and uses it for Do message receiving... How is it possible to work on the parent object when the input object is a child which may not have xxxQueue in its object cluster? Does a child class also contain all the info of its parents?

That last part is probably a new topic but also probably something obvious & I don't want you guys to exile me to the dark side... :oops:

Link to comment

Answering your own questions? Nice! Soon you wil be answering others too!

Just remember it is a 'Cluster of class private data' so your only access to a class's data including a parent class is through methods and properties. Sometimes, you purposely prevent children from reading or writing to your private data by not providing property VIs.

Also, I doubt fellow LAVAG folks will exile you. In my opinion, it is important to answer these kind of questions. LVOOP is a great tool and helping out is a great way to expand its use. Interestingly, I am the only developer on a LV development staff of 4 full time and 2 contractors that follow LAVAG. Probably explains why or code is in the state that it is. I have tried to get them to regularly read the posts but they seem intimidated. Good grief!

Link to comment

I have tried to get them to regularly read the posts but they seem intimidated.

You can lead a horse to water...

(Why would they be too intimidated to read the forum?)

Thank you, that pretty much clears everything up! I do already have this "Command" class except I named it "Messages". Hope that name is OK...

It's okay in that there won't be any naming conflicts with LapDog. My personal opinion is the class name should describe what the class is. Typically if I have a plural class name it's because the class is a collection of items. "Messages," to my way of thinking, is a collection class that holds multiple messages. Additionally, your Messages class is just one particular kind of message--a command message. There may be other messages that are not command messages in your application. My preference would be to name the class "CommandMessage."

[Edit - I rename classes and methods a lot as the code evolves--it helps keep the code readable.]

Could I put the downcast into the Command class Do.vi and then override it for all my child Do methods?

Nope, at least not the way I think you're thinking about doing it. Since the DequeueMessage method output terminal is a (LapDog) Message class, you'll need to downcast to your CommandMessage class in order to wire it to the Do method. The Message class doesn't have a Do method, so trying to connect CommandMessage.Do will give you a compile error.

Downcasting (and upcasting, to a lesser extent) tends to trip people up when learning LVOOP. I know I struggled with it a bit. The key for me was realizing we are downcasting the wire type, not the runtime object. In LV when you create an object, that object will always and forever be an object of that class. It will never be an object of its parent class or child classes.

Labview's on-the-fly compiling feature tends to blur the line between edit-time and run-time. LVOOP is a lot easier to understand when you conciously distinguish between the two ideas.

I have trouble understanding the override in general vs. the Dynamic Dispatch.

They are essentially the same thing. Technically, "Dynamic Dispatching" is what happens during program execution when the LV runtime engine chooses whether to execute the parent vi or child vi. "Overriding" is a more general term that usually means, "create a method in a child class with the same name and conpane as a method in the parent class." It's something the developer does, not the runtime engine. They both refer to using the inheritance feature of OOP.

[Edit - I was thinking about this a bit more and decided that statement isn't accurate. "Override" is context dependent...

"You should override the CommandMessage.Do method in each CommandMessage child class."

"During execution the child class' Do method overrides the parent method on the block diagram."

Both are legitimate uses of the word, even though one refers to developer activity and the other refers to runtime activity.]

  • Like 1
Link to comment

Could I put the downcast into the Command class Do.vi and then override it for all my child Do methods? I have trouble understanding the override in general vs. the Dynamic Dispatch.

You could make a new non-dynamic dispatch VI that takes a Message object, downcasts to Command, then calls the (dynamic-dispatch) Do method. Call this VI “Do Command”” or “Do if a Command”, or something. Note that it doesn’t need to be a member of “Message” class (or any class).

— James

BTW, you could also make the “Do if a Command” VI return the original message if it isn’t a “Command” (this output would return a null message if the command was executed). That would allow you to put it in front of your case structure, acting sort of as a filter for Command Messages.

Link to comment

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 Ryan Vallieu
      I have seemingly found an issue with the shipping example code for Nested Malleable VIs.  Another user has verified that he saw the same behavior in 2019.
       
      I am working through the examples and the presentation from NIWeek 2019.  In running the Lesson 2b code (C:\Program Files (x86)\National Instruments\LabVIEW 2019\examples\Malleable VIs\Nested Malleable VIs) I found the Equals.vi in the class was not being leveraged and the search failed.  When I went to my LabVIEW 2018 machine and ran the Lesson 2b.vi the code worked to find the element by correctly leveraging the in-class Equals.vi.
      One difference I see is that in the 2018 example the Equal.vi is in the example folder with the code, and in 2019 the Equal.vi has been moved to VI.lib - otherwise the code looks to be the same.  The Equals.vi code looks identical, and the calling VIM look identical.  I posted on the LabVIEW NI.com forum here: 
      https://forums.ni.com/t5/LabVIEW/LabVIEW-2019-Malleable-VIs-Shipping-Examples-Lesson-2b-Nested/m-p/3966044/highlight/false#M1129678
       
      I am trying to determine what may have broken or changed between the implementation in 2018 and 2019, visually the code looks the same.
    • By Voklaif
      Hello all,
      I am programming with LabVIEW for around 2 years and was recently stumbled upon LVOOP.
      I am required to write a communication protocol to work with a micro-controller, which later will be also used for ATP and debug purposes.
      I want to build the program "correctly" from the beginning so it will be maintainable and flexible to additions and changes.
      My natural way of building a program would have been a queued state machine, with several loops, each loop is in charge of a different module (one for GUI obviously), but as I stated in the beginning, I want to use LVOOP.
      Does anyone have a LVOOP project I can use as reference? I've searched online and found some nice examples, but they are small and teach you the basic stuff.
      For me it's important to see the how to use the project tree wisely, where to place the classes, see the managing loop and to learn as much as possible before I create one of my own.
      Thanks in advance,
      Voklaif
    • By GregFreeman
      I have an array of classes, let's call the object TestPass, of size 1 (but it is an array because it can scale out to multiple test passes). In this class, there is one other nested class which is not too complex, then various numeric and string fields to hold some private data. There is also an array of clusters. In this cluster there is a string, two XY pair clusters, and an integer. Not very confusing.
      This array of clusters gets fairly large, however, upwards of 80-100k elements. What I am finding is when I index the array of pass classes it is crazy slow. On the order of 30 ms. Doesn't seem like much, but we are indexing the array in our method to "Get Current Pass" which is used in various places throughout our code. This is adding potentially hours to our test time over the 80k devices we are testing. 
      So, I started digging. When I flatten the class to a string and get the length, it's 3 mb. But, when I run the function with the profiler is is allocating close to 20 mb of memory!
      My gut feel was that the string is causing the issues. So I removed the string from the cluster and the index time went to 0 ms. 
      Luckily we can normalize a bit and pull the strings out of the cluster since a lot of them are duplicates. But it makes our data model a bit uglier. 
      Has anyone seen these kind of performance issues before? I saw them in 2013 and 2017.
    • By ted Francis
      I am new to LVOOP and have jsut started writing my first LVOOP program which I have attached.
      I would appreciate greatly help with the question I have
      Thank you in advance 
      Ted
      This vi will perform two tasks 
      1.Generating Report data sheet for metrology 
      2. updating the scales in a MAX .nce file
      1. Metrology will input calibration information into the tables on the tabs
      Metrology will then click "Update Tables" then "Create Report ( create report section of code is not yet written
      Update Tables will write all information entered in the tabs to class varaibles and will also delete current Max informatiomn
      2. Metrology will click "Load NCE Scale"
      vi will prompt for nce file to load and then once file is selected, display existing scales for two channels (Current Motor 1 and 
      Current Motor 2)
      Metrology will then click "Update Scales"  the program will replace the existing scales with those entered in Step 5.14 and 5.15
      from the tables on the tab
      Question 1.  Steps 5.14 and 5.15 are needed by both classes ( Table Variable and MAX) - what is the best way to share this information
       
      CAT0000032 Class Version.zip
    • By shoneill
      I was browing through the actor framework discussions on the NI site yesterday and I came across a statement by AQ.
      Never inherit a concrete class from another concrete class
      I had to think about that for a second.  The more I think about it, the more I realise that all of the LVOOP software I have been writing more or less adheres to this idea.  But I had never seen it stated so succinctly before.  Now that may just be down to me being a bit slow and all, but in the muddy and murky world of "correct" in OOP-land, this seems to be a pretty good rult to hold on to.
      Are there others which can help wannabe plebs like me grasp the correct notions a bit better?  How about only ever calling concrete methods from within the owning class, never from without?  I'm learning for a long time now, but somehow, my expectations of LVOOP and the reality always seem a little disconnected.  AQs statement above helped crystallise out some things which, up to that point, had been a bit nebulous in my mind.  Well, I say I'm learning..... I'm certainly using my brain to investigate the subject, whether or not I'm actually LEARNING is a matter for discussion... The older I get, the less sure I am that I've actually properly grasped something.  The old grey cells just seem to get more sceptical with time.  Maybe that in itself is learning...
×
×
  • Create New...

Important Information

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