Daklu Posted October 8, 2009 Report Share Posted October 8, 2009 This thread is a continuation of the two discussions of using Create methods for reference classes here and here. Is this expressed "hatred" a semantic issue (you don't like the word "Init") or the whole idea of a "Create" method something that has fructarted you? Neither really. The idea of a Create method doesn't bother me, but the requirement of using a Create or Init method on an object constant that looks like it should work fine without one does bother me. To prevent this confusion I never use the object constant on the BD to 'create' objects.. Basically all objects are created by explicitly placing the constructor method on the BD. I should note I use by-ref classes for the major part of my designs and they come naturally with a create method for construction, but for by-value classes I use the same paradigm. The constructor typically has no input terminal for the class wire. For most LV users using a create-destroy paradigm is quite natural since there's a lof of that already in LV (instrument I/O, file I/O, Queues, etc..). Yeah, I've thought about that. The difference is that there's almost* no reason to put a queue constant or file I/O constant on a block diagram and when you do there's a clear indication via the dog-eared corner that you are dealing with a reference. There are valid reasons to put a by-ref object cube on the block diagram (upcasting and downcasting for example) and when you do, it looks exactly like a by-val object. (*The one corner case I can think of is if you need to wire it into a bundle prim as a place holder.) The rule-of-thumb for by-val objects is "branching always makes a copy." (We know that's not always true, but it's a useful way to explain the behavior to new users.) The rule-of-thumb for by-ref objects is "branching always refers to the same object." Now we have to throw in the caveat, "unless you haven't initialized your by-ref object." It's as if by-ref object constants on the block diagram aren't objects at all, but are classes instead. Before LV'09 you couldn't put classes on a VI--only objects. Now you can, and they look suspiciously like objects. It can be particularly perplexing for class users if, like me, you try to simplify the class by initializing the DVR at runtime on an as-needed basis. In those cases, simply reading a property will lead to unexpected results for the new LOOPer. Daklus last image seems prefectly normal to me, however it is an "unexpected" result. I submit that the only reason it seems perfectly normal to you is because I revealed information about the implementation. Specifically, I explained that it is a by-ref object and told you where the DVR initialization was taking place. Had I presented it as a normal by-val object the results would not have made any sense whatsoever. I think that's part of the problem... By-val classes and by-ref classes are fundamentally different beasts, with different behaviors across a wide range of operations, yet to the average user they look identical (subject to the class designer's icon making skills) and at design-time they behave identically. By-ref object cubes on the BD aren't really "objects" in the sense that they are ready to be used. They behave more like a traditional class definition--the user still has to "create" (i.e. initialize) the object before it can be used. Are there any other BD constants in Labview that have to be initialized at run time before you can use them? (Honest question... I can't think of any off the top of my head.) Ummm. VI, TCPIP, UDP. IMAQ, Bluetooth, IRDA? Nope. Static VI references are configured at design time. TCPIP, UDP, Bluetooth, and IRDA constants can't be initializied at run-time. You have to create a new one. (I don't have IMAQ installed so I can't check it.) Same with queues and notifiers. Functionally, those constants (minus the Static VI Ref) on a block diagram are only useful for their type information. There are no prims you can wire through that magically convert it into a valid refnum. Contrast that with a by-ref object constant. It's useful only for it's type information** unless you wire through its Init method, which magically converts it into a fully functioning object. (**Depending on how it's written, certain methods may be functional before creating the internal DVR; however, I think this confusion only compounds the problem.) Certainly using a Create method (class output only) rather than an Init method (class input and output) works in some situations. But it's not always a viable solution. Suppose I have a reusable by-ref class that is intended to act as a parent for other developers to extend for their own purposes. They'll need to have their own Create method to initialize the parent object, but they can't do dynamic dispatching on the parent's Create method because there's no class input. Work arounds, such as making the Create method external to the class and wrapping it all in a library to take advantage of namespacing, are bulky and cumbersome. Furthermore, sometimes developers do their LOOP work primarily out of the project window rather than from the palette. There's no way I'll drag a queue constant from the project window onto the block diagram and then wonder why it's behaving oddly. That can very easily happen with by-ref classes. I know I'm kind of all over the place with this discussion. I'm having a hard time figuring out exactly what I'm objecting to. I've just had a long-running sense that using objects with references introduces a lot of inconsistencies in the user experience (which leads to confusion for new users) and that it could be so much simpler. Quote Link to comment
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.