Popular Post Norm Kirchner Posted September 11, 2010 Popular Post Report Share Posted September 11, 2010 When working with dynamic code, sometimes we end up with a generic reference that we need to cast to complete our operation. Example: You make a sub-VI that extracts the plot color of a waveform chart or a graph. The reference input to that VI must be of a common reference type (GraphChart) The problem is that this property, although it exists for both types of references does not exist in the common type. Proof:http://content.screencast.com/users/NJKirchner/folders/Jing/media/d223f6b4-83a2-43dd-a830-be17877c9715/2010-09-10_1849.mp4 So if you want to have a piece of code that can operate on both types of references, what do you do? Somehow you need to have a switch in your code that will conditionally run the correct code based upon the specific reference you wire in. The way some people do this is by utilizing the 'Class Name' property into a case structure but this has problems w/ flexibility Proof:http://content.screencast.com/users/NJKirchner/folders/Jing/media/9f771182-303a-40d2-96db-3701ee43ff7f/2010-09-10_1903.mp4 This is a simple case where there is only 1 or 2 sub-types. What about a numeric w/ all of it's myriad of sub types (slider, guage, etc). The appropriate way to handle this is by doing a type cast, but people typically solve the 'Many Cast' design pattern VERY POORLY through nested error structures. Which looks really ugly Proof:http://content.screencast.com/users/NJKirchner/folders/Jing/media/7c0e0bfe-966a-458a-8bc8-c44bf6a91cc5/2010-09-10_1913.mp4 So what is our alternative? Introducing the very useful, and practically perfect in every way 'Many Cast' design pattern. It's stackable It's scalable And it even tosses errors properly Proof:http://content.screencast.com/users/NJKirchner/folders/Jing/media/55e8e391-bb10-4cc2-9a15-2e2a46912bb6/2010-09-10_1933.mp4 The Code is attached, not as a package 'yet' Demo to Follow in the subsequent postDesign Pattern - ManyCast.vi 4 Quote Link to comment
ShaunR Posted September 11, 2010 Report Share Posted September 11, 2010 Hmmm. I don't really see he difference between your using the class name "problem" example and using an iterative apart from the class name has a descriptive case name and the iterative "trial and error" just has 0,1,2 etc. You still have to have a case to handle the particular type to do the correct cast but with the iterative approach you have to try all the previous ones first before deciding its not supported. With the class name its either supported or not. Is there another benefit I'm missing? Quote Link to comment
Daklu Posted September 11, 2010 Report Share Posted September 11, 2010 Is there another benefit I'm missing? It's stackable It's scalable Functionally I don't think it's any different, but there's a HUGE difference in readability. I suspect Norm has been spending a lot of time looking at customer's code lately. (Personally I really dislike nested case structures. The logic is too hard to understand at a glance. If I can I'll usually execute all the logic tests, put the results in a boolean array, convert it to a number, and wire that into the case structure. Then I drop a comment explaining the logic. It's much easier for me to check the code that way.) Oh, and without going back and watching the videos again, what was the first word Norm said on all four of the videos? Quote Link to comment
Norm Kirchner Posted September 11, 2010 Author Report Share Posted September 11, 2010 Hmmm. I don't really see he difference between your using the class name "problem" example and using an iterative apart from the class name has a descriptive case name and the iterative "trial and error" just has 0,1,2 etc. You still have to have a case to handle the particular type to do the correct cast but with the iterative approach you have to try all the previous ones first before deciding its not supported. With the class name its either supported or not. Is there another benefit I'm missing? You did not see what happened with the XY graph did you? You would have to account for EVERY possible child string. EVERY CLASS NAME. If you had some VI that had a GObject come into it's terminal, you would need to manually enter the 'Class Name' for EVERY Class Name of EVERY child class that you wanted to handle. If GObject was the input and you wanted to do a bunch of operations on all, or even a subset, of numerics types, you would have to figure out every class name possible, and then type it in perfectly in the case selector, and then hope and pray that NI doesn't release another item in the GObject tree that now your code won't work with. It's all about Scalability, robustness & re-usability. You do not get that w/ the string Quote Link to comment
ShaunR Posted September 11, 2010 Report Share Posted September 11, 2010 (edited) Functionally I don't think it's any different, but there's a HUGE difference in readability. Really? Its easier to read 0,1,2,3... than WaveFormGraph, WaveformChart, XYGraph... ? (Personally I really dislike nested case structures. The logic is too hard to understand at a glance. If I can I'll usually execute all the logic tests, put the results in a boolean array, convert it to a number, and wire that into the case structure. Then I drop a comment explaining the logic. It's much easier for me to check the code that way.) I find nested case structures abhorrent. I must admit I didn't even consider the nested error example a solution Even a case structure with many cases causes me to look for an for an alternative. Its the same argument as Sequence Structures. If the case number is small (<6), I'd much rather use a select so its all out in the open. For more then I will try for strings unless its numerical in nature in which case I will do the same as you. Oh, and without going back and watching the videos again, what was the first word Norm said on all four of the videos? ummmm. "So"? You did not see what happened with the XY graph did you? Thought I did You would have to account for EVERY possible child string. EVERY CLASS NAME. If you had some VI that had a GObject come into it's terminal, you would need to manually enter the 'Class Name' for EVERY Class Name of EVERY child class that you wanted to handle. You mean the difference is that instead typing in the class name you wanted to handle you, would just "Copy Case" and change the cast constant instead? If GObject was the input and you wanted to do a bunch of operations on all, or even a subset, of numerics types, you would have to figure out every class name possible, and then type it in perfectly in the case selector, and then hope and pray that NI doesn't release another item in the GObject tree that now your code won't work with. Not really. Because unlike graphs the a property node accepts all the numeric classes for the common properties. It's all about Scalability, robustness & re-usability. You do not get that w/ the string Certainly waveformchart,waveformgraph and xygraph don't have child classes. Neither do boolean, cluster etc Numeric types are consistent (whether they be a U16, DBL, slider, knob,gauge or whatever) since all the common properties can be wired to the same property node. The graphs, however (I think) are the exception and it is only because the property node doesn't allow it (which it should) means that you have to handle them differently. I found that out when writing PassaMak. Edited September 11, 2010 by ShaunR Quote Link to comment
ShaunR Posted September 11, 2010 Report Share Posted September 11, 2010 (edited) Having slept on it (after all wise words from NI are never to be taken lightly). I thought I'd better to refresh my memory. Unfortunately I seem to have remembered correctly (what? No crying emoticon?) as this works as I would expect However, Plot color isn't available, yet it is still common to all plots. Which brings me back to the summation that you have really highlighted a problem of inconsistency of the property node for waveform types since this also works. So. You don't have to create a case for every class and subclass. Only the parent (if at all). Apart from some properties of waveforms (there maybe others but waveforms are the only one I've come across). Edited September 11, 2010 by ShaunR Quote Link to comment
Norm Kirchner Posted September 11, 2010 Author Report Share Posted September 11, 2010 Functionally I don't think it's any different, but there's a HUGE difference in readability. I suspect Norm has been spending a lot of time looking at customer's code lately. (Personally I really dislike nested case structures. The logic is too hard to understand at a glance. If I can I'll usually execute all the logic tests, put the results in a boolean array, convert it to a number, and wire that into the case structure. Then I drop a comment explaining the logic. It's much easier for me to check the code that way.) Oh, and without going back and watching the videos again, what was the first word Norm said on all four of the videos? SO.....Dak, the problem is that it is functionally different. Check out the second video again. If someone made a piece of code that only had String Name case structures for ClassName WaveformChart & WaveformGraph, their code would fail to execute anything if those were the only two cases handled EVEN THOUGH the WaveformGraph case could have handled the XYGraph just fine. Really? Its easier to read 0,1,2,3... than WaveFormGraph, WaveformChart, XYGraph... ? Shaun, I agree that having the Class Available in the case selector would be better and maintain the robustness and flexibility of the pattern, but that requires a new type of stacked frame structure in LV to exist outside of a feature request You mean the difference is that instead typing in the class name you wanted to handle you, would just "Copy Case" and change the cast constant instead? No, I'm saying w/ the design pattern, you don't have to make a special unique case for the XYGraph at all because the cast to WaveformGraph will not fail. Not really. Because unlike graphs the a property node accepts all the numeric classes for the common properties. But as you've seen, not all common properties in class trees are common Certainly waveformchart,waveformgraph and xygraph don't have child classes. Excuse me?? What?? Um, U B mistaken sir. XYGraph is a child of WaveformGraph Neither do boolean, cluster etc Numeric types are consistent (whether they be a U16, DBL, slider, knob,gauge or whatever) since all the common properties can be wired to the same property node. Thats assuming that you're trying to access properties and methods that exist in all cases for the common ancestor (after all wise words from NI are never to be taken lightly). You give me far too much credit sir. Working in the tower has it's perks, but not the midas touch of LV wisdom. Although easy access to the 3rd floor is damn nice. Unfortunately I seem to have remembered correctly (what? No crying emoticon?) as this works as I would expect However, Plot color isn't available, yet it is still common to all plots. Which brings me back to the summation that you have really highlighted a problem of inconsistency of the property node for waveform types since this also works. So. You don't have to create a case for every class and subclass. Only the parent (if at all). Apart from some properties of waveforms (there maybe others but waveforms are the only one I've come across). SO.... this gets to the heart of your argument and the weakness in my example. I stand by my example as a good simple case of showing why the string based operation fails and if someone was trying to make some generic code for waveform graphs they would easily miss the XYGraph case and need to go back and re-code BUT!!! Where this code really shines is while doing LVScripting, where you end up with an array of GObject often and need to operate on a variety of types which a common ancestor with the needed functions can not be assumed or found. EXAMPLE: <object id="scPlayer" class="embeddedObject" width="944" height="566" type="application/x-shockwave-flash" data="http://content.screencast.com/users/NJKirchner/folders/Jing/media/4175933d-db01-4105-b527-c9935b5bc59f/jingh264player.swf"> <param name="movie" value="http://content.screencast.com/users/NJKirchner/folders/Jing/media/4175933d-db01-4105-b527-c9935b5bc59f/jingh264player.swf"> <param name="quality" value="high"> <param name="bgcolor" value="#FFFFFF"> <param name="flashVars" value="thumb=http://content.screencast.com/users/NJKirchner/folders/Jing/media/4175933d-db01-4105-b527-c9935b5bc59f/FirstFrame.jpg&containerwidth=944&containerheight=566&content=http://content.screencast.com/users/NJKirchner/folders/Jing/media/4175933d-db01-4105-b527-c9935b5bc59f/2010-09-11_1240.mp4&blurover=false"> <param name="allowFullScreen" value="true"> <param name="scale" value="showall"> <param name="allowScriptAccess" value="always"> <param name="base" value="http://content.screencast.com/users/NJKirchner/folders/Jing/media/4175933d-db01-4105-b527-c9935b5bc59f/"> <video width="944" height="566" controls="controls"> <source src="http://content.screencast.com/users/NJKirchner/folders/Jing/media/4175933d-db01-4105-b527-c9935b5bc59f/2010-09-11_1240.mp4" type="video/mp4;"> Your browser cannot play this video. Learn how to fix this. </video> </object> By all means, keep using the 'Class Name' based selection of your code, but I believe you will find that, although it potentially meets your needs immediately, you have introduced a point of weakness into your code that unnecessarily would need modification to handle cases not originally though of. But why would you? 2 Quote Link to comment
jgcode Posted September 11, 2010 Report Share Posted September 11, 2010 Norm - this is really cool. I think this part of the last video really hits home and defines the benefits of this design pattern, highlighting why using strings would cause an epic fail. I agree with Shaun in that strings are generally easier to read than integers in a Case Select, but in this case it doesn't really matter - the benefits are huge (you get some readability from the casted type anyways). I can see the benefit of this straight away esp for scripting, and will be adding this to my templates folder. Thanks for posting! 1 Quote Link to comment
ShaunR Posted September 12, 2010 Report Share Posted September 12, 2010 Shaun, I agree that having the Class Available in the case selector would be better and maintain the robustness and flexibility of the pattern, but that requires a new type of stacked frame structure in LV to exist outside of a feature request It was a trivial point but I think it improves readability immensely. And (probably in the minority again....but) I will choose readability over elegance if performance is not impacted.. No, I'm saying w/ the design pattern, you don't have to make a special unique case for the XYGraph at all because the cast to WaveformGraph will not fail. But I want it to fail. Because it means I have given due consideration to an unexpected behaviour and therefore is a part of the designed behaviour. In the absence of similar behaviour in other classes, I almost view this as a NI implementation oversight (and therefore all methods more of a bug fix) rather than a design pattern to be used generically for accessing objects. In most cases (where things are as they should be) it's a performance hit since the probability is that you will be trying invalid cases before stumbling onto the correct one is high. If all t saves is 1 case. Then I see no reason to switch from an accepted, proven method to a shiny new method that may have performance hits and is (slightly) less readable. You'll have to give me more than that (What are the benchmarks comparisons like out of interest? If you don't have time, post an everyday example and I''ll do them) But as you've seen, not all common properties in class trees are common All are as I'd expect EXCEPT graphs. Excuse me?? What?? Um, U B mistaken sir. XYGraph is a child of WaveformGraph Excused! Indeed I was. (It was late/early is my excuse and I'm sticking to it ) But my point (perhaps explained better after the sleep) was that I didn't need to create a case for EVERY class and subclass. And my memory from over 11 months ago, was that I didn't have t deal with subclasses. It turns out that was because of the consistency of implementation of the property node (In fact to handle any control in PassaMak only required 4 cases. So that's only 1 more than you have above.....for all of 'em).. You give me far too much credit sir. Working in the tower has it's perks, but not the midas touch of LV wisdom. Although easy access to the 3rd floor is damn nice. Well. Get banging on the floor, tool up your Pikachu with an Uzi and tell them to sort the Graph class out SO.... this gets to the heart of your argument and the weakness in my example. I stand by my example as a good simple case of showing why the string based operation fails and if someone was trying to make some generic code for waveform graphs they would easily miss the XYGraph case and need to go back and re-code Well I didn't miss it. And I didn't miss digital graphs either But. The string based system doesn't "fail". If you hadn't thought about the waveform graph or waveform chart, yours would "fail" too. I'm looking at the graph example and all I can see is that you are replacing a nested case structure with an iteratively nested case structure. Perhaps I need a different perspective?. BUT!!! Where this code really shines is while doing LVScripting, where you end up with an array of GObject often and need to operate on a variety of types which a common ancestor with the needed functions can not be assumed or found. EXAMPLE: Hmmm. Now I see no difference between the "string" based system and this one apart from the "string" one will always do it first time, every-time (if it can) but this method has to try a few different ones before either it hits one that works or it runs out of options. Same number of cases because there is no common denominator and each operation has different properties and methods. It seems to me that the graph example is indeed a one-off scenario where you save 1 case. By all means, keep using the 'Class Name' based selection of your code, but I believe you will find that, although it potentially meets your needs immediately, you have introduced a point of weakness into your code that unnecessarily would need modification to handle cases not originally though of. But why would you? How can you handle cases not originally thought of? If that were possible, you wouldn't have to add the extra cases because it can handle stuff you don't think about Moreover. If you haven't thought about them,how do you know it will handle them correctly? (Wavey lines, Soft fade.....) Many moons ago, in a galaxy far, far away. We used to use a similar approach for instrument identification. The SCPI spec was fluid and manufacturers all had their own way of identifying their device (to some extent that's still true today).. So we would have a list of all the ident commands for all the instruments we supported and try each one in turn until either we ran out or found one that worked Sales called it "Auto-detection". We called it the BFI method (Brute Force and Ignorance) . It was slow and cumbersome and with hindsight, didn't obtain the holy grail of "future proofing" that many believed. It also had a really annoying habit that if a customer happened to stick on an unsupported device that had the same ident command. it'd make them think it was compatible but fall over because the rest of the command set wasn't the same. Eventually, we decided to make it a maintenance issue and that if they swapped out a device for a different one they'd just select it from a drop down list, It was faster, cleaner, easier to maintain and also meant that "if it 'aint on the list, it 'aint getting in". Does this have anything to do with The "Any Cast Design Pattern"? Probably not. But but I'm having flashbacks Quote Link to comment
Daklu Posted September 12, 2010 Report Share Posted September 12, 2010 SO.....Dak, the problem is that it is functionally different. Yep, you are correct. I've been pwnd. Quote Link to comment
Norm Kirchner Posted September 12, 2010 Author Report Share Posted September 12, 2010 Hmmm. Now I see no difference between the "string" based system and this one apart from the "string" one will always do it first time, every-time (if it can) but this method has to try a few different ones before either it hits one that works or it runs out of options. Same number of cases because there is no common denominator and each operation has different properties and methods. It seems to me that the graph example is indeed a one-off scenario where you save 1 case. Ok then, replicate the code that I have that can handle changing both a control to an indicator and a constant to an indicator. How many cases would you need for that w/ the string based implementation? Quote Link to comment
ShaunR Posted September 12, 2010 Report Share Posted September 12, 2010 Ok then, replicate the code that I have that can handle changing both a control to an indicator and a constant to an indicator. How many cases would you need for that w/ the string based implementation? Well. For controls ........none. Since I wouldn't use any of them. I'd use something like this: I can't remember off-hand how to get th BD reference (cannot seem to find it in the list). I'll have to dig into my old code for a refresher example (is it only available if scripting is installed and activated?). Quote Link to comment
Norm Kirchner Posted September 13, 2010 Author Report Share Posted September 13, 2010 I can't remember off-hand how to get th BD reference (cannot seem to find it in the list). I'll have to dig into my old code for a refresher example (is it only available if scripting is installed and activated?). Yes, grab it from ni labs And to clarify the challenge, make a sub-VI that takes an array of GObject references input and converts both constants and control terminals into indicators Quote Link to comment
ShaunR Posted September 13, 2010 Report Share Posted September 13, 2010 Yes, grab it from ni labs And to clarify the challenge, make a sub-VI that takes an array of GObject references input and converts both constants and control terminals into indicators Why don't you just send me your code and I'll mod it. Quote Link to comment
ShaunR Posted September 13, 2010 Report Share Posted September 13, 2010 (edited) http://www.screencast.com/users/Phallanx/folders/Jing/media/6d33f01c-4961-4c88-9944-e3290ab349a0 Remember.I'm not the one promoting a "Design Pattern". I'm only prepared to spend as much effort in discussion as you are! Edited September 13, 2010 by ShaunR Quote Link to comment
ShaunR Posted September 29, 2010 Report Share Posted September 29, 2010 And to clarify the challenge, make a sub-VI that takes an array of GObject references input and converts both constants and control terminals into indicators Not even a rep-point or effort? Quote Link to comment
Yair Posted January 7, 2012 Report Share Posted January 7, 2012 http://www.screencast.com/users/Phallanx/folders/Jing/media/6d33f01c-4961-4c88-9944-e3290ab349a0 Remember.I'm not the one promoting a "Design Pattern". I'm only prepared to spend as much effort in discussion as you are! Not that I really want to get involved, but since you dug it up - in this video you don't just take the class name. You rely on every class inheriting from constant to have "constant" in its name, which could fail (for instance, knob and digital inherit from numeric). This could also be a problem with other classes which are called constant but don't inherit from constant, but that's presumably not an issue, because at most the cast will fail. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.