Jump to content

By-Reference Class without embedded subVIs


Recommended Posts

Hi,

We all know the lack of by-reference LVClasses. There has been some community implementations of by-reference LVClasses but they all include files such as "Get data and lock". For each separate class, one needs to create a separate copy of these "embedded subVIs". Furthermore, since method names are not allowed to collide, the name of these embedded subVIs needs to differ in each separate class. This naming issue prohibits one to just save a copy of a template class to create a new class as then subVI names would collide.

I've had an idea. Why not to replace the embedded subVIs like "Get data and lock" with XNodes. These XNodes would adapt to each individual class they are used in and there would be no need to embed these XNodes to the class itself. On the contrary they could reside on common location such as user.lib or similar.

I've tried to write such an XNode. The problem keeping me from finnishing is that XNodes run in a different application context and therefore they don't know about the open classes in the development context.

I attatch my project to this post. There is a XClass.lvproj file which contains a sample class. The class has a control Class Private Data.ctl that defines the class private data members. The class built in control contains a queue reference so that the class would act like a by-reference class. The queue type is defined by Class Private Data.ctl. The class method Get Element Template.vi is what I'd like my XNode to do (see image below).

The XNode is in a subdirectory Get Data. It has a few abilities that control how the XNode behave. It can detect when a LVClass in connected to it's object in input and it can adapt to this type. The problem is that this is not a valid type inside the XNode. So the code generation succeeds but the code remains broken.

Jim's XNode challenge was a good starter for this project. I give you a little more challenging task, make this XNode work. If this XNode works, then we'd have a very nice implementation of by-reference classes not far away.

Tomi

post-4014-1170423841.png?width=400

Download File:post-4014-1170423749.zip

Link to post
Share on other sites
I've had an idea. Why not to replace the embedded subVIs like "Get data and lock" with XNodes. These XNodes would adapt to each individual class they are used in and there would be no need to embed these XNodes to the class itself. On the contrary they could reside on common location such as user.lib or similar.

Tomi,

This is a really great idea! I truly hope that we can make this idea work. I love the idea of having not having to carry around the GOOP Core VIs -- XNodes are the answer. Actually, they could also be the answer to the same problem for more traditional GOOP frameworks!

I've tried to write such an XNode. The problem keeping me from finnishing is that XNodes run in a different application context and therefore they don't know about the open classes in the development context. [...snip...] It can detect when a LVClass in connected to it's object in input and it can adapt to this type. The problem is that this is not a valid type inside the XNode. So the code generation succeeds but the code remains broken.

When you say "this is not a valid type inside the XNode" do you mean that the code inside the facade (XNode instance) or the code inside the ability VIs? If it is the latter, then you should be able to get the Application context (reference) from the Diagram reference that is passed into it. If it is the former, then I'm not sure how to solve the problem. Maybe an NI developer can point to a solution, assuming that they can be convinced that XNodes exist :shifty:

Also, is there any way to inspect the code behind the facade of an XNode instance? It certainly would make debugging a whole lot easier.

Thanks,

-Jim

[uPDATE] I figured out the answer to my own question. The ini key XNodeWizardMode=True enables an XNodeWizardMenu>>GeneratedCode right-click menu option that opens the XNode facades block diagram.

Link to post
Share on other sites
When you say "this is not a valid type inside the XNode" do you mean that the code inside the facade (XNode instance) or the code inside the ability VIs?

There is no problems editing the ability VIs, all the problems occur at the runtime of the ability VIs so in that manner they are XNode instance related. First the "Adapt to inputs" ability VIs detect the type of connected wires from the variant that holds a wire type. When I set "object in" and "object out" terminals to adapt to the type that is connected to the "object in" and then connect a user defined LVClass object to an XNode instance, everything starts to get weird. The XNode instance looks ok from the VI where it's embedded, although it's not executable. But the code doesn't get correctly generated. That is the variants carrying the LVClass objects inside the XNode instance must somehow have different meaning than they would have on the normal development application context. Propably the XNode instance application context cannot access the LVClass pointers in the application instance where you are developing you class. Therefore starnge things happen when you try to do this. LabVIEW quite often crashes, so be careful.

I tried to typecast the objects to cluster and well anything just to get the queue reference out of the objects. I didn't succeed but this still could be a one way to go. If one succeeds to somehow get the reference to the queue in the application context where the XNode instance is running, then perhaps one can access the queue without explicitly accessing the object. Sounds a bit tricky. Other ideas are welcome as well.

Also, is there any way to inspect the code behind the facade of an XNode instance? It certainly would make debugging a whole lot easier.

I've set the following XNode related INI keys:

XNodeWizardMode=True

XTraceXNode=True

These set, one can right click on an XNode instance and select XNode Wizard Menu subitem. There menu contains a list of all of the ability VIs. When opened from there, you get the runtime instance and can debug it normally. The "Generated Code" gives you the code that the XNode has generated, or may crash LabVIEW if you using LVClasses inside your XNode. When the code is generated, my "Generat Code.vi" ability also copies the generated code to the clipboard where you can paste it to somewhere else.

I hope this helps you forward.

And for those NI employees who don't think XNodes exist, try searching LabVIEW help for keyword "XNode"...

Tomi

Edit: If we don't manage to get this working. There is an option to use XNode as script generators and let the XNode to script directly to the VI containing the XNode. I think it's very much what XNodes exactly does. At least having weird broken hidden wires on the block diagram when an XNode generated code is not working indicates this. So I assume that the generated code is indeed generated directly to the block diagram of the VI where the XNode is located. Then it's hidden simply hidden like hidden controls on the front panel. I wonder if we can detect these hidden wires and nodes using scripting.

Link to post
Share on other sites

XNodes do not exist. But if I pretend that they do, I might also pretend that there was a great sigh of despair the day I realized that they used a separate app instance.

Good thing they don't exist so that I can go on being cheerful.

Link to post
Share on other sites

I think I may have a partial solution at least. However I'm too tired to test it right now, it's already past midnight here. The idea is to delegate the tasks that don't work in the application context where XNode runs back to the application context where the VI is open. I tested simply to call such a delegate VI from an ability VI and it seems that at least some tasks can be delegated back to the original application isntance. The image below show how, not very complicated. Simply wire the XRef terminal of ability VIs that need to delegate some tasks to the property node at the left end of the image.

post-4014-1170453159.png?width=400

This is my contribution for today, I hope somebody has made a leap forward the next time I visit LAVA :)

p.s. The XRef reference didn't seem to work in Initialize ability so don't try to do delegate calls from there.

Edit: Only 3 downloads for the challenge souce code. I thought this would be a challenge that everybody wanted to get their hands on immediately :D

Tomi

Link to post
Share on other sites
XNodes do not exist. But if I pretend that they do, I might also pretend that there was a great sigh of despair the day I realized that they used a separate app instance.

Let's pretend they do exist. Would you AQ think the in such an imaginative situation, NI would change the context where the XNodes would be running in a future release of LabVIEW to be the same where the VI using the XNode is open? Of course XNodes do not exist, but just try to imagine such a situation.

Link to post
Share on other sites
Let's pretend they do exist. Would you AQ think the in such an imaginative situation, NI would change the context where the XNodes would be running in a future release of LabVIEW to be the same where the VI using the XNode is open? Of course XNodes do not exist, but just try to imagine such a situation.

It's hard to imagine this implementation aspect of XNodes changing. The XNode developers assure me this is a key aspect of XNodes -- I'm not privvy to all the details of why and wherefore. And since LVClasses would be the only feature really putting any pressure to change this, it would surprise me if anything changed. I think it is up to LVClass R&D and LVClass users to find all the workarounds we can. I know that the LVClass should be able to be used in the writing of an XNode so long as that same class is not part of the code that actually gets scripted into the XNode. The problem with wiring an LVClass to an XNode is that the scripting has to be done very gently to avoid loading the LVClass into the XNode context and then copied back into the original context (which occurs when the XNode is done with scripting in what I think of as the scratch pad context).

I don't play with XNodes at all myself yet. It's an interesting tech, but not my primary focus, so most of what I know comes from others -- both internal and external -- who tell me about the problems they've encountered.

Link to post
Share on other sites

I made some further investigations about the application contexts related to XNodes. It seems there are three different application instances related to the issue.

  • The VI which you edit and run are in an application context of their own, normally either Main Application Instance or then project related context.
  • Second the Ability VIs are executed in NI.LV.XNode application context.
  • Third the code is generated to third application instance, which is NI.LV.XnodeCodeGen
  • When the XNode generated code is executed, it's executed in the same context as the VI where XNode instance is located.

No wonder this is a though issue to deal with...

Tomi

Link to post
Share on other sites

AQ, thanks very much for your answer!!! :worship: :thumbup: Is there any public source where I can find information about passing LVClass objects between application contexts, either when the application context exist on the same computer or when they are physically distict. What is needed for an object passed form one context to another to become a valid object in the other context. Especially interesting is the case where the runtime type of an object is not know in the sending end, how the proper runtime class is loaded to memory of the receiving context when at compile time one cannot define the runtime type of the object being received, only that it's of some more generic type X.

EDIT: I Added the fourth point to the list in my above post (When the XNode generated code is executed, it's executed in the same context as the VI where XNode instance is located.)

Link to post
Share on other sites

I go on my lonely discussion. A small step forward and some steps backward - I've managed to place a class constant to the generated code without crashing LabVIEW. It seems that if a class constant is explicitly scripted to the generated code, then the class get's loaded to the memory of other application context as well (NI.LV.XnodeCodeGen?) and LabVIEW manages the situation better. The generated code cannot access private data members, as LV thinks it's not part of the class. I wonder if you can script it to be part of the class, at lest for the time the code is generated. Furthermore the opening the class in a second application context makes the class locked as LabVIEW locks classes that are open in multiple application contexts. This is not very good thing as one is trying to modify a class method by placing an XNode into it.

Link to post
Share on other sites

I haven't managed to script any XNode generated code that contains user defined LVClasses and that doesn't make LabVIEW either unstable or to crash. So I tried another way to achieve my goal. I used the XNode to script directly to the block diagram of the VI that owns the XNode. The idea was to use the XNode stay on the top of the scipted code so that the scipted code would be invisible or something similar. The problem in this case is that when ever I script something to the block diagram directly, the addition of the new node triggers ability VIs to rerun and the generate code is executed again and again and again. So I end up in a loop of automatic code generation. However perhaps there is a way to detect in which cases the call to the ability VIs is a rerun triggered by the XNode modifying the owner diagram and when it's a real change on the diagram. I'm beginning to be a little frustrated as all the paths I've tried seem to be dead-ends. Perhaps it's time to watch TV for the rest of the evening.

Download File:post-4014-1170670103.vi

Link to post
Share on other sites

I attatch a handy tool for debugging. It lists all VIs belonging to any LVClass that are currently in memory of any application instance. The VIs are categorized by the context they are open in. Using the tool you can see when a class is loaded to a memory of specific application instance and when it's removed from the memory.

Download File:post-4014-1170670103.vi

I think the following actions may take us to the goal.

  1. Before scripting the code or terminals referring to LVClasses force the NI.LV.XnodeCodeGen to open these classes into it's memory or script a class constant to the diagram.
  2. Avoid using variants carrying class constants and originating from another application context to script the terminals (this is the default way of doing it) as variants carry a reference to the class but this reference is located in wrong context.
  3. When you are done with scripting the code and the code get's copied to the VI containing the XNode, tro to figure out a way to close all the class references in the NI.LV.XnodeCodeGen context so that the classes don't get locked. Classes get locked when they are open in more than one context simultaneously.
  4. The XNode generated code cannot access class private data as the generated code doesn't belong to the class, I think a way around this is to create a common parent class that returns a queue reference that can then be used to get the private data being hold in the queue

I was also thinking of a concept of dual objects. These objects could be both by-value and by-reference objects. When the object is in by-reference state, one could sync the content from the queue to the private data members so that the class would then hold both the queue reference and the by-value data. The synchronizing the object would lock the by-reference object. From then on the object would behave as by-value object until it would be synchronized back to the queue and the lock would be released. This would allow faster access to the private data inside class methods that call other class methods as the object could be passed to subVIs in by-value mode instead of by-reference mode. All the class methods would need to be able to detect if the object is in by-value mode or by-reference mode but that could be done using common subVIs or XNodes. The problem with this dual object concept I haven't figured out (besides how to implement the XNodes) is how to get the dynamic dispatch wires to pass trough the synchronizing XNodes without breaking.

Now the weekend is over and I've to concentrate on real work that needs to get done.

Tomi

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.

×
×
  • Create New...

Important Information

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