Jump to content

Aristos Queue

Members
  • Posts

    3,183
  • Joined

  • Last visited

  • Days Won

    202

Posts posted by Aristos Queue

  1. Aristos, do you think you could implement this in a future release of LV. After all it seems to me quite powerful addition to the language :)

    Worth thinking about, certainly. At this point I don't see any pitfalls.

    Edit: Some more brain work.... your design pattern would also allow users to make pure virtual classes :)

    My brain is going slow this morning. How does this work?

    Oh, and I did find one hole in the entire solution... uninitialized shift registers. An unscrupulous programmer can connect the terminal output of one of the exposed VIs to the inside terminal of the right-hand shift register. Then the left-hand shift register, if left unwired, would be able to produce an uninitialized (in the most terribly litteral sense!) value of the class. To really enforce the pattern, I would need to force shift-registers to be wired if they cannot access the class.

  2. Class probes can access to private data members of the class. However class probes cannot access private or protected member methods of the class. Workaround is to make methods public, but then the methods will also be visible to class user which really spoils the idea of private and protected methods.

    This was reported to R&D (# CAR 4148NNJ1) for further investigation.

    It is confirmed as a bug. Custom probes should have the same access as any other VI in a library (or any deriviative of library, such as class or XControl).

  3. So, a suggestion that's been knocking around the R&D team for a bit....

    I've mentioned several times (during the beta testing, at NI Week, in various forums) that the Error Cluster would make a great class ... if only we already had classes and were introducing the error code cluster for the very first time. Mutating all existing VIs and prims in some future version of LV would be nigh on impossible (I think). But...

    The General Error Handler.vi takes in an error code cluster and makes it presentable ("human readable"). This VI follows a general pattern of 1) look up the code in the error code database and 2) display the source of the error with the translation. Now, several hacks have been applied in the past to embed information in the error code cluster. Specifically, the GEH.vi recognizes <append> and <err> tags. If these two tags appear in the source string then they are interpreted to mean "the source stops before this tag and everything after the tag should either be appended to the translation of the error code from the error code database or should replace the translation in the error code database (depending upon which tag is used)."

    When DAQmx was rolling out, the hardware teams really wanted to have an error code cluster that would produce a graph in the General Error Handler.vi. We said No Way because the GEH.vi is too big already. We really can't afford to bloat it further with specialized dialogs for particular error codes. But what if we could dynamically dispatch somehow? Then we would only have VIs in memory for those errors types that actually might occur in a system -- that means specialized dialogs wouldn't be a global expense.

    So the idea is to introduce an <obj> tag. Everything before the tag is the source of the error. Everything after the tag is a flattened object inheriting from ErrorDescription.lvclass or whatever name we make up. Then we could have the core of the GEH -- where the error code gets translated and put into a dialog -- be a dynamic dispatch. If no <obj> tag is encountered, construct a default error description object which does what the GEH does today.

    The nice aspect of this is that non-LabVOOP users would get the advantages of object dispatching and specialized error types without ever having to be aware of them.

    I have no idea what the performance would be like. I haven't had time to prototype the idea. But in combination with your throw/catch suggestion it might be a better way to handle errors in LV.

  4. Hmmm... Interesting. Could I use those VIs not only to create custom class icons, but to create a custom class wizard, that is executed when ever a class is created? This could allow me to define a set of predefined project items I could select to add to the library and, well everything. So the question probably is if I can anyhow get access to the referense of the class library being created. Can I?

    Nope. That VI only controls the icons. It takes an icon set in and outputs an icon set. That being said, the functions for "add to library" etc are all available. Take a look at the VI Server meths/properties available for LVClass library files.

  5. It means number of rows of pixels. If your mask color is white and you use white text in icon header, then the header text wouldn't be copied. Therefore you can define the header height in number of rows of pixels, so that the complete header is always applied. In addition all the pixels that are not of the mask color will be copied from everywhere else except header.

    Asking is defenitely easier, the code is really ugly. I coded it in a hurry and for just one purpose only. Perhaps later I'll add some more features later on and clarify the code:

    • Inheriting overloaded VI icon from parent class VI
    • Automatically generate color16 and monochrome icons from color icon
    • Automatically applying color for the frame surrounding icon; red for private and blue for protected (user defineable colors)
    • Allow user to select library items to include / exclude
    • Store settings to file

    Since you're playing with the icons, you should know that the initial icons for the private data control and the library are both set by VIs in <labview>\resource\plugins\ directory. The VIs are named something with "icon" in the name... I don't recall off hand. You can rewrite those VIs if you want different initial icons (or even create a walk through wizard for establishing those initial icons).

  6. Beautiful! "Save a bug report! Write it yourself!"

    [*]You can also define the number of lines from the top of the template to always copy to method VI icons (this allows you to use mask color in the header)

    I had a hard time understanding "number of lines." Is this "number of rows of pixels" or "number of lines of text"? [Yeah, I could drill into the VI and puzzle it out, but it is easier to ask.]

  7. From your detailed answer (thank you), I gather that in all instance (while debugging classes) the only errors to pay attention to are the one marked with a red x and everything else is basically broken because these red x errors; if this is correct, then why do I need to see all the other errors? this just add to the noise and does not make my job any easier.

    I made the same argument. I was forced to conceed the necessity of showing all the broken VIs, though I keep hoping for a better idea to come along.

    Basically, when a VI is broken, you can click on the broken run arrow and see a reason why the VI is broken. Now, if the VI is broken because of a subVI, my thought was, "Well, then take me to the broken subVI... why am I messing around here?" But although sometimes you might want to fix the subVI, it was pointed out that sometimes you you may want to know which subVI node is the problem so you can delete that subVI call.

    With LV classes, I think 90% of the time you're in the situation of "please, just take me to the subVI." That's because so many barely related VIs break in response to a single broken VI. With LV in general, I'm not sure what percent of the time you want to fix the subVI vs change the call to that subVI. But since few developers are LabVOOP developers at this time, we stay with the current convention of scrolling the Error List Window to whatever subVI you clicked the broken run arrow on... you can scroll up to the Red Xs. I did at least get those sorted to the top of the list.

  8. You mentioned RT / FPGA targets. Does LVOOP extend to those targets as well, without modifications?

    No. At the current version LVClasses cannot be downloaded to any of LV's targets. They execute exclusively on the desktop platforms (Mac, Linux, Windows). They are completely portable across those platforms. The targets, well, ... R&D never promises features. But, in the words of one developer some years ago... "It would not be unreasonable to assume that we might be working on something like that."

  9. In order for any VI in Class X to run,

    A) every dynamic dispatch VI in the Class X must be runnable.

    ...because we have to build the dynamic dispatch table of compiled VI pointers in order to have runnable data on the wires. Trying to only reserve certain positions in the dispatch table turned into a nasty mess that wasn't really maintainable. When you hit the run button, we were traipsing through call hiearchies, including all possible dynamic dispatches, searching for any call that might invoke a given subVI and then figuring out which position in the dynamic dispatch table that subVI occupied and thus all classes needed to be able to reserve that position.

    B) X's parent class has to be runnable.

    ...because the child is a parent and depends upon the functionality of the parent. By induction, this implies all ancestors of X must be runable.

    C) all classes that are members of Class X must be runnable

    ...because those classes are part of the data of X.

    D) all classes that are children of Class X must be runnable

    ...because controls of Class X can contain child data and there's no way to detect when we hit the run button whether or not such data exists.

    E) we have to lock all members of Class X (even the static ones) so that you cannot edit them because if you were to edit a static VI to be dynamic while the classes were running, this would change the indexing of the dynamic dispatch table.

    This is a burden for LV that I'd like to decrease, but I would like to point out that in most languages the entire hierarchy has to be runnable for anything to work. We were able to maintain the individual runnability of VIs, but everything has to be *able* to run.

    Also, I end up in situation with several VIs with a red X where I was not able to figure out what was wrong.

    I'm very concerned about these cases. A lot of stuff breaks when one VI breaks, but that one VI should be readily findable with the red X and I'd hoped that the errors there were sufficiently explicit. Was the error list window not descriptive? What were these errors?

    I know about the red X, but why does VIs in the class that have no dependency whatsoever (whith the broken VI) are broken?. Basically, every member in the class is broken (and if you follow the error path [from VI to VI] you end up in a recursive list of errors). Why?

    See above for why so much breaks. As for the cycles, the dependencies list is cyclic and its hard to get descriptive error messages propagated so that everything is reporting the real reason for its breaking, especially when there are multiple things really broken. Again, that's why the red X modification was so important to get in this version.

    In my opinion, the class debugging is so poor that this greatly limit LabVIEW OOP usability.

    There are certainly improvements that can be made in the future.

  10. Aristos,

    I thought flatten data was a way to store arbitrary complex structures in a continous piece of memory, but it is not the way that data is stored in memory when that complex structure is passed in a wire?

    Many flavours of GOOP floating around, uses some kind of flatten data as storage, and each flatten/unflatten operation requires memory allocation and copying?

    So if NI could make LabVOOP work with the native datatypes instead of flattening data we would not see these memory allocations, with increased access speed and less memory footprint as the result.

    AH! I found the miscommunication!

    "Stores" in this case means "saves on disk or transmits across TCP/IP or explicitly requested by LV's Flatten to String prim".

    In memory the structure is just as unflat as any other LV structure.

  11. I will have to second that.

    I got VERY frustrated trying to debug simple LV class.

    A wire connected to the wrong input and the whole class is broken and the error windows return a huge amount of errors completely irrelevant.

    In some instance I could not even figure out what was going on and I had to recreate the class from scratch (what a pain).

    To make thing ever worse try to put a class in a lvlib... Enjoy the nightmare.

    PJM

    Take a close look at the Error List Window. The items at the top (scroll to top) have a Red X next to them. These are where the real breaks are. Everything else is broken because of one of these.

    This is a fix that applies even to subVIs in deep hierarchies. This UI feedback should help with a lot of the "drill down the hierarchy" type problems.

  12. bsvingen:

    Please keep a log of where your biggest time sinks are. The team is already aware of the gigantic sucking pit of time needed to edit icons, even if you're just doing text, and we have a way to fix some of that. Further, we know about the need for automatic (scripting) creation of get/set methods for member fields.

    C++ has more syntax when classes get involved than plain C. It seems like most languages have this overhead compared to their non-class counterparts. With the graphical environment, we need to log what the biggest sinks are and try to provide the needed shortcuts.

    Glad to hear that the LV2OO idea is working out for you. What I posted is a first attempt -- I've had the implementation for a long time, but I didn't have time to really clean it up or consider ways that it might be augmented.

  13. THERE IS A TIME AND A PLACE FOR OOP

    The time is now? The place is your harddrive? :)

    Seriously though -- as much of an OOP advocate as I am, I agree. If you're building an app that isn't going to be used but once, or if you're just setting up to take a quick DAQ measurement, or any of a number of low level function VIs, you shouldn't be setting up a class. Too much work for too little return. OOP comes into play when:

    * the app will be maintained and revised over time

    * multiple developers are working concurrently on the app

    * one developer develops, then hands off ownership to another developer

    * the app is going to be bigger than some threshold, probably somewhere around 10 VIs, or whatever point it is that you can't hold the whole app in your mind simultaneously and need some structure to keep it together.

    That having been said...

    OO Programming is not the same as OO Design. And OO Design is eternal and universal. :)

  14. While trying out the LabVOOP, I searched the LabVIEW help and discovered that this implementation uses flatten data as storage instead of native data format. This could mean that to access only one attribute, LabVIEW still have to unflatten the complete structure?

    My guess is that this is something that will change in time, because it makes no sense for NI to use flatten data when they have full control of the data handling. Anyway, I think that this is something that should be mentioned in the Critical analysis...

    /J

    I don't understand your question. What exactly is the difference between "flatten data" and whatever it is you think NI has access to? I'm not trying to be difficult, but I'm not sure what optimization you see.

    "This could mean that to access only one attribute, LabVIEW still have to unflatten the complete structure?" When LV unflattens a string of data, it knows the type of the data because you wire a type descriptor to the input of Unflatten From String. With LV Classes if you wire a type descriptor of Parent, the data could be of type Child. This is perfectly legitimate. If, however, Child.lvclass is not in memory, then how can LV unflatten it? LV has no idea what Child.lvclass looks like -- its a data type that a user created. In fact, there may be many Child.lvcass files on disk. Which one did you intend? So, yes, we have to have the definition of the structure in order to access any element of that structure.

    That's why I'm confused about post. I'm happy to address the point (and maybe update the Design Decisions document) but I'm not sure what needs addressing.

    Dataflow OOP has however raised a need for totally new kind of reentrancy,

    Actually, it suggests the need for about a bijillion different flavors of reentrancy. Or at least a consistent view of what "reentrancy" means. ;-) And that is part of why it isn't in this release -- it turned into a deep deep pit of issues, options and conflicting use cases.

    Wire level reentrancy poses some serious problems. Let's take the issue of Custom Probes -- just to pick one. If the data goes down the wire, do you want a copy of your data going into the Probe (because it is going to be there after the execution continues past the probe) to be allocating new data spaces? There's some serious negatives for performance if you do, and some serious impact possible on the actual functionality of your VI if you do (because then running a custom probe would modify data).

    Another issue: Should the reentrant dataspaces remain in controls after the VI finishes running? That would mean that as long as there's data of the class, you couldn't edit any of the reentrant VIs. That would be a serious problem. Or do we need to save off the current run state of every member VI for every class instance every time a VI goes idle and then restore that running state (uninitialzied shift registers and all) when you hit the run button or use Value property to get that value into another running VI?

    Wire level reentrancy gets very icky very quickly. I don't like dumping on this idea, but it really is nearly unworkable. Once I really sat down and asked "what would it mean to have a VI dataspace associated with each object?", I ended up with many conflicting cases, which lead to unpredictable behavior. I think that wire level reentrancy is a fun idea that isn't really needed: if an object needs to store all of its data in itself, not storing it in local variables and uninitialized shift registers of member VIs, then it can initialze any shift registers that need to be "per object" whenever that method executes.

    Something needs to be done to support reentrancy with classes. No doubt about that. But I don't think that wire level is going to work.

  15. I'm just wondering if the project file is deleted somehow, will it still be possible to edit the objects (LVOOP)?, or are they/inheretence etc lost forever? :oops:

    The LV classes are completely independent of the project that you used to construct them. You can load the same classes into multiple projects simultaneously (just as you can with VIs) and you can load VIs that use those classes without opening any project at all.

    The project is just a listing of files and how you're using them. Unless you're using targets (FPGA, RT, etc) I don't think any information is uniquely stored in the project file. The project does store the deployment information for the targets, ie. which VIs get downloaded to which target. The storage of relationship information about the class and the definition of the class is entirely in the .lvclass file.

  16. I would greatly appreciate LabVOOP design patterns. However you Aristos mentioned in another post that LabVOOP that it's currently hard to know which is the best design since the language is so new. So I don't think that a fixed document can do the thing, LabVOOP design patterns will evolve for some time until we the community understand what is the best way to implement different things in this language. So instead of document I'd appreciate a kind of online design pattern library. Each design pattern should include
    • name of the pattern
    • verbal description of the pattern
    • UML of the class hierarchy
    • images clarifying the central parts of the code (png not jpg)
    • example code as a zip packages
    • discussion forum about the pros and cons of each design pattern in slashdot style, everybody can comment and suggest new design patterns but only the moderators can add new design patterns to keep the quality of patterns

    The PDF is what you just asked for -- name, verbal description, image, link to example code, editorial comments. it's the best I've been able to pull together thus far. The patterns I've included are reasonably sound concept wise for LV... its the implementations that are questionable. The UML component, for example, will be hard to stabilize for some time, thus I didn't even attempt it in this draft. If you're looking for discussion about each individual pattern, I didn't think it was worth, at this point, starting a separate discussion forum for each one. You can do so if you think it's worth it.

  17. Well, I'm back... The data does indeed need to go "more than one place" :(

    I've learned that there is data that must be evaluated AND shown to an operator before and during actual logging to file. I've created a new vi that reads the original raw data queue (tcp strings) and performs a least squares fit on a subset of that data. I create a second data queue within this new vi that I "forward" the raw rate data (tcp strings) to.

    Sounds like a good design.

    By the way, under the hood the queues are a very efficient circular in-memory buffer. They don't do any data copies when enqueing and dequeing unless you fork the wire to take the data elsewhere on the diagram (and even then only if the "elsewhere" is a function that will modify the value).

  18. If you have LV8.2, I offer a new twist on an old idea. You've heard of LV2-style globals? If not, go search LV's online help for "functional global variables." They're very useful and dataflow safe. For everyone else:

    I've put together what I'm calling a LV2OO-style global*. I'm not convinced that this implementation is ideal, but I want to get some conversation going about the possibilities. Basically, I suggest that classes make it possible to build a single LV2 functional global that doesn't need to be rewritten for every use, among other advantages.

    :!: Download LV2OO Prototype

    If you download and unzip this, open the project file and then open the top VI in the project (the only one not in a folder). Comments explaining what's going on are on the FP and BD. Many of the ideas discussed in this LAVA thread about references could apply to the LV2OO-style global. I'm interested to see what comes out of the brainstorm.

    This is just a prototype, so there may be rough edges.

    * LV2OO : As in "LV2 Object-Oriented".

  19. I've posted a document on my personal website on the topic of LabVOOP Design Patterns.

    Here's a bit from the introduction to let you decide whether you want to dive into the whole document. :book: Feedback is welcome. Eventually I'd like to put this up on DevZone, after it has a bit of polish, but it has not been reviewed by any tech writers yet.

    When talking about computer programming, a design pattern is a standard correct way to organize your code. When trying to achieve some particular result, you look to the standard design patterns first to see if a solution already exists. This sounds a lot like an algorithm. An algorithm is a specific sequence of steps to take to calculate some result from a set of data. Generally algorithms can be written once in any given programming language and then reused over and over again. Design patterns are rewritten over and over again. For example, in house cleaning, consider this algorithm for vacuuming a carpet:

  20. Edit:

    Ok. Now I have implemented the recursion by stack. I was able to implement stack recursion easily. However as I suspected I failed to keep classes clean

    Ok... new idea:

    A variation on the "Vistior" pattern (see Gang of Four textbook)

    Add a method to FileSystemObject called DoTraverse.vi. This VI takes as inputs a FileSystemObject (dynamic dispatch input) and a TraverseVisitor. The TraverseVisitor object has a method "Enqueue Next Element" and a member field that is a queue refnum. A standalone VI obtains an unnamed queue and uses that queue refnum. Enqueue the root of the tree in the queue. Then in a loop the VI dequeues, calls DoTraverse, until the loop is empty.

    Result: You now have a generic traversal of the tree. The TraverseVisitor can be subclassed to provide different data/services to the DoTraverse.vi implementations. The parent class FileSystemObject does not have anything about "next" or "child" in its definition, only a method of what to do during the traversal.

    ----------------

    More general note about this conversation: It's a very strange feeling. I have programmed LV, JAVA, C++ and half a dozen other languages. In all of these, I could quickly identify a hack as distinct from a good implementation. With LV and OO, I have only vague feelings about whether something is a hack or not. I've never worked with a programming system this new before. Very cool, in some ways, very odd in others. This conversation needs to be tracking two aspects: 1) the search for good implementations and cannonical patterns and 2) the holes that need new language syntax to patch over. Distinguishing what is a hole that needs to be patched from a bad idea that should be avoided is the root of the design decisions that lead to the current LabVOOP implementation, only now there's a working model to see if the theory tests out. ;-)

    ----------------

    [Later Edit] We could simplify this purity problem you're having. :P In the file directory use case, you could argue that every FileSystemObject should have a GetNext function... after all a shortcut is a file that might want to traverse to its real file, or a .zip file might want to traverse to the files contained within it. "When the problems get hard, redefine the solution." :P

  21. Also a special question for Aristos, what is NI recommendation for this kind of problems?

    Reentrancy is a nasty problem for dynamic dispatching. I won't go into the details here. There's all sorts of weird ideas kicking around the LV team on how to handle it, none of them exactly satisfactory yet.

    There's a couple of answers.

    • The first answer I can offer today is the refuge of CS theory: Any function that can be written recursively *CAN* (provably) be written iteratively. The trick is figuring out how to do it for your particular algorithm, and there is no magick bullet. Most solutions use a stack data structure. Using the Queues I've managed to get several recursive algorithms implemented in G. Tree traversal tends to be easy if you want breadth first traversal -- enqueue the root, then inside the loop dequeue an element, operate on that element, then enqueue the element's children, if any. Continue looping until the queue is empty. Depth traversal is done the same way, only using Enqueue At Other End prim. This works even if your tree is implemented as an array with stored indicies for left and right children -- just enqueue indicies instead of the elements themselves.
    • The other answer is to have a non dynamic function that is reentrant and recursive that calls a dynamic subVI. The subVI "does whatever" and returns enough information for the non-dynamic portion to decide which node to recurse on next.

  22. I think almost all LAVA users agree that there are serious problems with the implementeation of LabVOOP. What I suggest is that we bring front and analyze those problems. We then try to innovate the best possible way to implement OOP in context of LabVIEW and dataflow programming. We gather this information into a form of a proposal, prioritize things into a few categories and then hand this proposal to the CEO of National Instruments. What do you think?

    The map of things you can do with LabVOOP still has "Here There Be Dragons" on it in many places. We've set up base camp and will be exploring out from here. Pointing out which dragon's region you'd like to civilize first would be useful. But I do think that sending the list of priorities to someone on the LabVOOP development team would be more useful than sending them to Dr. T. Just my opinion. :P

    In the last days i have read from NI officials (the white paper about LVOOP and a post in here from NI R&D) that XControl is in fact needed for proper automatic initialisation of objects and that the XControl is "the single reason to upgrade to LV8.0". To me they are saying that the Full Development System is NOT a "full development system" anymore, starting from LV8.0.

    Both of those sources you cited are from me personally, so please don't hang "NI" with that rope. You don't need XControls for classes or to make useful apps with classes. So far I have four good size apps where every VI is part of a class and none of those have XControls anywhere in them. So you can do a lot of development (one might even say "full development) without XControls. I see many UI/initialization aspects of classes that can be simplified with XControls, but those aspects can be worked around. Christina Rogers' refactoring of the Getting Started Window is all about UI, but doesn't use the XControls. I try not to advocate tools that are only available in Pro as The Solution on general sites like this precisely because not everyone can get the tool (on LAVA/info-LV I'm less concerned about things not in Base package). In this case, I didn't know.

×
×
  • Create New...

Important Information

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