07-03-2013 09:05 AM
In the meanwhile I found a "solution" - or at least something that works, but I don't really like it.
I had to move the device manager into base class (as suggested), but additionally override the manager implementation for each inherited class, so that each manager hold a collection of the same type.
That leads to the next problem: Finding out which manager holds which DeviceId. This is done by an additional Device Registry.vi (functional global, located in base class but actually independent), which does the DeviceId => Type mapping.
In summary a big effort just to manage some objects by ID (think of actions "delete", "clear" etc.)
If somone knows a more elegant way, please let me know...
Regards,
Alex
07-08-2013 07:04 AM
Alex,
sorry, my fault. I miswired the output terminal of the class output of the manager.
Attached, you find an updated version of the example which works fine on my machine. Good news: The dynamic dispatch output is not necessary, so the device manager can be stand alone again!
All in all, Shane is correct that a simple "Preserve Run-Time Class" is sufficient....
Norbert
07-08-2013 08:02 AM
@Norbert_B wrote:
All in all, Shane is correct that a simple "Preserve Run-Time Class" is sufficient....
07-08-2013 11:00 AM
alex_bauer wrote, in the initial post:
Storing and reading to and from manager works, at least until the VI borders are reached. Within the VI, the correct original type (e.g. "Device GPIB") is returned. Outside of the VI, the type is casted to "Device Base" and the wrong dynamic dispatched member VI gets called (Base implementation)
How can I safely dynamically store and read mixed objects of the same base class without loosing the concrete type?!
Your initial "Device Manager" has a bug in it: the "Device Object" output is mistakenly connected directly to the input rather than the the output tunnel of your Error case structure. Thus, the output is always the same object as input, and is never the object stored in the Device Manager. Connect the output properly and it works.
FYI, objects never "degrade" or otherwise change classes. Nor does use of dynamic dyspatch methods require the explicit identification of the child objects (that being the whole point of DD). If they seem to, it's because of a bug or some misunderstanding somewhere.
07-08-2013 01:40 PM
I can't believe it, your're right! Had to look twice to find the bug, thanks a lot!
More than that, it seems that I not even have to provide the correct class at the input now, after changing the device manager back from a base class member to a normal functional global without DD!
I will verify this tomorrow in the real application.
Seems I have to apologize for anything I might have said or thought about LVOOP in the meanwhile 😉 ...
Such a dumb mistake, I would have worked right from the start as intended.
Thanks again and best regards,
Alex
07-09-2013 02:02 AM
Alex,
ok, this is what i attached (except you indeed even don't need the Preserve Run-Time Class).... 😉
Well, i just reviewed your initial approach and the only difference now is that the objects are stored in an array in the device manager rather than as variant attributes.
When working with variant attributes, these are themselfes variants again. So your object are cast to variant and back again.
Obviously, when an object is in a variant, you have to exactly specify the class of the object to get the correct object type back again (variant to data). That seems to be your original issue overall.
This was new to me as well, therefore all the confusion inbetween....
Norbert
07-09-2013 02:16 AM
Hello Norbert,
no, the original issue was just the wrong wiring. Now everything works as expected and I don't even have to wire the input for the "get" case. The device manager is now part of the application (where it should be). The terminals are defined as static base class objects (allows to call only "interface" methods, which are dynamically dispatched) but internally keep their class specific attributes => everything perfect now.
Regarding the device manager: there is no explicit casting required and the objects are handled correctly when storing them as variant attributes. The advantage of this approach is the faster lookup and built in key-value mapping and management. It also behaves differently, because I have to override the object in the "set" case to update an object instead of adding it to the array, even if it already exists.
Again, thanks for all your help and I'm glad it works now.
Regards,
Alex
07-09-2013 03:03 AM - edited 07-09-2013 03:04 AM
Alex,
ah, i see...sorry, i thought the miswiring was my fault 🙂
Correct, the miswiring in the device manager is already in the initial attachement of yours in place, which is, as far as i can see, the main reason for this thread at all.
One side note:
VI Analyzer could have helped in this issue (d'oh, haven't used it on my own!) as it would have critized the wire behind objects (the case structure)!
Short summary:
Provide code only if you tested it before using VI Analyzer. Also a ToDo on my side.....
Norbert
07-09-2013 04:46 AM
For those new to LVOOP, it is helpful to keep straight the differences between the following pairs:
The class of a wire versus the object on the wire.
"Edit time" vesus "run time".
A Class versus an Object (an instance of a class).
These are all closely related. Wires have a class type defined at edit time. Objects exist at run time and can be of a child class of the wire they travel on. The wires that an object travels on can change, but the objects class type never changes.
"Variant to Data" is about wiretype/edit-time (as are several other "change-wire" operations); "Preserve Run Time Class" is about objects/run-time (hence the name).
-- James