LabVIEW Idea Exchange

cancel
Showing results for 
Search instead for 
Did you mean: 
0 Kudos
BrianGShea@NGC

Allow Class Events for Register for Event Nodes

Status: Declined

Any idea that has not received any kudos within a year after posting will be automatically declined.

Allow LabVIEW Classes to be wired directly to the Register for Events Node and create a drop down list of events the class and ancestor classes expose.

 

Events will be defined like properties, a special folder type (Event Definition Folder) with a nifty overlay. A single VI will be defined that will output an event reference. The Register for Events Node can traverse the class hierarchy, and build the drop-down menu based on the Event Definition Folder names. Separators can be used to break the Events down by class type (like properties on controls and indicators).

 

A new right-click action on the class will allow the event to be created from a default pattern VI. The VI should just have an empty cluster or simple control type wired to a Create User Event node.

 

Maybe if a user event reference control is in the class' private data, a right-click action to create the event from the control and named it as it is named in the class' private data.

Brian G. Shea
Former Certified LabVIEW Architect
17 Comments
AristosQueue (NI)
NI Employee (retired)

This is not a meaningful request. It has been made many times before, but it isn't just something that NI hasn't gotten around to... it is, in the mathematical sense, not a well-defined request.

 

Associating an event with an by-value object is meaningless. Suppose you create a MyClass.lvclass and put into its private data two things: a) a numeric and b) an event refnum for "Numeric Changed". You add a method "MyClass:Set Numeric.vi", which will assign the numeric and fire the event.

 

You have now mixed by-ref and by-value syntax. Let's see what happens.

 

Drop a constant of the class and fork it 3 ways. Fork A goes to the Event Registration node. Fork B goes to a "MyClass:SetNumeric.vi" wired with a "6". Fork C goes to a "MyClass:SetNumeric.vi" wired with a "7".

 

(Assume you do the work to force the Event Registration to fire before either call to Set Numeric -- easiest way is to use a sequence structure.)

 

You register for the event. Then the first event fires (maybe "6", maybe "7"). Your event structure handles it. Then the second event fires (whichever one didn't fire last time). Either way, you now have two objects, one that contains a 6 and one that contains a 7 and an event structure that thinks only one of those is the real value.

 

This is a classic mistake of conception. LabVIEW cannot/should not promote a single-reference-existence idea of the object that just isn't true. If you want to associate events with a reference thing in LabVIEW, you associate them with a by-reference thing.

 

Could LabVIEW design something brand new that accommodates your request? Yes. But we are already building out systems that are significantly more aligned with dataflow than "associating events with objects references." These alternate approaches are much safer and more well-defined in a massively parallel environment, i.e., LabVIEW and modern multi-core hardware. For static relationships, look to channels as your mechanism for communication (and as of LV 2017, the Event Messenger channel allows for connection to the event structures). For more dynamic relationships, the Actor Framework promotes a design based around asynchronous messaging.

 

Events-tied-to-objects patterns are useful in other programming environments. And they could be hacked into LabVIEW. I'm trying in this post to convince you to not try to do so.

Intaris
Proven Zealot

I have re-read this response many times but I can't help but think there's a large disconnect between what the OP actually requested and what AQ has objected to.

 

I use User Events for a lot of communication and I use Objects.  Never have I come even close to attempt what AQ is describing in his post (which I can understand is an inherently broken use case).

 

If I have an Object designed as an API, then this idea could help me.  The Event needs not be tied in any way whatsoever to classic "LV" Events (Value change and so forth) but can represent an API to already running processes.  Instead of having to use an accessor to choose which UserEvents to register for, using a drop-down menu of the "Register for Events" node would be a very nice change.

 

I see no other explicit request of the OP.

AristosQueue (NI)
NI Employee (retired)

This idea conflates the syntax simplification with the semantic meaning of the nodes. It is asking us to suppose some event inherent to the class exists that can be chosen by the Register For Events node, but no such events ever exist. There is nothing inherent to the node. I'm hoping a picture will make this make sense. It has to do with whether or not the event is inherent to the object or not. Anything you put in a field is not inherent.

 

You said, "If I have an Object designed as an API"... the 2nd and 3rd images are classes that are designed as such APIs -- to the user of the object, they behave like refnums. The 1st and 4th images are by-value objects that happen to expose a even refnum data accessor VI.

Untitled.png

 

AristosQueue (NI)
NI Employee (retired)

To put it another way... direct wiring to the Register For Events node could be allowed if

a) The class contained only a data value reference in its private data, ensuring that all information therein really is a coherent thing.

b) Creation/destruction of the DVR was restricted to the class (using the checkbox options in the class properties dialog).

c) The DVR contains the event refnum directly, i.e., as a event refnum, array of event refnums, or cluster of event refnums, and not in any further level of indirection.

d) The event refnum is placed into the DVR at the time the DVR is created and the code could be proven that nothing ever allowed the value of the event refnum to be modified across the entire lifetime of the DVR.

e) The code could be proven to destroy the event refnum at the same time as the DVR refnum is destroyed.

 

D would be really hard to prove by compiler code analysis today--not impossible, but I would rather not undertake that project. E is straightforward. But I think that far better would be to create some sort of class declaration where the events are inherent to the thing being created... research is in progress.

 

I can imagine people arguing with me that these restrictions aren't necessary... after all, I said in the image earlier that we could just define the direct wire to Reg Events to mean "call the data accessor". But I hope you can see how that syntactic shortcut actually conflicts with the meaning that the Reg Events has in all other contexts. Worse, without the A-through-E restrictions, the code now has an ambiguous meaning for anyone reading it -- it might be that the class author has made those events behave inherently, but the class author might just as easily have *not* done that.

 

It is perhaps a subtle point, but it is one that I believe matters a great deal.

Intaris
Proven Zealot

I assumed we were referring to User Events, not Control Events so I still don't understand why we're talking about Control Events at all.  I don't see why the events in question have to be linked to any specific "control" or "Field" or "DVR" at all.  Just behave like normal User Events.  So the presence of the phrase "control" and "Data accessor" to me seems really out of place in the discussion.  It is making connections which I feel are not borne out by the OPs request.  I think you're attaching a lot of implications which were not implied in the original request and which, to me, are not terribly relevant.

 

It's perfectly legit to wire up an invalid User Event reference to "Register for Events" (in this sense, it's just a strictly-typed placeholder) and then later, from within the Event Structure, activate the placeholder with a valid reference.  Of course if the user messes up, then tough luck.

 

If I have an object which links to a different process, but which perhaps is able to activate certain events only at a later stage (all of which I can ancapsulate in the object) then this would provide a useful way to get those User Event refnums out of the object and into the "Register for Events" node.  I believe the OP is asking for no more than that.  Any accessors which may be implied are for the Event Refnums themselves (since they are private members), not for any associated data fields.  So if we could define accessory with the prefix "_UserEvent", these might be recognised by the "Register for Events" Node and offered as an option for the drop-down list.  As Iunderstood it, it's simply a syntactic shortcut for the first image you posted "marked as Meaningful" where ""string event" (discoverable by the aforementioned prefix perhaps) would appear in the drop-down list for the "register for Events" Niode if the object would be wired up directly to the node.

Intaris
Proven Zealot

Just to be clear.  I'm not arguing for or against the idea per se (Although I lean towards the "for" side, just because I use a load of User Events), I just want to make sure that if it's declined, it's declined for the right reasons.

BrianGShea@NGC
Member

One fundamental problem with LabVIEW Objects: each branching of the wire results in a different set of By-Value values with the same set of By-Reference data. (I often forget this because I do not mix and match By-V and By-R) LabIVEW is a data flow language, therefore, this was the expected behavior of such an implementation. The implementation follows every other wire construct that was not a reference type. AQ is correct in his initial assessment, to have By-Reference and By-Value in the same class is a recipe for disaster. Ultimately, a user, not a programmer, of LabVIEW will attempt to use this feature in this way and will be stuck with the inevitable race condition of having branched their class wire containing By-Value and By-Reference data and now be left with many events coming from many different flavors of the original class wire with no way to know which is the correct flavor.

 

There are other means to a solution that fits within the confines of the LabVIEW data flow paradigm and it will be best to follow those methods.

 

 

Brian G. Shea
Former Certified LabVIEW Architect
AristosQueue (NI)
NI Employee (retired)

Hm. I'll try one last time to communicate my point. It is really hard for me to demonstrate a contradiction that I can only see in potential.

 

First, yes, we are talking about user events. We are talking about user events inside an object. I brought up control refnums to provide contrast so you could maybe see the difference in how a control refnum defines its events and how a class defines its events. Maybe an XControl is a better comparison because it is user-written code?

 

Second, the implementation (direct access to fields, using accessor VIs, special naming) is irrelevant to my point. Regardless of the mechanism for exposing, the direct wiring is a problem. Direct wiring has a semantic implication not backed up by the implementation.

 

> I don't see why the events in question have to be linked to any specific "control"

> or "Field" or "DVR" at all.  Just behave like normal User Events. 

 

They don't have to be linked from a technical perspective. As I said in my post, there is absolutely no technical reason why we couldn't allow the direct wiring and assign it the meaning requested in this idea. Literally, I can tell you exactly the C++ code changes needed to allow this to work.

 

I am saying that the meaning of direct wiring is different than the meaning of indirect wiring, and we should not blend those two just for convenience because -- and this is my professional opinion, but it is, I grant, an opinion -- that misleading implication will result in wrong applications for no real gain.

 

There are two different paradigms for events in software -- not LabVIEW, but software generally. LabVIEW classes only support one of them, but if we allow direct wiring of the object to Register For Events, then we appear to support the other one, and I believe that is a problem for readability of diagrams.

 

One paradigm is an object that contains a reference to an event and that event is dynamically setup and possibly reprogrammed during the lifetime of the object. The other paradigm is a class that has events, inherent, that are tied to the existence of the object itself, and are meaningfully tied to the object. BOTH paradigms exist in various programming languages. LabVIEW doesn't have the second one, and I believe it would be wrong to use the syntax of the latter when we don't have it -- it uses syntax for a minor advantage to the code writer while marginally increasing confusion of the code reader because the code implies certain operations are safe when they might not be.

 

Put another way: a direct wire reference cannot ever fail and means "operate on that specific object." But a contained refnum doesn't do that because it isn't tied to the lifetime of the object.

 

Does any of that make sense?

AristosQueue (NI)
NI Employee (retired)

Thank you, Brian. I'm struggling to connect all the pieces -- I think you did a better job of getting to the heart of the problem.

BrianGShea@NGC
Member

AQ, I appreciated your deep dive into the compiler!

 

Ultimately, if I were to do this, I would implement it in the class, where the class wire would collect a set of 1) VI refs to call or Event Refs to fire off. Much like AnObject.AnEvent += MyEventHandler. My classes are inherently by Reference and so I would just access the DVR to update the array of delegates by adding or removing the handler. Now my applications can register themselves to the class by obtaining the reference to the class from my object store.

 

<private>Class.GenerateEvent -> Invoke Handler, On error, remove reference from array, close reference and drop error, move on to next element.

 

There is no need to add the complexity to LabVIEW when it is already achievable.

 

Example use case, several UI's all monitoring the connection state to a piece of hardware want to know when the connection state is good to enable/disable UI components. Each UI App will obtain InstrX class from store, call add event ref to handler method and register event locally. When InstrX state changes GenerateEvent will be invoked, each UI will determine new UI state from the class state which contains a DVR on event received.

 

I hope this concludes this discussion.

Brian G. Shea
Former Certified LabVIEW Architect