Jump to content

Aristos Queue

Members
  • Posts

    3,183
  • Joined

  • Last visited

  • Days Won

    204

Posts posted by Aristos Queue

  1. QUOTE (Jim Kring @ Jan 2 2009, 02:31 PM)
    (ideally, we should be able to create installers from items on disk using wildcards and optional recursion, rather than just items in the project)
    Ideally you what?! Weren't folks just complaining about cross-linking? Yes. And yet now you want to add it as a feature for build specs. *sigh*

  2. QUOTE (Yair @ Jan 2 2009, 03:07 AM)

    Can you expand on that? I only really started using 8.x recently and would prefer avoiding it if there are good reasons.
    I've argued it elsewhere in these forums, but the short story is that the feature contradicts the basic principles that we designed into the project and it causes logical contradictions to arise when using libraries (all types of libraries: .lvlib, .lvclass, .xctl and .lvsc). The project was designed to help you separate the physical layout on disk from the virtual layout in your project. That was a feature, and it is a good feature. The autopopulating folders unifies those two again, which once again means there is a lot of churn among caller VIs when a subVI moves to a different folder, and it means that source code control revision history is harder to track whenever VIs go through moves on disk. It moves us in the wrong direction: toward more disk integration instead of less. Libraries in the project show ownership tree -- but if the library is inside an autopopulating folder, you get all sorts of stupid situations when trying to use libraries, and we in LV had to invent all sorts of arbitrary rules for handling cases... for example, a library is in an autopopulate folder, but one of the members of that library is not in the same directory (this is common for sublibraries). The library is listed under the autopopulate folder; and under that library, the owned item is also listed, even though it isn't in that directory.

    I know why a lot of folks like the autopopulate folders. I get the "ease of use" arguments. But in my opinion they're just like global VIs: easy to learn, quick to implement and a complete disaster for long term code maintenance.

  3. You missed a key trick -- that enum is a maintenance hazard, and there's an easy way to avoid changing the mechanical action of "Plus 2". Oh, and I renamed your "Data.lvclass" as "DoNothing.lvclass" since its job really wasn't to load the data but just to give the queue something to do on those events. See attached file.

    You can actually get rid of the Value Changed event case and the shift registers entirely by just moving those FPTerms outside the event structure -- I didn't make that change in this revision. I could've gone a lot further in the refactoring, but I figured this revision highlighted the enum improvement the best.

    Download File:post-5877-1230873647.zip

  4. QUOTE (Ton @ Dec 31 2008, 03:40 PM)
    There are reasons auto-populating wasn't in the first releases of 8.x
    There are reasons why I opposed its introduction into current LV versions and would have no qualms if it went away in future versions. Unfortunately, I am in the minority, both among developers and users. I loathe that "feature."

  5. QUOTE (sam @ Dec 31 2008, 09:43 AM)

    Has anyone else ran into this?
    I use Perforce which keeps the repository on a separate machine, so there's no chance of local VIs crosslinking to the repository files. Having said that...

    QUOTE

    What do you do to avoid false linking?

    Yes, I have encountered this problem, but more rarely in recent versions of LabVIEW. I'm surprised to hear you blame the project explorer -- that has gone a long long way toward preventing these problems, particularly LV version 8.5. That version added

    • cross-link detection before the VIs load into memory (if a caller VI in your project links to a subVI not in your project, the project checks to see if another subVI of the same name is already in the project, which indicates that the caller VI has linked to the wrong item).
    • the File view of the project (shortcut key ctrl+E when on the Project Window) that lets you quickly see if any VIs are linked that are from unexpected directories.
    • protection for VI renaming... when you rename a VI, LV updates all the caller VIs in the project, even those you haven't loaded into memory, so you have fewer cases of loading a caller VI and its subVI being gone, triggering a search for the subVI.
    • and some rather powerful untangling tools. There are several problems with the untangling tools when libraries (.lvlib, .lvclass, .xctl and .lvsc) are involved, but if you're working purely with VIs, these tools are a major aid.

    Cross links of the type you describe almost always come from a caller VI missing a subVI and then LV searching for the missing subVI and finding it. Do you frequently rename VIs on disk instead of renaming them inside LabVIEW? Are you using libraries, moving a VI inside a library (which changes its fully qualified name) and then not saving the caller VIs? Can you move the svn directory to a location where LV won't automatically search it when looking for missing VIs?

  6. QUOTE (Yair @ Dec 30 2008, 01:18 PM)
    I have to say that it took me a while to figure it out, though. I think the help needs to be more explicit about how this specific case (iterating over notifiers) will not be handled as the user might expect.
    Write up the exact documentation change you'd like to see. I'll ask the tech writers to review it and see if we agree.

  7. QUOTE (Jeff @ Dec 22 2008, 10:33 AM)
    For my case, I think my answer would be "I would create a functional global that manages the <class data>" (and not, "I would create a reference to it"). But isn't that what GOOP effectively is? It's a functional global that manages data, with additional mechanisms to manage multiple data sets.
    Yes, it is, and thus, in this case, references seem like an acceptable choice.

  8. QUOTE (Jeff @ Dec 22 2008, 09:57 AM)

    Perhaps I am old-school and too used to a class with a protected data repository that can be shared among parallel pieces of code, but this seems like an obvious solution to me. I'm completely in favor of avoiding references (and I have been trying to figure out a way to do so) if you can show me the error in my ways.
    The easiest thing to do in this case is ask yourself, "If my data was an integer, just an integer, how would I structure this?" If the answer is still, "I would create a reference to it" then a reference is the right thing to do for the class. But the answer may very well be "I would add parameters to my subVIs and pass the integer to them" or "I would create a functional global that manages that integer" or "I would use a global VI to store that integer".

    But, again, the decision applies to that one class only, and you would then make the same evaluation for the next class in line.

  9. QUOTE (Jeff @ Dec 22 2008, 08:00 AM)

    I'm still considering whether to do use a by-value or by-reference model. So I'd like to know if there is a way to replace a parent object with a child object and still keep the same reference.
    Why are you having to choose between by value and by reference? Say it with me:

    • By ref and by value models are NOT MUTUALLY EXCLUSIVE.
    • By ref and by value models are NOT MUTUALLY EXCLUSIVE.
    • By ref and by value models are NOT MUTUALLY EXCLUSIVE.

    You should be using references for classes that represent hardware and system resources and, sometimes, for extremely large data structures if you're not confident of your ability to avoid forking wires to modifier functions and thus creating data copies. You should be using data for classes that represent data, including very large data structures where you are confident of your ability to write LV code that avoids data copies. My personal estimate -- based on two years of observing programs from LV developers, both inside NI and not -- is that

    1. The vast majority of programs have no use for references whatsoever
    2. The total number of classes that should be by reference in the world is roughly 5% of the total of classes written.

    The GOOP Toolkit refnums are -- get this -- written as by-value classes. They are by-value classes that implement reference functionality. Using one domain does not exclude using the other. To put it another way for C++ programmers: Using a class pointer in one part of your code does not prevent you from declaring local variables of the class in another part of your code.

  10. QUOTE (Nate @ Dec 21 2008, 03:00 PM)

    But in cases where the child class author does not have access to the parent class source, its also very inconvenient and limits the customer's ability to extend your classes.
    I'm only going to contest a single word of that sentence. Change "extend" into "hack", and I agree with you. Essentially, if access to the data is limited to the API, then, yes, you are limited to only the things that the author of the original class foresaw you needing to be able to do. But that could be stated another, more positive way: you are limited only to those things that the author actually planned for and (hopefully) tested. Setting the internal values of the parent class to arbitrary values in the child class may move your class in directions that may destabilize the object or give rise to unintended behavior -- even crashes, perhaps (not in LV [if we in R&D have done our jobs correctly], but perhaps in a DLL that you call out to]).

    I realize that all of this argument is fairly philosophical, and yet I think the philosophy is a strong one for a language in LabVIEW's design space. LV classes really tried to balance the ideal against the practical, to weigh guiding users into good designs against forcing them into ridiculous academic constructs. The privacy of data was a major step in simplifying dialogs, simplifying design options, and supporting various other features through subVI connections only instead of having to constantly check for data connections too. We are not a hacker's language. We are a design, test and control language that seeks to be used to communicate directly with hardware, to maintain "always on" systems, and to provide all of this to folks who are not trained as computer scientists but are scientists and engineers in their own domains who need the computer to serve them instead of the other way around. Being a bit more "ideal" seems like a good thing in such situations, as long as we don't go overboard with it. For the moment, I think the balance is preserved, but I keep listening to feedback from users to make sure we keep it balanced as we go forward.

  11. QUOTE (Jeff @ Dec 21 2008, 11:14 AM)

    So creating an entirely new object seems like a reasonable way to solve my problem, but the act of transfering the parent attributes to the child attributes is unsatisfying, potentially memory-intensive, and error-prone. Each time I change a parent attribute, I have to modify the code that creates a new child from a parent. So what I really want to do is copy the parent attributes as a group to the new child object, despite the reasons that it is not strictly correct to so. I accept this can't be done, and I do not dispute the reasons, so my question now is: is creating a new object and copying the parent attributes to the child the best way to accomplish my goal? Or is there a better way? I would expect that others have to deal with the same issue I do--how do they deal with this? Perhaps I am thinking about this all wrong?

    The solution I would suggest (for minimum code changes AND minimum data copies) is as follows:

    1. create a protected-scope member VI named "Set Parent Values.vi" in the parent class that takes two Parent objects in and puts one Parent object out. Call them Source Object in, Destination Object in, and Destination Object out. Make the Destination Object in be a dynamic dispatch input and the Destination Object out be a dynamic dispatch output.
    2. On the block diagram of this VI, drop an Inplace Element Structure. Create two Bundle/Unbundle pairs on the border of this node and unbundle both the Source and Destination objects. Grow the terminals so that all the elements of the class are unbundled.
    3. Inside the structure, drop N "Swap Inputs" primitives. Wire one element of the unbundle to each of these nodes, and then wire the results to the other side of the structure node.

    What have you built? This is the single VI that you need to edit when you change the private data of the parent class. It provides a mechanism for child classes to override the standard behavior.

    There's a lot of other tidbits in here. Check out the attached files... unzip and open Demo.vi.

    http://lavag.org/old_files/post-5877-1229884239.zip'>Download File:post-5877-1229884239.zip

  12. QUOTE (normandinf @ Oct 15 2008, 09:23 AM)

    As easy as it gets... I didn't imagine it would change itself with the actual parent icon in the background.

    thanks

    And it will stay up-to-date conpane wise if you edit your VI or do "save as: rename" to change the VI file name, or if you move the nearest implementation from the immediate parent to some older ancestor or vice versa.
  13. QUOTE (Eugen Graf @ Dec 8 2008, 07:11 PM)

    Sorry, I read the post again, so dynamic VI can't be reentrant. I have to define all VIs as static. No problem, but I would disable this property (selection) if I would be NI.
    Dynamic dispatch VIs cannot be reentrant only in LV8.2. They can be reentrant, with shared clones, in LV8.5 and later.

    QUOTE

    Would anybody explain me why I should share clones? Why
    LV
    doesn't lock this setting in a VI even if this setting creates such errors?

    I've answered the first question elsewhere and perhaps someone can find a link to the explanation. But as to your second question --- why doesn't LV lock this setting? because when I implemented reentrancy for dynamic dispatch, I just didn't think about it. I'll go file a bug report to myself and perhaps someday that will get changed. Thanks for the suggestion.

  14. QUOTE (Nate @ Dec 18 2008, 01:11 PM)

    Is variable scoping (public, private, protected) in LabVOOP only performed at design/compile time, or is it also checked on each access at runtime?
    Hello, Nate. As the lead architect for LabVOOP, I can give you some authoritative answers.

    1. With regards to accessing data in the private data control, Paul is correct. All the data members of a class are always private, so checking that a VI does not attempt to unbundle or bundle any class other than the one it is a member of is easily done at compile time and doesn't need to be done any time else.
    2. With regards to accessing member VIs in a class, scope checking is done in four places:

      1. At compile time
      2. When a VI loads into memory
      3. When a VI tries to open a strict VI reference to another VI in memory (does not apply to a non-strict VI reference)
      4. When a VI tries to call the Run method of a non-strict VI reference

    There is not any checking done at runtime for individual subVI calls -- we assume those are all checked when the VI came into memory or when it was edited after loading into memory.

    QUOTE

    I'm hoping the only thing that prevents it is the fact that the child class should be broken at design time by the LabVIEW compiler,

    LV classes are designed to be binary independent of their ancestors, so a built app can load a revised ancestor class without having to have re-compiled versions of the descendant classes [see note below]. As long as the public API is unchanged, the children should be unbroken. But, like VIs, we check for the interfaces matching when we load the class into memory. Again, there is no overhead once we get running, but we do take a few processor cycles to verify that the dynamically loaded class is everything its parent said it should be.

    [NOTE] When we were surveying folks years ago for what they would expect/need from LabVIEW classes, one of the significant items mentioned was this binary independence. "If my app dynamically loads a parent and its children into memory, I want the ability to ship to my users a new rev of the parent class without having to redistribute all the child classes, and it should work as long as the parent public and protected API is unchanged." To the best of my knowledge, with the exception of a single known issue (see below), this works. And yet thus far, 2.5 years after LabVIEW classes became available, I have yet to hear of any customer actually using this feature. If any of you are using it, I'd like to know how that's going.

    The lone exception mentioned above is if you add a new private VI to the parent class, if any descendant class already had a VI of that name, it will break. Private VIs in the parent class should not affect the child classes in any way, but the bug is that they steal the VI name for all their descendant namespaces. This bug has existed since the original introduction of classes in LV8.2 and my team has repeatedly prioritized other work ahead of fixing it since we have never heard of anyone being actually affected by it -- it was found by users doing exploration of class features in the early days after the release. The bug would possibly get a lot more attention if anyone were actually doing independent rev distribution of classes for built applications.

    1. From a logical point of view, you are correct that no there's no reason that LabVIEW should disallow a notifier of a class being inside the class itself (or a queue or an array whose default value is an empty array, or a datalog or indeed any other refnum type with the class embedded inside it). After all, although the data *type* may be recursive, the data is not.
    2. From a language simplicity point of view, it's just a lot easier to explain "LV does not allow a class to be used as part of its own definition." than to go into the intricacies of why an array would have to have a default value of zero length, or try to puzzle out the error list window when such a circular class breaks. This is ESPECIALLY true when we start talking about circles of greater than one step (i.e., A includes B which includes A).
    3. From a language implementation point of view, there are plenty of performance shortcuts that can be made when loading a class into memory if we assume that all classes that are not broken are ones that do not include themselves in their definitions. Class unloading is complex enough without having to try to find "in any given circle of classes, identify which one is the reference one and allow it to unload first".

    Because the need for circular definitions is particularly rare compared to the total number of classes in the world, and because such need is typically encountered by advanced programmers, and because such programmers can and do stumble upon the idea of using the parent class in their child class definition to achieve much the same effect, points of view #2 and #3 trumped #1 during LV's design process.

  15. QUOTE (sachsm @ Dec 19 2008, 07:50 AM)

    I recall that we used to just place such a vi in a the non-executing state of a True/False case structure, but LV seems bent on optimizing

    out this 'non-running' code. I had to be creative to fool it. Just curious what others have found.

    The canonical solution is the static VI reference, introduced in the same version that the case structure optimizations went in.

    And, for the record, if you change the constant to a control then LV won't optimize it out -- at least, not in any version of LV that has shipped yet. It is entirely possible that LV could decide in a built application, where the Front Panel has been stripped out, if the bool is not on the conpane, then the case structure could be optimized. Not that I'm saying that change is coming... I'm just saying that you probably want to use a static VI reference.

  16. What you want is a new object based on an existing object. You happen to be asking about the special case of having a parent object and wanting to create a child object. You think, "Well, gee, I already have the parent fields, surely the programming language will just let me fill in the values, and then I can set the child values. Why do I have to create some function that copies all the parent values into my new object?!" But that special case of parent-to-child has all the same problems of arbitrary object-to-object. Let's examine...

    Suppose you have class Thing and class Stuff. Both of them have exactly the same fields for private data --- an integer, a string and a path. Now, because they have the same private data, LabVIEW could, in theory, allow you to cast a Thing into a Stuff or vice versa. But that isn't allowed. Why? There are two reasons:

    1. Those fields have meaning for their objects. In the Thing class, perhaps that integer is always an odd number and in the Stuff class the integer is always an even number. Perhaps Thing enforces a rule that either the String or the Path are always empty, but never both, where as the Stuff class never allows either one to be empty. The APIs of each class control the data values that can be set in objects of that class type.
    2. The data is private. Assigning from one object to another directly because the fields happen to be the same would mean that we were taking public advantage of private knowledge, and that if at some point the private details of either class were changed then public functionality would break. That's exactly the sort of thing that is not supposed to happen.

    So, obviously, simply changing one to another cannot be a built-in part of the language. Any time you want to be able to create a new object from an existing object of another type, you, the LV user, have to write the transformation function and assign the fields as desired.

    Now, you're interested in the more specific case of parent-to-child. In this case, we can rule out reason #2 because any time the parent class changes, the child class will change in the same way, so the cast would always be possible from a pure "can this data be copied here" standpoint. But reason #1 still applies:

    • Suppose Parent defines an integer and a dynamic dispatch method "Set Integer.vi". The Parent implementation takes an integer as input, multiplies it times 2 and bundles it into the cluster.
    • Child has its own override of "Set Integer.vi" which takes the input, multiplies it times two, and then does Call Parent to the parent verson.

    In this case, the Parent API has enforced a rule to make sure that the integer is always an even number. The Child class has gone further and made sure that this integer is divisible by four. The fields that a child class inherits from its parent are settable only through the parent's API and thus must conform to the parent's rules. But the child class can put more restrictive rules onto the fields. So even though the data types are the same, and even though the parent API is used to set those fields, those fields still might not be acceptable as values of the child. If LabVIEW allowed any VI to simply cast from parent to child, there would be no way for you, the programmer, to enforce rules about the consistency of data that are specific to a child class.

    You may read this and think, "Fine, don't let *any* VI do this cast. Just give the ability to the child VIs to take a parent object and downcast it." But the parent class may have some weird rules. One of its fields might be a refnum, and when ever you try to set it in a new object, a new refnum is allocated, or something like that.

    And so, no, LabVIEW cannot provide this arbitrary construction under any circumstances.

  17. QUOTE (neB @ Dec 19 2008, 08:57 AM)
    I have experience with XControls and LVOOP but not what I was concider a lot. They have both served well but I have never managed to combine the two in a single app.
    Nor have most people succeeded in that domain. Could it be that some crucial connection between the two is missing? Does it feel, perhaps, unfinished...? If it feels that way, yet again, you are not way off...

  18. QUOTE (shoneill @ Dec 17 2008, 10:35 AM)

    You're not way off. :)

    QUOTE (jdunham @ Dec 17 2008, 12:22 PM)

    Bringing this back to the original question, I would focus on OOP first, since it can change the way you think about programming, usually for the better.

    I agree. The XControls are useful only for UI heavy projects. Classes start becoming useful about the same time "Create SubVI from Selection" is useful, and for many of the same reasons.

  19. QUOTE (Milchbilch @ Dec 16 2008, 03:25 AM)

    But instead of this "manual reference creation" can I create references to objects of type "ClassA" by using something like an

    "Open class reference.vi" and typecast it to any of my classes?

    Just like the way like I can create VI References using "Open Vi Reference.vi"

    The "Open class reference" is a reference to your class. What you are looking for is a reference to your object that is an instance of your class. These are two very different things. No, there is no object reference built into LabVIEW. You have to do something that dynamically creates a data storage location. Your options include

    1. opening a new VI [either by duplicating a template or cloning a reentrant VI] which you could then use to store data either in controls [through the Value property] or in uninitialized shift registers [as per functional global]
    2. creating a queue or notifier of the desired type
    3. using some sort of global VI with an array of objects and adding a new position in the array
    4. etc... I'm sure there are more if you get creative

    The class reference is a reference to the .lvclass file itself. You can use it to query the class definition (who is my parent class, how many methods do I have, etc) and to do editing to the class (change wire appearance, etc). It does not give you a reference to an actual object.

  20. The latest revision of my LabVOOP Design Patterns document -- with some revisions and with all the implementations filled in finally -- is now available. Unlike previous versions that you downloaded from somewhere, this version is in a WIKI so that the community can help maintain, extend and comment about the document.

    http://decibel.ni.com/content/docs/DOC-2875

    This document takes several of the design patterns from the Gang Of Four book, originally written for C++ and similar languages, and explores how to implement those patterns in LabVIEW.

×
×
  • Create New...

Important Information

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