LAVA 1.0 Content
Members-
Posts
2,739 -
Joined
-
Last visited
-
Days Won
1
Content Type
Profiles
Forums
Downloads
Gallery
Everything posted by LAVA 1.0 Content
-
I encounter the following quite frustrating problem. I've created a class hierarchy of three classes. I'd like to make a copy of these classes. So I add a new folder to the project explorer, add all the classes to this folder, convert it to library and save everything. To test if this library works, I run en example that uses the classes and which I also included in the library. Well, LabVIEW crashes and the project gets corrupted. Detailed information below. System is Win XP SP2 + LabVIEW 8.2. To repeat the bug do the following: - create an empty dir called Tree - extract the Tree_002.zip to this directory - open Tree.lvproj - click My Computer on project explorer and select New Folder - Name the folder Tree - Move all 3 classes and the Tree Example.vi to this new folder - Right click the Tree folder and select convert to library - Save the library as Tree.lvlib inside Tree directory (you created in step 1.) - select Save All - Open Tree Example.vi - Run it LabVIEW crashes and the project gets corrupted. Posted to NI with ref num #8959-P3E602 Download File:post-4014-1156528264.zip
-
Trees, Recursion, Reentrancy & LVOOP
LAVA 1.0 Content replied to LAVA 1.0 Content's topic in Object-Oriented Programming
I try these out. I kind of thought of these already, but my intuition says there may be a few problems especially in the case of OOP. Consider tree structure of files and directories. You can think of class structure FileSystemObject to be the parent class and File and Directory both being child classes of FileSystemObject. Now the FileSystemObject in common denominator for both Files and Directories. Files can hold data and Directories can hold other FileSystemObjects. This can be implemented in LVOOP and is very similar to the example I posted above. The problem is that in OOP the Files unlike Directories are not containers of other FileSystemObjects. That means that the common super class FileSystemObject cannot be container of other FileSystemObjects. So in a strict sense it cannot contain a method to do the recursion, either iteratively or using reentrant calls. The only place the recursion can take place is in the method of Directory class. But then neither of the methods Aristos mentioned work, since both of them need to be executed from the FileSystemObject level. At least that is what my intuition says. I'll try it out. To summarize the problem is that if one wants to recurse trough a tree structure, one needs to violate the OOP encapsulation paradigm and include properties and methods to the parent class that are really not properties and methods of all the child classes. One can of course hide the implementation from the class user. However from the class developer point of view, the class reusability suffers. In order to add new kind of child class to a tree class hierarchy class developer may need to modify the top most class parameters and methods to do the recursion properly. This requires that the implementation of the tree class hierarchy cannot be hidden from the class developers. Hiding the implementation also from class developers is one corner stone of object oriented programming paradigm. I'll try out if my above described analyzes really holds or if I'm thinking something wrong. 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, i.e. I was forced to include methods to the parent class that really didn't belong there. I kept these methods protected so that the dirtyness is not visible the class user but only the class developers. The new version of the example is below. Download File:post-4014-1156502334.zip In the example the Tree Object class is the parent class for Node and Leaf classes. I was forced to include _getItems and _hasSubItems methods to the Tree Object class, both of which are protected. I use _ to indicate that a method is protected. These items do not naturally belong to Tree Object class, since objects of Leaf class can never have sub items and sub items is not there fore a common concept of both Node and Leaf classes. Can anybody find a way around this elegancy problem that perhaps only arises from my puristic mind -
Trees, Recursion, Reentrancy & LVOOP
LAVA 1.0 Content replied to LAVA 1.0 Content's topic in Object-Oriented Programming
Yes, see my example above. That however wasn't the problem but rather executing functions on the tree. Edit: The problem is recursing trough the tree. -
Hi folks, The data in my project is naturally trees. LVOOP seems like a elegant concept to encapsulate trees. So I made a class hierarchy to encapsulate a tree and it seems to be elegant and works perfectly. BUT. There is a big BUT. Recursion is a natural way to deal with trees. In previous versions of LV, I was able to deal with tree like data structures by calling re-entrant VIs dynamically. This was not always the best performing method as dynamic calls took quite a while but it was elegant and worked perfectly. I was hoping that I can combine recursive handling of trees with the elegance of encapsulation provided by LVOOP. But it seems I cannot. Trees are naturally handled by recursive operations. In my project where I use trees I cannot think of any other simple enough way to implement one of the central features of the program except recursively navigating trough the trees. The problem now is that I find no way to implement recursion with dynamic class methods. The dynamic class methods don't allow reentrant calls and therefore don't also allow recursive calls. Dynamic methods are needed, since the objects in the tree are not the same and need to be handled each different way. The example below helps to understand the problem. Download File:post-4014-1156366399.zip In the attached example I have created an example of the situation. I have an encapsulated the tree concept into three classes. The first class is "Tree Object" and each item in a tree are always tree objects. In addition I chose to have only two types of "Tree Objects": "Nodes" and "Leaves" both of which inherit from the class "Tree Object". Of course in reality I would have much more different kinds of tree objects but this is just a simple example. Each "Node" can contain any number of "Tree Objects" where as each "Leaf" is on the top of the tree. I have a few methods: getType is dynamic and common for all three objects and is used to identify each object type. Another dynamic method that is common to all three classes is "toControl". That is meant for populating a tree control using the content of the tree. "Nodes" have two additional methods "addItem" and "getItems" which add and get new "Tree Objects" from the tree. The "toControl" method represents a general problem of navigating trough the tree and executing some code for each object in the tree. The executed code needs to depend on the type of the object. I tried to implement it using recursive calls to the toControl method. There were no compile time errors, so I was very hopeful that it will also run correctly. To my disappointemt when I run the code, it fails to execute because of recursive calls. Can anybody think of any other way to implement tree class structure of heterogeneous trees elegantly and allowing recursive navigation trought the tree so that the top-level class doesn't need to know which kind of items there are in the tree and the decendent classes don't need to know about other decendent classes. For the moment I cannot think of any way... This problematics is super simple in C++ and Java. I don't care if it becomes a little more complicated in LabVIEW as long as I just can do it elegantly i.e. preserving the class structure and encapsulation. Also a special question for Aristos, what is NI recommendation for this kind of problems?
-
Thank you for that Aristos, I agree with you in this issue. And despite all the critics I have given on LVOOP, I still think that even the present implementation of LVOOP is a great advancement. I also like your new icon (below) I think represents the fact that LVOOP doesn't have by-reference objects and that you have to use queues to get by-reference behaviour for the objects. Perhaps I should ephasize that unlike most of people here, I agree with you (NI) that it was the only possible choise to implement LVOOP was by using objects-by-value, although I don't see why objects-by-reference couldn't have been implemented on top of that. Perhaps you will, perhaps you will... *hopeful thinking*
-
LabVIEW doesn't force convention, as you all know. It would extremely help class user if there was a common naming convention for initialization methods. It would also reduce bugs, as class users could easily verify if such a initialization method exists. On the other hand if initialization method name varies from one class to another, it is very easy not to know if some method should be called to initialize an object. Consider how much it easies your life that all programs have the same name and place for the operation that stores your current work to disk. On Windows computers it is File -> Save or Ctrl + S. It's a little same thing here. May I ask why? Don't you see any good in common naming convention?
-
Interestingly even though you cannot overload operators in LabVIEW you can "overload" method icons, that is create a method with exactly the same icon. This has the same result in code readability than operator overloading, since icons define "what you see" instead of VI-names.
-
I suggest common naming standard for class initialization methods as long as LVOOP doesn't provide special initialization methods. There is a strong need for common naming so that class users easily know which method to call to initialize an object. The name of the initialization method needs to be different for each method in any class hierarchy because LV doesn't allow overriding the method connector pane. Therefore I suggest that all initialization methods should have the name of the class. That is for ClassA the default initialization methods should be called ClassA.vi. If class needs destructor, it should be called ~ClassA.vi following the naming in C++. "~" can be part of file name at least in LV 8.2 on Windows XP, can anybody verify that this also works on Linux and OS X. If there are more than one alternative initialization method for the class I suggest that the default one should be called as described above. The succeeding ones should be called ClassA.1.vi, ClassA.2.vi, .... that is adding the period and the number of the initialization method. The numbering starts from 1, the default method can be considered as the zeroth one. How does this sound to you?
-
XControls can be used for FP initialization of the object, but not for block diagram initialization (you would need XNodes for that). So one shold encapsulate the initialization method separate from the XControl and use XControl just to call the initialization method. I think XControls are far too complicated and slow to develop to just do the object initialization. There should be a simpler and faster way. I hope NI will develop a constructor which has i) block diagram that initializes the object, ii) a typedef that defines the parameters to be passed for the constructor and would also act as the interactive control replacing the need for XControls and iii) front panel that defines the block diagram interface and connector pane for the constructor. There should also be ability to have more than one constructor for each class, however one of them should be default. When placing the class on the front panel or block diagram one could right click the object and select non-default constructor instead of the default one.
-
The example #3 works for simple classes but it still lacks the ability to use the class with external algorithms that would modify the class content. (Read the post scriptum first...) To enable this we need some further modifications - addition of new public lock method - this would lock the object and return a "lock reference" - if class user intends to modify a class object based on a result of a class method he needs to acquire a lock - only one lock for the object is allowed simultaneously - during lock all method calls that would alter the object are prohibited - during lock all get_only methods that do not modify the object are allowed (see limitations below) - addition of new public release method - releases object lock - all class methods modified - all methods have a new connector for a "lock reference in" and "lock reference out" - get only methods and methods that do not modify the object - can be accessed when object is locked and lock reference is not wired - cannot be accessed when object is locked and lock reference is wired - all methods that modify the object - cannot be accessed when object is locked unless correct lock reference is wired to lock reference input - all methods wait until the lock is released or timeout is reached unless correct lock reference is provided The programming model for algorithms that are external to the class is following: - acquire lock - get some data from the object - process data algorithm internally - modify the object trough class methods based on the processed data - release lock As an example of an algorithm consider the following An object that is container for some time series data, let's call it DataObject A algorithm that takes DataObject as an input and reduces noice and returns DataObject, let's call it Denoise - Denoise acquires a lock for the DataObject - Denoise gets the time series by calling DataObject.getTimeseries - Denoise reduces noise from the acquired time series - Denoise writes new denoised time series by calling DataObject.setTimeseries - Denoise releases the lock POST SCRIPTUM This kind of programming model closely resembles of functional programming and is often preferred over the programming model where all algorithms are defined as class methods. The advatage is generality and code re-usability, a single algorithm can be applied to a number of different classes as long as classes fullfill certain preconditions. I however started thinking while writing if this kind of functional paradigm can even be used with LabVIEW. In C++ algorithms are implemented using templates to overcome strict typing. Haskell naturally supports algorithms by polymorphic typing. Java algorithms can be defined trough defining common interfaces for the classes. None of these methods is available in LabVIEW. Polymorphism is only available via XNodes, variants, flattened strings and polymorphic VIs. XNodes are not available, variants and flattened strings don't seem to do the thing, and polymorphic VIs require adding a separate VI for each new supported class. I've used scripting to create polymorphic VIs with normal data types but I'm not sure this concept extends to creating class methods; LabVIEW 7.1.1 ,which I use for scripting, doesn't have the concept of classes. NI is propably not going to implement interfaces or templates in a long time. So we are left with manually adding new VIs to polymorphic algorithms. Perhaps the idea of algorithms just don't fit into the world of LabVIEW in it's present stage. Wouldn't be the first programming concept I'm missing...
-
If parameters to initialization method (or constructor) would be passed always as a cluster, this parameter cluster could be placed on the front panel instead of the private data members cluster when the class is placed on the front panel. The buffer would be "preinitialized" when the VI is loaded, but when the VI runs for the first time the constructor would be called. If VI is a subVI then constructor is called only if the class control is not connected to an external wire.
-
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?
-
I strongly disagree with bsvingen. Consider for example a class representing an employee with fields with private data members name, age, sex, email, salary etc. I don't think that an initial LV object of this class can be considered an object representing an employee. No static initial values can represent a valid employee. What would we mean by a default employee. What would be his or her salary. Would default employee be male or female. This just doesn't make sense. That is and init method is needed to initialize an object of class employee to validly represent an employee, let's call this method Init. Consider now that you derive a class executive from the class employee. In addition to employee data members, let's add an object representing option program the executive belongs to. Now to initialize the executive class object, we cannot use the name Init anymore, since the front panel layout of this method is fixed and cannot be changed. We need more information to initialize the executive object. We need to create a new initialization method and call it InitExec. What happens if class user accidentally calls Init instead of InitExec when he creates a new instance of executive. According to LabVIEW valid instance of executive class is created and no error is generated. However the object is not correctly initialized, since the option program data member points to some default option program. This mistake is more than likely to happen, if there is not a common name for initialization method (i.e. a constructor). NI emphasizes that it made the design decissions it made with LabVOOP so that LV would stay simple and intuitive to use. I simply cannot see how allowing class users to use inproperly initialized objects makes it clear and intuitive for the class users. Constructors don't complicate the class development at all, but it simplifies the life of the class user. The class user doesn't need to always check what is the proper way to initialize the class. However, I also think that the by-reference objects are needed and in this sense the whole discussion about if constructors are needed only for by-value objects is pointless if by-reference objects will be implemented.
-
using your own Icon Editor in LV8
LAVA 1.0 Content replied to Mark Balla's topic in Development Environment (IDE)
Hi guys & gals, Another similar nice OpenG projects would be a Windows Explorer LabVIEW Extension, that would show the real VI icon instead of the default VI icon when browsing the files with windows explorer. I think this would be fairly easy task, some COM programming and a small LabVIEW generated DLL that would reaturn the icons to the COM program. -
An "empty cluster" is always "100% determined" but the problem is that it just cannot represent the data I'd like it to represent (well it represents nothing). Similarily uninitialized objects don't necessarily represent anything meaningful unless initialized with class programmer defined code. The code could do tricks such use opening a file. An object representing a file that doesn't point to a file isn't really 100% determined to me. What we need to do is that we need to distinguish between the class developer and the class user. The class developer is responsible to develop such a class that is hard to use inproperly by the class user. When we have no constructors, it is fairly easy for the class user to create an object of that class that is not properly initialized. Custom class methods are not a solution. If the language doesn't force their call, the class user can always forget to call them. Even if the user remebers to call the class initialization method, problems arise. A child class cannot override parent class method interface. That is child class cannot use the same initialization method name if it requires more parameters or different parameters than the parent class. Think of a class hierachy of ten levels. All of the levels would have different name for the initialization function. Do you think that the user really remembers to always call the right initialization function. I bet users would call the wrong functions quite often. Then think of the situation you want to change the implementation of your class. You need to do some initialization stuff to create proper objects of the class. Let's say you want to open a file to store very large arrays that don't otherwise fit into the memory. The problem arises since LV doesn't force the call of default constructor. All the code using the class needs to be properly modified to call the custom initialization method. It's very hard to do this since the code looks like ok, there are no broken wires because calling the initialization mehtod is volontery. I could go on this list.... The fundamental thing however is that in object-oriented programming, the objects should ALWAYS represent a valid entity, there should be no uninitialized objects, not even transient uninitialized objects. All objects should be properly initialized on creation or on copying. LabVIEW doesn't guarantee this, or well it guarantees it only for in-memory objects that do not interact with the surrounding word. With surrounding word I mean files, other programs, screen, acquisition devices, network or anything that is not only present in LabVIEW internal memory.
-
The article was good, thanks NI for the article. One thing however annoys me quite a lot in the article. It kept repeating that the lack of properties in LV OOP is due to the fact that scientists and engineers are not formally trained for programming and therefore couldn't use properly any fancy features of programming languages. I strongly disagree with this view. I think that most professional programmers are not really that, well professional. At least no more professional than LabVIEW users are professional programmers. Fromal training doesn't really teach people programm well, programming is learned by practise. There are very talented LabVIEW programmers out there as there are very novice LabVIEW progrmmers out there. But the same thing applies for Java and all other programming languages. NI could easily package different kinds of product packages for different kinds of programmers. For example LabVIEW base package didn't have to include by-reference objects whereas the professional package would include these. No that LV OOP has been launched, I'd appreciate if NI would publish design patters on how to cope with the issues that cannot be coped using the methods in popular object-oriented design patterns due to lack of features in LabVIEW OOP implementation.
-
This is an argument I've seen number of times, that is dataflow implies lack of constructors, copy-constructors and destructors (or implicit memory only constructors). I fail to see why dataflow would imply no need of constructors or inability to implement constructors. One can always allow no constant objects on a block diagram nor on front panel i.e. require that all objects are properly constructed using constructor call. When ever an object is placed on a block diagram, a constructor creating the object is actually placed instead. When ever an object is placed on a front panel as a control, also constructor is placed instead, so that instead of private data elements, constructor parameters are visible on the block diagram. These front panel objects would differ from the block diagram objects in a sense that when the VI is called as a subVI then constructor is not called. That is when ever object buffer is created, it is created not only by reserving a block of memory and initializing this block to default values but instead reserving a block of memory and calling some code to do the initialization. I see no reason what so ever that in dataflow paradigm would not allow this.
-
Hi all, I've written a critical analysis on the implementation of object oriented programming in LabVIEW 8.20. In the same document I propose what I think is a better way to implement object oriented programming in LabVIEW. Check the document out. I'd like to hear your comments. It has been discussed that LabVIEW Object Oriented Programming should be based on objects by reference. I strongly disagree the objects-by-referense should be the basis of the implementation. The reason is that objects-by-value are much more efficient and allows utilizing the concurrecny capabilities of LabVIEW. However I think that even though objects-by-value should be the basis of the implementation, there must be a way to create by-reference objects to refer to objects of the outside LabVIEW world like files and windows and data-acquisition devices etc. I also think that the leaving out constructors, copy-constructors and destructors was a very bad decission. I also cover some other issues, but have left out a few important issues like exceptions due to time limitations (I'm currently on vacation...) Link to the document p.s. I don't have a PDF version of the document available yet. My primary computer suffered from heat and this laptop doesn't have PDF conversion software installed. If anybody is ready to provide the PDF, please email it to me. The contact information can be found from the link above. Edit: I added a RTF for the moment for those who cannot read Word documents. -jimi-
-
MD5 Checksum of my downloaded file is EB49905E432022482A0C2802B8FDA46F
-
Kennon, Thank you very much for the detailed explanation. After carefully digesting the possible solutions, I determined that for my use case 4 or 5 would be the best possible solutions. I quickly ruled out 4 because I realized all the subpanels I was using would have to be changed to Active X containers, and this was not practical for various reasons. So that brought me to 5 as stated below. I have never used VI server to open a LabView built exe, but with the help of my great new Reference book (Labview For Everyone, third edition ) I found that I needed to create an INI with the sme information relative to VI server found in my LabView ini and name it the same as my exe. This is what I added: server.tcp.enabled=True server.tcp.access="+127.0.0.1" server.tcp.port=3364 it would appear that the application reference is correct but when I try to open a reference to the VI (c:\myapplication.exe\b.vi) I get the same error 7 I was getting when I tried just opening the VI reference without passing it the Application reference. What Am I missing :headbang: .? Thanks in advance for any more help you or anyone else can provide. :worship:
-
The LAVA Girls... I Google!
-
I received the same error today (8.0.1). My vis have been in a project (including an lvlib). An associate of mine attended Crystal Drumheller's "Demystifying the LabVIEW Project" session at NIWeek 06, and she suggested that a project should only be created after the VIs are 'mature'. I'm still prototyping, and the rest of my group has not started using projects yet, so I decided to work on the VIs outside the project environment (didn't want to create 'issues' later) I opened the project, removed all the VIs, controls, etc. from the project; leaving only the project name and the lvlib. I saved the project and exited. All is well... I then opened the higher level VIs and saw the "could not determine data types" error. I searched the LAVA forum and found the exact error AND the solution here (recompile). I stopped, put on my LAVA button , and proceeded... My problem was that ALL my typdef'd enum constants on the block diagram reverted to the first value . Also, all the typdef'd enum constants used as inputs to my sub-vis reverted to the default as well. It took me some time to check every one of these. I THINK I dragged and dropped the typdefs from the project window to the block diagram, and also copied these on the diagram, but I'm not sure. I only post this in case someone else is considering "un-project-ifying" your code.
-
I have a sort of test executive I created in labview that calls other labview built exe's and embeds them in subpanels, this technique has worked well for me, and has widespread use at my facility. The path to the VI would simply be <path to .exe/toplevel vi name.vi>, this worked because a LabView exe is basically just a folder with all the VI's in it. In 8.20 this technique is not working, it basically says the path to the VI is bad. I was in a closed door session at NIweek for large application development and they mentioned that you could no longer view the contents of an exe by simply changing its extension to a .llb. I asked if the technique I was using would still work , and I was told it would. It is very possible I did not convey the question properly, or perhaps there is another way to accomplish this task, and that is why I was told it could be done. So in the hope that there is a way, does anybody out there no how to acomplish the aforementioned technique in 8.20?