Variant vs Native Datatypes
#1
Posted 08 September 2011 - 02:39 PM
Certified LabVIEW Developer
#2
Posted 08 September 2011 - 03:24 PM
My initial thought is doing something like your example pushes UI code down into your application and is probably best avoided. Multiple controls can be registered for the same case (and I do it sometimes myself) but somewhere in your code you need to figure out exactly which control triggered the event and respond appropriately. I believe the best place to do that is in the event handling loop.In practice I wouldn't register all controls on a front panel like that; instead controls (or groups of controls) which need special code would have their own case. But multiple controls can be registered for the same case, either statically or dynamically as an array of references.
I wasn't aware different units were considered separate types. To be honest I've always thought the units were more trouble than they were worth. I'll have to think about that for a while before deciding whether or not to add a variant message.
I like your other examples too, though I need to study them some more before I comment on them.
Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.
Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.
There are two secrets to success:
Secret #1 - Never tell everything you know.
#3
Posted 08 September 2011 - 04:14 PM
Just a quick response... I'm short on time.
I wasn't aware different units were considered separate types. To be honest I've always thought the units were more trouble than they were worth. I'll have to think about that for a while before deciding whether or not to add a variant message.
I have not used units much but I see why they are different types. You get a broken wire if you try to multiply volts and temperature but you can multiply volts and amps. Pretty cool stuff for preventing bugs.
[Edit: Hah. I told you I have not used units much. I just tried and indeed you can multiply volts and temperature. You end up with a new unit entirely s^-3 m^2 kg A^-1 K. It turns out that 5 degrees Celsius times 6 volts is 1668.9 of whatever those things are. Yea more trouble than they are worth
Certified LabVIEW Developer
#4
Posted 08 September 2011 - 10:34 PM

POPULAR
Tell that to the people who flew the Mars Climate Orbiter INTO the planet, rather than into orbit, because one of their software packages was outputing in pound-seconds what the rest of the program thought was Newton-seconds.To be honest I've always thought the units were more trouble than they were worth.
It's a Volt-Kelvin.I have not used units much but I see why they are different types. You get a broken wire if you try to multiply volts and temperature but you can multiply volts and amps. Pretty cool stuff for preventing bugs.
[Edit: Hah. I told you I have not used units much. I just tried and indeed you can multiply volts and temperature. You end up with a new unit entirely s^-3 m^2 kg A^-1 K. It turns out that 5 degrees Celsius times 6 volts is 1668.9 of whatever those things are. Yea more trouble than they are worth)
Volt = Joules/Coulomb; Joule = kg m^2 s^-2; Coulomb = Amp-second --> Volt = kg m^2 s^-3 A^-1
The base unit is often unintelligible to humans, but as soon as you create an indicator and set it to "Watts", or do any math operation that requires consistent units (add, subtract, greater than, etc.) you'll get a broken wire and realize you multiplied the wrong things. And you'll get an error from your power module if you send it a VarMessage to set power at 1668.9 Volt-Kelvin. Basically, the computer is too dumb to tell you your unit is weird, but it's far better than you at identifying when the physical dimension is not the same between two quantities.
Units can be some trouble, and internal to a module you might want to not use them, but for public communication between modules (possibly written at different times or by different programmers) they extend the bug-preventing value of type-checking to physical dimensions and eliminate the need to remember what units other modules expect things in.
-- James
BTW: the link to the prior conversation is actually here.
Edited by drjdpowell, 08 September 2011 - 11:00 PM.
#5
Posted 08 September 2011 - 10:50 PM
I'm not sure I understand. The event loop figures out which control triggered the event and sends a different message for each control ("Set>>{control name} in my example).Multiple controls can be registered for the same case (and I do it sometimes myself) but somewhere in your code you need to figure out exactly which control triggered the event and respond appropriately. I believe the best place to do that is in the event handling loop.
Now, this example is only for controls that map well onto the required messages that the UI needs to send (User changed the pressure to 50PSI? --> Send "Set>>Pressure; 50PSI" message). If the relationship is more complex, then one needs custom logic in the UI for each control.
-- James
#6
Posted 09 September 2011 - 12:07 AM
BTW: the link to the prior conversation is actually here.
Copy and paste error. I fixed the link at the top.
Certified LabVIEW Developer
#7
Posted 15 September 2011 - 07:27 AM
Yep, you're right. For the life of me I can't remember what I was thinking when I wrote that... However, that still means you have code down in your message receiving loop that requires knowledge of the UI. Specifically, it has to know the control's label. Labels are one of those things that--in my experience--developers tend to change without thinking too much. Writing algorithms that unnecessarily depends on label text causes brittle code.I'm not sure I understand. The event loop figures out which control triggered the event and sends a different message for each control ("Set>>{control name} in my example).
If I want to add a control, I just drop it on the front panel and give it the right name and it's done. <snip> I like things to be as "easy as hooking up a...wire".
This is one area we differ. I'm more concerned with creating code that is sustainable rather than code that is easy to write. Often times these goals exert opposing forces on your design decisions. In fact, there is a noticable decrease in my code's sustainability when I try to make code that is "easy" to write. Readability, testability, extendability, etc., all take priority over writability.
This is only true when the data from the two modules are linked together directly. If you drop a value in a variant message to send it to a different loop the compiler can't verify the run-time type propogation is correct. In the hypothetical world where Labview ran the Mars Orbiter, using typed units may not have prevented the problem.Units can be some trouble, and internal to a module you might want to not use them, but for public communication between modules (possibly written at different times or by different programmers) they extend the bug-preventing value of type-checking to physical dimensions and eliminate the need to remember what units other modules expect things in.
There's more I wanted to comment on, but I'm falling asleep at the keybroddlxz.z.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...
Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.
Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.
There are two secrets to success:
Secret #1 - Never tell everything you know.
#8
Posted 15 September 2011 - 01:31 PM
Well, your already using generic message "names" that are text and can thus be misspelled; you'll need some mechanism to handle such issues, such as producing "unknown message" errors in the receiving code. The same error will be triggered the first time the code runs with a changed control label. New developers will quickly learn to use something called a "caption" instead of messing with the label.Labels are one of those things that--in my experience--developers tend to change without thinking too much. Writing algorithms that unnecessarily depends on label text causes brittle code.
This is one area we differ. I'm more concerned with creating code that is sustainable rather than code that is easy to write. Often times these goals exert opposing forces on your design decisions. In fact, there is a noticable decrease in my code's sustainability when I try to make code that is "easy" to write. Readability, testability, extendability, etc., all take priority over writability.
That brings up a question only you can answer: is LapDog intended to support and encourage a particular style of design, or is it to be of more widespread use to developers with differing styles? Personally, I would think having the control label match the name of the process variable controlled, with generic code connecting them, is an advantage for readability and testing, no? Note that using generic code for some controls doesn't preclude individual treatment of others (the "all controls" example I gave is just an example).
Well, compile-time checking isn't possible at all in a messaging system, is it? If you send a U32 message to a loop expecting I32, or "BeginProces" to a loop expecting "BeginProcess", you'll learn about this error at runtime. Similarly for your "SetTemp" to 20psi message.This is only true when the data from the two modules are linked together directly. If you drop a value in a variant message to send it to a different loop the compiler can't verify the run-time type propogation is correct. In the hypothetical world where Labview ran the Mars Orbiter, using typed units may not have prevented the problem.
BTW, it was the ground software, used to calculate how long to run the thrusters, that had the wrong-unit bug. The Mars Orbiter computer executed it's suicidal instructions flawlessly!
-- James
#9
Posted 15 September 2011 - 03:33 PM

POPULAR
Labels are one of those things that--in my experience--developers tend to change without thinking too much. Writing algorithms that unnecessarily depends on label text causes brittle code.
FWIW, when I have to do this I like to use the following convention:
If the Label is red (BD and FP), its dependent so don't go changing it.
I think I copied it off someone after seeing it on LAVA (thanks to Olivier I think
#10
Posted 16 September 2011 - 04:05 PM
I'm not saying using the control label as part of the message name is wrong. If that's a practice your development group standardizes on and everybody is comfortable with it then there's no problem. I'm just saying I don't like to use it for the reasons I stated.Well, your already using generic message "names" that are text and can thus be misspelled; you'll need some mechanism to handle such issues, such as producing "unknown message" errors in the receiving code. The same error will be triggered the first time the code runs with a changed control label. New developers will quickly learn to use something called a "caption" instead of messing with the label.
That brings up a question only you can answer: is LapDog intended to support and encourage a particular style of design, or is it to be of more widespread use to developers with differing styles?
All the LapDog components (currently Messaging is the only released package, but Collections and Data Structures are around too) are intended to be usable by LVOOP developers regardless of their particular style. I don't provide everything needed to implement a given style, such as a Variant message, or a Command message, but they are very easy for developers to add on their own.
Personally, I would think having the control label match the name of the process variable controlled, with generic code connecting them, is an advantage for readability and testing, no?
Readability, probably yes. Testing, maybe. Flexibility, no. A lot of it depends on the project specifics, who the users are, and how much the user interface abstracts the implementation. If your software controls a system of valves and sensors and the operators are engineers who want direct control over everything, then yes, using control labels for message names might make sense. For higher level applications my fp events trigger "MyButtonClicked" messages. What that message actually does is handled elsewhere.
Propogating fp control names down into functional code follows fairly naturally if you're using a top-down approach. In my experience the top-down approach leads to less flexible and tighter coupled code. Abstraction layers tend to leak. Using the bottom-up approach I name messages according to what makes sense in the context of that particular component, not based on what a higher level component is using it for.
In theory it is, though I don't know how practical it would be. What breaks compile-time type checking is casting to a generic type--variants or a parent class, which is required to send multiple types over a single wire. If one were to create a messaging system where every data type sent had a unique queue for it then type checking would be maintained. The difficulty is in figuring out how to write the message receiving code without making a complete mess.Well, compile-time checking isn't possible at all in a messaging system, is it?
Eliminating (or significantly reducing) run-time typecasting errors was my original goal of LapDog.Messaging. Creating a unique type (class) for each message and encoding the message name as part of the type eliminates a lot of the risk, though not all of it. Even though I've adopted a more generic approach with the current LDM release, users can still implement a "one message, one class" approach if they want.
That's a good idea. (As long as the control isn't on the UI.)If the Label is red (BD and FP), its dependent so don't go changing it.
Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.
Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.
There are two secrets to success:
Secret #1 - Never tell everything you know.
#11
Posted 16 September 2011 - 11:53 PM
That's a good idea. (As long as the control isn't on the UI.)
Ha, I was going to explicitly write that...
But I don't think I have used that method on UI - and if I did, I would most likely send the data as e.g. a Class, and then update the UI accordingly using the 'API' of the UI
I like to do this (with Class) if I have a group of data to send.
#12
Posted 17 September 2011 - 12:17 PM
You can still use it, but show the caption instead of the label. I use a similar method for changing languages.That's a good idea. (As long as the control isn't on the UI.)
Captions are not used nearly as frequently as they should be (IMHO)
Edited by ShaunR, 17 September 2011 - 12:18 PM.
Founder and general mischief maker on www.labview-tools.com.
SQlite aficionado and websocket zealot.
If it 'aint in LabVIEW, then you 'aint got a clue!
#13
Posted 18 September 2011 - 12:13 AM
I agree with you regarding caption use, but I sure wish it were easier to switch back and forth between them. Maybe a hotkey combination that switches all fp controls between showing the label and showing the caption.
Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.
Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.
There are two secrets to success:
Secret #1 - Never tell everything you know.
#14
Posted 18 September 2011 - 12:51 AM
Uhh... Coloring the label red then showing the caption instead kind of defeats the purpose of coloring it red in the first place doesn't it?
No - because the fact is you can change the caption without really thinking about it - but you haven't changed the label name which is the dependency (and hence your code is not broken)!
The BD label will still be red, and this is only for the case of a UI VI.
I love it!
#15
Posted 19 September 2011 - 10:12 AM
My development group of one is very good at standardizing.I'm not saying using the control label as part of the message name is wrong. If that's a practice your development group standardizes on and everybody is comfortable with it then there's no problem. I'm just saying I don't like to use it for the reasons I stated.
All the LapDog components (currently Messaging is the only released package, but Collections and Data Structures are around too) are intended to be usable by LVOOP developers regardless of their particular style. I don't provide everything needed to implement a given style, such as a Variant message, or a Command message, but they are very easy for developers to add on their own.
The advantage of having a "VarMessage" as a standard part of the library is that you could add it to the enqueue polymorphic VI (in analogy to how you currently allow data-less messages), simplifying the wiring for those who use Variant messages. One can easily extend the polymorphic VI oneself, but then one has a customized LapDog library which makes upgrading to a new LapDog version trickier. Command Messages are different, I think, because they are inherently non-re-use (unless I'm mistaken, one would have a different tree of commands messages for each application).
A VarMessage might also be an easier way in to LapDog messaging for those used to text-variant messages.
My experience is limited to much smaller projects than yours, and they are scientific instruments where one does need direct control of many things. And "abstraction layers" seem less attractive if your the only person on both sides of the layer. Also, I was more imagining a bottom-up approach, where the meaningful process variables are propagated up into the UI control labels. And one isn't constrained to do this; one has the flexibility to abstract things as needed.Readability, probably yes. Testing, maybe. Flexibility, no. A lot of it depends on the project specifics, who the users are, and how much the user interface abstracts the implementation. If your software controls a system of valves and sensors and the operators are engineers who want direct control over everything, then yes, using control labels for message names might make sense. For higher level applications my fp events trigger "MyButtonClicked" messages. What that message actually does is handled elsewhere.
Propogating fp control names down into functional code follows fairly naturally if you're using a top-down approach. In my experience the top-down approach leads to less flexible and tighter coupled code. Abstraction layers tend to leak. Using the bottom-up approach I name messages according to what makes sense in the context of that particular component, not based on what a higher level component is using it for.
Currently, for example, I'm implementing control of a simple USB2000 spectrometer. I've written it as an active object that exposes process variables such as "IntegrationTime". In my simple test UI, I just dragged the process variables into the UI diagram, turned them to controls and wired them to send messages in the generic variants way I described in my examples. In the actual UI, which is a previously written program from a few years ago, the IntegrationTime message is sent programmatically based on other UI settings. Making a specific IntegrationTimeMessage class would have made writing the test UI much more work, without gaining me anything in the actual UI.
BTW, you don't send "MyButtonClicked" messages, surely? Isn't that exactly the kind of UI-level concepts ("Button", "Clicked") you don't want propagating down into functional code?
I certainly see the advantages of the "one message, one class" approach. I'm just arguing for variants as a better generic approach over "one simple data-type, one class".Eliminating (or significantly reducing) run-time typecasting errors was my original goal of LapDog.Messaging. Creating a unique type (class) for each message and encoding the message name as part of the type eliminates a lot of the risk, though not all of it. Even though I've adopted a more generic approach with the current LDM release, users can still implement a "one message, one class" approach if they want.
-- James
#16
Posted 19 September 2011 - 12:57 PM
Correct. Here is a bd of the main ui in an app I am currently working on. This app uses a hierarchical messaging architecture I've described elsewhere. Each component has a mediator loop that handles all message routing between the external world (external to the component, not external to the app) and the various internal parts of the component. You can see the event structure for the LoadBtn control. It passes an "Inp:LoadBtnReleased" message to the mediator loop, which in turn passes a "GoToCenterPosition" message on to the application's business logic contained in the CoreSlave.BTW, you don't send "MyButtonClicked" messages, surely? Isn't that exactly the kind of UI-level concepts ("Button", "Clicked") you don't want propagating down into functional code?
There are two negative side effects of sending the Inp:LoadBtnReleased message down into the functional code:
1. If I want to change the way the user triggers moving the system to the center position, I have to change the name of the message through the entire app. It's not particularly difficult, but it is annoying and prone to errors.
2. More importantly, a "LoadBtnReleased" message doesn't have any meaning in the context of the CoreSlave or its subcomponents. They don't know anything about the UI. In fact, I can run the app without a UI at all if necessary. Suppose there were a need to automate a process normally done by users via the UI. I can drop the CoreSlave on a new bd, queue up a sequence of messages to execute the process, and let it run. Having a "LoadBtnReleased" message in that situation makes no sense and reduces readability.
(Note: You'll notice this app doesn't use LapDog.Messaging. That was due to business reasons outside of my control. Instead I recreated the enqueue/dequeue functionality using traditional string/variant messages.)
I'll think about it. It goes against my instincts, but you have made valid points.The advantage of having a "VarMessage" as a standard part of the library is that you could add it to the enqueue polymorphic VI (in analogy to how you currently allow data-less messages), simplifying the wiring for those who use Variant messages.... A VarMessage might also be an easier way in to LapDog messaging for those used to text-variant messages.
Rather than directly editing the LapDog.Messaging library, a better solution is to write your own wrapper class that provides the interface you want (polymorphic vis with variant support) and delgate the functionality to LapDog. That way minor version upgrades will be (mostly) painless.One can easily extend the polymorphic VI oneself, but then one has a customized LapDog library which makes upgrading to a new LapDog version trickier.
In practice they probably usually are, but there's nothing about them that would prevent a well-constructed command message hierarchy from being reusable. To be honest I don't use them much--they tend to cause more coupling than I like.Command Messages are different, I think, because they are inherently non-re-use (unless I'm mistaken, one would have a different tree of commands messages for each application).
-Dave
Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.
Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.
There are two secrets to success:
Secret #1 - Never tell everything you know.
#17
Posted 20 September 2011 - 09:50 AM
-- James
BTW: is that a timed loop that reads a global variable? This is not your preferred architecture I would hazard to guess?
#18
Posted 20 September 2011 - 01:26 PM
I used to do that too, but combining display updates with user inputs can easily cause subtle issues that may not become apparent until it's too late to fix easily. For example, what happens if a dialog box blocks the thread? No display updates are shown until the dialog box is cleared. What if nobody is around to clear it? The event queue will keep growing until eventually LV crashes with an out-of-memory error. Or maybe the dialog box is sitting there for 3 hours before somebody notices and clears it. Then they get to watch as the UI catches up with the last 3 hours of data updates.Personally (illustrating alternate possible styles of programming that might use LapDog) I would probably try and write such a UI in a way that combines your top three loops in a single event-driven UI loop (using a User Event instead of a queue).
In general I have found that combining functionality--like so many things--is slightly faster to implement in the short term but costs way more time in the long run.
Yep, it is. I prefer not to use globals, but sometimes business decisions override architectural decisions.BTW: is that a timed loop that reads a global variable? This is not your preferred architecture I would hazard to guess?
Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.
Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.
There are two secrets to success:
Secret #1 - Never tell everything you know.
#19
Posted 20 September 2011 - 02:22 PM
Modified version of this image from Broken Arrow.
Certified LabVIEW Developer
#20
Posted 20 September 2011 - 04:04 PM
Ah yes, the synchronous call to the unpredictable "User" process, I have been bitten by that before. I've written dialog boxes that beep loudly or that auto-cancel after a short while. I've toyed with the idea of making an asynchronous dialog box that works with command-pattern-style messages (since what is a dialog box but a way of sending a message and getting a response) but haven't put the effort in.For example, what happens if a dialog box blocks the thread? No display updates are shown until the dialog box is cleared.
Your multi-loop design is certainly robust against such issues, but how do you handle information that the UI Input loop might need? What if you have a dialog box that needs to be configured using your "DeltaZ" value, for example? My Users are always asking for dialog boxes that redisplay all the configuration controls for them so that can realize what they forgot to set. I don't see how your UI input loop could implement such a dialog.
Just as an aside, has anyone heard of a design for a message-passing system where messages are flagged by what should be done if they are undeliverable for a significant time? Most of my messages convey current state information, and are rendered obsolete in a few seconds when the next message of that type arrives. Having the queue fill up with obsolete messages and crash the program seems silly. The ideal queueing system would know this and only save the last version for most messages. One could use a size-limited lossy queue, but unfortunately some messages are of the type that must be delivered.The event queue will keep growing until eventually LV crashes with an out-of-mem...
-- James












