02-20-2015 07:13 AM - edited 02-20-2015 07:19 AM
OK another exploratory post from me. To anyone who has put up with this kind of thing from yours truly many times in the past, apologies. Completely impervious to any objections, here goes:
I have discovered a new toy : Registering event callback VIs. OK, I have used them before but a previous post by James McNally about his MVC framework revealed to me a usage which I had not previously thought of. Thanks for that James.
I like LVOOP. One pattern which is quite easy to understand is the command pattern in conjunction with state machines where we essentially replace the individual states of a state machine with external VIs. This makes it far easier to customise behaviour and allows for re-use of the core state machine for differing functionalities. Cool.
We can leverage this with LVOOP by passing different "commands" to the state machine depending on the real object being utilised and thus we have a nice extensible architecture. Again, cool. If we need to change one common action, we simply update that VI and instantaneously all ancestors share the new code in that command object. Double cool.
Problem is that I love User Events. The idea of having an extensible object model gets awkward to handle when you start using Events to handle communications in and out of the object. Create a Parent, Implement the 15 Events required. Create a child, Implement the 15 Parent events and the 12 new events. Create a Grandchild, Implement the 15 Grandparent, the 12 Parent and then the 25 new Events. Armageddon occurs when you want to change the common functionality for the sixth Event of the Parent. Now you need to go to each and every ancestor which uses them and update them. Wait a second, isn't LVOOP supposed to save me from this kind of crud? Frustration ensures. Can you ever be sure you got all instances? What about those obejcts not listed in the project, maybe you forgot one of them...... Nasty testing and debugging ensues.
I think I may have (partially) found the answer. What we need to do is basically do the same thing we have done with the command pattern and extract the individual frames of the event structure and place them into external VIs so that we can 1) re-use the VIs in each level of hierarchy and 2) maintain all the other niceties of Events.
Turns out that using Callback VIs for each level of the object hierarchy can help to solve this problem. You need to have a method with a different name for each level of the hierarchy which exposes the events int his way because each method will most likely have different input values.
Has anyone else done things like this? Are there limitations as to what can and can't be done with this arrangement? Any nasty bugbears waiting for me around the corner? How to deal with events which should give some kind of return value? Do I encorporate the return value into an implementation-agnostic return channel (again Events of course) with the object in question providing one return user event for each callback function which requires a return value?
02-20-2015 08:52 AM
I'm not really following what you're actually doing. Can you upload an example with a couple of children with a couple of events each so that we have a baseline?
02-20-2015 09:08 AM
Yes, I'll try to do that. Even though my words might be cryptic, hopefully code will help more than it hinders.
02-20-2015 09:42 AM
Grr, I was trying to attach a file (whose contents apparently didn't match the file name?!!) when I ran out of time to edit and now I lost my text.
Here's an example.
Base class swaps out a control Caption for Label upon "Mouse Enter"
Child class swaps out a control Label for Caption on "Mouse Leave"
Grandchild increments a counter (stored in Description) for every "Mouse Enter"
Trivial but get's at what I mean.
I know I can do this in other ways but
1) I don't need a parallel process
2) I'm just having fun
Darn, I can't attach a zip. Rename this file to .zip and unpack. Sorry guys.
02-21-2015 11:52 AM
No, can't say that I did anything similar and at the moment I can't come up with a proper use case either. It certainly looks interesting, but I would need that to really be able to assess it.
Some semi-random thoughts:
02-21-2015 12:51 PM
Thanks for taking the time to investigate my ramblings.
1) I often have the same feeling regarding running somewhere in la-la land with the command pattern. While its eadier tl know where something is executing, knowing what is executing is more difficult.
2) Im not interestedin whether inheritance is the best for this example but much more whether the combination of LVOOP and callbacks offer new ways of achieving better extendable yet sstrictly-typed APIs.
3) Again, the example is a bit contrived and was all done in about 15 minutes total. The ability to do something different than a parent is retained by having the option to override individual functions. If i design the classes so that each callback registration is in a dynamic dispatch vi, then each individual function can be overridden by any ancestor.