Jump to content

Aristos Queue

Members
  • Posts

    3,183
  • Joined

  • Last visited

  • Days Won

    204

Posts posted by Aristos Queue

  1. QUOTE (jgcode @ Mar 5 2009, 04:44 PM)

    Therefore, even though it is possible to do this in JAVA - are you saying that you would never do this in the real world?
    I am saying that I would never do this in the real world and I would strongly advise anyone else against ever doing it. It opens the door to your child object (and all of its descendants) being in an inconsistent state that their designers may never have handled. It can be used to hack around a poorly designed parent class. The one case I am most familiar with, making a direct call to grandparent functionality (bypassing the parent) did let a software team ship a product on time, but that hack bit them badly in the next release when they didn't go back to refactor the code because a new descendant class was added that assumed (rightfully) that the functionality of the parent (which was being bypassed) would be invoked.

    Essentially, the situation was this

    • Grandparent
    • Parent
    • Child

    Each level of the hierarchy had an implementation of RegisterMe(). Parent's version registered the object with a framework. Child had its own overriding implementation of RegisterMe() did some checking of itself and if certain flags were set, the function would return an error; if those flags were not set, the function would call up to the Parent implementation to do the registration.

    There was one place in the code where the correct behavior was to do the registration of a Child object even though the flags were set on Child that would normally make the function return an error. Refactoring the code at that point was hard -- they would have had to change some interfaces that had been stabilized. So the programmers called directly up to Parent's version, bypassing the flag check. By just bypassing Parent, the team made Child work correctly. Fine -- they shipped.

    Next version, a new Grandchild class was introduced. Grandchild overrode RegisterMe() such that it called up to Child's implementation. If Child returned an error, so did Grandchild. But if Child did not return an error, Grandchild did some more work, including registering itself with a second framework. Grandchild assumed that anytime it was registered with the first framework, it would also be registered with the second framework. It assumed that the code protected it from ever getting into an inconsistent state.

    The problem was that a Grandchild object got passed to that special section of code that called directly to Parent:RegisterMe(). That registered Grandchild with the first framework but not the second. Grandchild's desgin predicate was violated. No one noticed this bug until after release of the new version... the first to notice was a customer. Serious bug... required a custom patch for the customer. Expensive.

    Object-oriented design is supposed to prevent design errors like that. The whole point is that there are predicates that each class defines: I am in state X. I define a set of functions that let me transition from state X to state X+1. I have no functions that ever let me reach state X+2 without going through state X+1. I have no functions that put me in state Y EVER. Therefore I don't have to check for state Y, and I can assume that things done in state X+1 are taken care of when I am in X+2." With these predicates, the software developer can actually make logical arguments about the correctness of his/her code.

    This shield is one that I took great pains to maintain in the design of LabVIEW classes. We eliminated many of the aspects of other OO languages that keep you from asserting certain truths.

    • You cannot have two VIs of the same name that do not override each other by having different connector panes.
    • You cannot directly call an ancestor implementation of a method
    • You cannot as a user directly edit the private data of a class through any UI mechanism [Yes, I know this causes a problem for debugging and we're still working on that problem, but don't expect anything soon. But while it is a problem when debugging, for a running app this is a feature.]
    • You cannot have public or protected data [This one we could relax and it would be your choice when to have public data about which you could make zero assertions of correctness, but the reasons for all private data are explained in the LabVOOP white paper.]

    I feel this makes LabVIEW a more robust language, something that is important in all the industrial control and hardware feedback situations that LabVIEW is used for.

  2. QUOTE (Mark Yedinak @ Mar 5 2009, 09:47 AM)
    I do think its inclusion would produce cleaner looking code in the long run. And in the end, isn't that what we are trying to accomplish?
    I agree with the goal of cleaner looking code. I just don't buy that something that looks like a wire but isn't and something that doesn't look like a terminal but is contributes to the cleanliness of the diagram, especially when the functionality, as you noted, is available today through existing mechanisms. Going further, your primary case is doing timing on a block of code, having to drop down a flat sequence structure. I think that is extremely clean code. It clearly identifies what code is included in the timing AND it is instantly recognizable visually that you are doing timing ("I see Get Milliseconds in one frame, then a frame of code, then Get Milliseconds in the final frame. Oh, that's a benchmark pattern.") I don't see how having a NULL wire that could wander all over the place -- including branching off to stuff that is not included in the timing -- would be any cleaner.

  3. No, you cannot do what you are seeking to do. It is impossible, by design, and if you find a way to do it, please let me know so we can fix it.

    Now, having said that...

    What you claim you are trying to do is this:

    • The parent defines functionality X.
    • The child overrides functionality X.
    • You want to have a child object call Parent:X.

    But you would never really want to do this. Doing so completely violates the definition of child -- child overrode the behavior of X for some reason, which may be because the parent behavior is invalid or doesn't do sufficent input checking, or doesn't keep related fields up-to-date... etc.

    What you actually want to do is this:

    • The parent defines functionality X.
    • The parent defines functionality Y, which happens to be identical to X. (So it is probably implemented as Y calls X in the parent, but that's private implementation detail, so we don't know... the parent could have duplicated the VI, or call into a common subVI...)
    • The child overrides functionality Y.
    • You have a child object call functionality X.

    In this case, the parent has exposed both the wrapper layer and the core layer -- and exposed it as two separate methods even though itself doesn't need to have any difference between these. That's how you'll handle the JAVA code.

  4. QUOTE (jdunham @ Mar 4 2009, 02:50 AM)
    I would also highly recommend upgrading your LabVIEW, since the LVOOP code has a few major bug fixes between 8.2 and 8.6.1 AFAIK.
    At the very least, you should get 8.2.1. There are seven major bugs fixed in 8.2.1. They range from annoying UI delays to files saving corrupt.

  5. > However in general sequence frames are not very desirable for many reasons.

    One of the reasons they are desirable is when there is a need for an order dependency and there isn't a dataflow dependency. As a matter of fact, this is exactly the *right* time to be using a sequence structure.

    > So in order to time a task we generally have to place a flat sequence frame down

    > with the Get Time in the first and third frames and our task in the second one.

    And we like this because it makes for very legible timing diagrams. But, if you want to use less diagram space, put a sequence structure around the first timeing node, another around the second timing node, and thread the inputs to your code through the first structure and the outputs through the second structure. It's just a bit harder to identify exactly what nodes are being timed.

    • Like 1
  6. I recently placed an idea in front of the LV R&D team to think about: Shouldn't error terminals be moved -- on all nodes -- to be the top terminal of all nodes? That is the one consistent location that you could then string an error wire across between functions, regardless of type. Then if you have a second type that is railroading along side the error code, have it running in the second-from-the-top terminal. This means that you have one side of your node that you can get values to the other terminals without crossing your two railroad track wires, and your nodes can stay top aligned to minimize bends in the error wire.

    Yeah, it'd be a big change to the diagram to do it today. But if we didn't have 20 years of diagrams, wouldn't that be a better strategy?

  7. QUOTE (joey braem @ Feb 23 2009, 04:24 PM)
    because the solution is more elegant in a EXE ;) You're solutions is a nice work around, but in the dutch we call this a little bit "Een houtje touwtje oplossing "( a log and a string solution) ;) I hope in the future the analyser Vi's can be used in a executable program.
    Not going to happen. The VI Analyzer is intended to look at block diagrams. The block diagrams do not exist in the runtime engine. And a lot of the "reflection" API for the connector pane, etc, on which the VI Analyzer relies, is also non-existant. The RT engine is for running VIs, not editing VIs. The VI Analyzer is part of the editor environment.

  8. Quick addition to crelf's clarification:

    QUOTE (crelf @ Feb 23 2009, 12:48 PM)

    GOOP = Endevo by-ref OOP implementation

    The latest edition of the "GOOP Toolkit" from Endevo is built out of LVOOP classes, and the toolkit includes tools for manipulating both GOOP classes and LVOOP classes.

    We now return you to your irregularly-scheduled return to your regularly-scheduled programme.

  9. QUOTE (Jim Kring @ Feb 22 2009, 06:54 PM)
    The only problem that I see with the work-around you mentioned (editing type def with callers closed) is that I use classes a lot. And, having any member of a class (e.g., a type definition that is a member of a class) will cause all class members to be loaded into memory (e.g., VIs with Event Structures whose dynamic events use the type definitions).
    As a workaround to that, rename the class file, load the typedef, edit it, then rename the class back to its original name and open it. This shouldn't be necessary, but since you're working around the other bug, this workaround becomes useful.

  10. Clarification: It means that the default value of the control is not the same as the default value of the class. It may be an instance of a child class, as Justin suggested, but it can just as easily be a non-default value of the class itself -- so if your private data cluster contains a numeric whose default value is 5, this control may have the numeric with a default value of 6.

  11. QUOTE (mic_k86 @ Feb 19 2009, 09:36 PM)

    Aristos, thanks for your help, but hv one problem. when user selected 0 hour 0 minute 0 second the error box will pop out, but after that when waiting the user to select another new time interval, the sensor still keep saving data. is it possible to set the vi to not save any data during that waiting interval? how to do it?
    Yes, it is possible... in fact, I had to go out of my way to make it keep acquiring data because that's what I thought you wanted. :D Guess I misunderstood. I don't have LV available at the moment, so I'll tell you the easiest way in text: Take the VI I gave you and put the data acquisition code inside a Case Structure. Connect the time to the ? terminal. Put your acquisition code in the "Default" case and don't do anything in the "0" case.

    There's actually a much better way (the way I just told you will have the loop spin as an empty loop polling for a value change) but I can't explain it in text.

  12. Edit >> Find

    Set the radio button at the top of the dialog to "Objects"

    Click on the Add primitive and select from the palettes the Stacked Sequence Structure.

    Set the search scope to the VIs you want to search -- they have to be loaded into memory already.

    Click "Find" and you'll get a list of all the sequence structures. If there are any password-protected diagrams, you will be prompted for the password before the results from those VIs will be displayed.

  13. QUOTE (MJE @ Feb 18 2009, 09:40 PM)

    Ah. I see. Yes... I agree... something like this would be useful for you. Hm... well...

    Attached VIs are saved in LV8.6...

    Replace

    <labview>\resource\Framework\Providers\LVClassLibrary\NewOverride\CLSUIP_CreateOverride.vi

    with the new version here Download File:post-5877-1235021532.vi (BACKUP YOUR EXISTING VI FIRST!) and save the new "User Scripting For New Override.vi" Download File:post-5877-1235021543.vi in the same directory.

    You now have a hook to write your own scripting code into the process. The new subVI gets invoked after all the other scripting is already complete, so you can delete what's there and start over or somehow adjust that diagram to suite your needs. I can't help more than that at this point.

  14. QUOTE (MJE @ Feb 18 2009, 01:15 PM)

    Defining the parent dynamic VI sa a VIT doesn't seem to do the trick. Is there a way to do this?
    No, there's no way to do this. When LV is asked to create a new Override VI, we *ALREADY* start with the parent VI as the template VI. This gets all of the connector pane, VI properties, and front panel. Then the diagram is wiped except for the FP Terms, a call parent node is dropped, the terms are wired up, and the controls of parent type on the FP are substituted for child type controls, including updating the labels if the parent label text includes the name of the parent. To do what you're asking would require amending that entire process.

    HAVING SAID THAT...

    If you have "a common starting point", that suggests you are overriding at too high a level. In other words, you currently have Parent:DoSomething.vi and you are overriding with Child:DoSomething.vi. What I'm suggesting is you consider taking the "variable" portion of Parent:DoSomething.vi and make that another subVI -- call it Parent:DoSomethingCore.vi -- and then override that core VI. Part of why we wipe the entire block diagram is that ideally the child doesn't have any code that is duplicated by the parent.

    Would that work for you?

  15. The Call Parent Node is for VIs that are members of a LabVIEW class that have dynamic dispatching enabled. Dropping the Call Parent Node on the block diagram of a dynamic dispatch VI creates a call to the parent class implementation of that method.

    The Context Help and the online help for the Call Parent Node go into lots of detail.

  16. QUOTE (menghuihantang @ Feb 15 2009, 11:10 AM)

    32-bit length followed by Unicode sequence, similar to Labview string.

    This is not an authoritative answer -- someone else may know a better way.

    One thing you could do that would work is to create a LV string where the first 4 bytes are the length of the rest of the string and then pass it to the DLL call as a C-style string pointer.

  17. QUOTE (shoneill @ Feb 12 2009, 02:22 AM)
    PS On mature recollection I reckon inheritance could be very difficult if a child class is dynamically loaded where more than one possible parent is in memory.....
    Yep... that's where I was going next... dynamically load the parent, give it a run-time only ID, now dynamically load the child... and the grandchild... it gets messy quick. Now, there are TONS of applications where you don't need multiple levels of inheritance to be dynamically loaded, so your suggestion has significant merit. But it is still one mitigation, not a general solution.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.