Jump to content

Black Pearl

Members
  • Posts

    410
  • Joined

  • Last visited

  • Days Won

    13

Posts posted by Black Pearl

  1. Thank you for your reply...As I am a beginner in object oriented programming with Labview (did only some stuff in C++, programming Labview without objectorientation since 6 years now...), I am trying hard to understand your ideas and reading on the design patterns...

    I'm not much ahead of you. For OOP design patterns, I normally use wikipedia (in lack of a text book).

    First of all, as far as I understand, the factory design pattern let me initialize objects at runtime as needed without loading the class (perfect for plugins?). So this would help me to handle all my different data devices...like camera, scanner, ad-card and so on. Is this right?

    My idea of using a factory was linked to the DVR concept. Using a DVR as private data requires an initialization method which you would call in the factory.

    if I know initialize the scanner, how can I pass the DVR from the camera-object to the scanner-object? Is this meant by "the factory object (the DVR??) needs to be a singleton), that if i initialize my camera and later the scanner, the same buffer is used?

    A factory is most of the time implemented as singleton.

    The DVR is a reference. If all your objects have the same reference, they share the data. You just need to pass the DVR to every object you create in the factory, then they all share the buffer. Working with DVRs is very similar to single element queues (SEQ).

    What do you mean, btw, with "serialization that naturally takes place"?

    If you don't set the VI as reentrant, it can only run when it isn't running in an other section of your code. This is a very elegant way of protecting against concurrent access to data. In all other situations you need to explicitly state this, using semaphores around globals, the dequeue/enqueue operation of SEQ, the Inplace Structure for DVRs.

    If it's really a design constraint to make this buffer static? Let me say...the only thing I'd like to do is to know where I can find my data...if I use the camera or the scanner, there shoudn't be separate buffers...as all saving, displaying and manipulation-functions are already implemented, I don't like to distinguish where my data comes from. The saving, for example, is the same routine for scanner as it is for camera...so I want to use the same data buffer.

    Why don't you just use an array as private data in your parent class and implement the data access methods (Get/Set). All code that is the same for every device (like save) will be implemented in the parent class using these data access methods.

    All device specific code goes in the child classes, like 'record' and use the parent methods to place the data in the array.

    (As a side note, you can override the Data Access methods in a child class, the parent calls to these methods like in the save will 'dynamic dispatch' to the child methods)

    By the way: How objects are passed in LabView? I started using queues to do a "by reference" call, as I have to transfer large amounts of data...if I now use classes and pass these classes into my program, the class data is handled by reference or by value? Meaning: If i have one wire which goes parallel to 2 sub-vis, if the upper subvi changes something in the class, it will simultaneously change in the lower subvi?

    Most of the time a by-value implementation should be good. Then you treat the object like a cluster.

    If you need to access the same data in parallel loops, you need a by ref implementation. There are 2 diffrent ways to do it:

    a) place the class data in an DVR, the private data is then the DVR. You can mix this with by-value data (for example only place the buffer in the DVR).

    b) place the object in an DVR. Then wrap all methods of the class inside inplece element structures. You can mix it with by-val, too (direct calls of the class methods, e.g. in the initialization part before you have the parallel loops).

    Felix

  2. My idea would be to have the DVR initialized in the factory class itself and whenever a new ImageDevice object is created, the DVR is set by the create methode of the factory class. The factory object of course needs to be a singletone (there is plenty of discussions on singletons on lava and ni forums).

    Rethinking this, a simpler solution would be to implement the buffer as an 'Action Engine'/'LV2global'. This would be the same concept as I would make the factory a singleton, by using the serialization that 'naturally' takes place at the subVI boundary.

    And rethinking again, is it really a design constraint for you to make this buffer 'static'?

    Again, one different implementation could be to make the buffer an object itself and make this object a singleton.

    Felix

  3. Hi Felix!

    That is correct. A class can implement multiple interfaces.

    Not correct, I did ask if interfaces support multiple-inheritance. The whole concept of interfaces would be stupid if a class would only be able to implement a single interface. To clarify:

    IMyInterface declares MethodA and IMyOtherInterface declares MethodB and I can draw somthing that would be comparable to

    IMyChildInterface extends IMyInterface, IMyOtherInterface

    and if I now have a class that implements IMyChildInterface I am forced to have both MethodA and MethodB (and anything else that IMyChildInterfacedeclares).

    Does your concept of interfaces allow inheritance on interfaces at all?

    Felix

  4. Concerning 'static variables': Just to clarify, you want to have a single variable that is shared among all objects? Then you could use an DVR (data value reference) for this. Then use a factory (search for factory design pattern) to create the objects at run-time and initialize them with the same DVR.

    To set/unset the 'recording' button, I would use User Events and the objects will fire them as Enter/Exit Action of the recording code section. This is motivated by the fact that your FP code has already an event structure and you don't need an additional loop like when using queues, notifiers, some kind of global for this.

    Felix

  5. I did make some progress concerning multiple-inheritance. Because I won't have time to continue on this the next weeks, I want to share my current approach.

    The first thing is inspired a lot by Daklu's Interface Framework.

    Basically I just have an array of objects called step-parents. When I want to cast to a step parent, I check through this array with the PRC if I find it. Then my Child just needs to wrap the calls and pass them to the step-parent class. Here it's simpler than the Interface Framework, where the Interface needs to call back to the class. Also I need an inheritance step to make the protected vi's available. I think it's easy to understand this from the uml draft.

    Now we come to the real tricky thing: the diamond problem. For the methods, it's a decsion of the designer weather to wrap the function from the step-parent or call it's own ancestor. Much more difficult is dealing with the class private data. So we go: the class private data is DVR to the real data. In each Initialization call-chain (going with call parent through the inheritance chain and then creating the step-parent objects), I check weather this object is already present genalogy-array. If yes, the PRC is returning my an object of the same type as 'this', so I can (that's really cool!) access the private (!) data of the object and use it as the value of my DVR ref to the private data.

    So all object's through the multi-inheritance tree that or of the same type have the same 'shared' private data!

    The nasty thing is, that at the moment it seems to be necessary to code the Initialization for really every class, but this can be automated.

    Still an issue is this: If you cast to a step-lineage, dynamic dispatching is not working.

    Felix

    post-15343-127515033457_thumb.png

  6. I had read some of the posts where AQ was talking about the thralling. I really like this feature, because I get a design-time type-check instead of a run-time type-check (errors when I cast to a wrong class).

    I was thinking about which structures would need a thralling-feature and a came up with - only arrays.

    Also, the array-prims will determine the output-type if they are 'inlined'. So it seams to be almost-there. What I didn't think about is nested subVis with thralled array terminals.

    If I find time, I'll place this in the Idea Exchange.

    Felix

  7. There's nothing (afaik) that stops you from iterating through an array of objects and calling PRC on each of them, as long as each object in the array is an instance of or child of the target class. I'd need to better understand the context of what you're trying to do to say whether or not it would work in your specific situation. It's not clear to me why you need it in first place. Can you provide an example of how you expect users to use your code?

    Both vis just pass the input to the output. One with LVObject and one with an array of LVObject. Using an object, I get the output of the same class. Using an array, the class type doesn't get propagated. Also, the array Prims handle the class-type propagation.

    Felix

    post-15343-127488970847_thumb.png

  8. Nope, no way to define something as abstract in LV. In Java if a class is abstract it cannot be instantiated. In LV everything you drop on the BD is instantiated, so abstract classes don't really fit into Labview's paradigm. You can do some things that give you a few of the same behaviors, but I've never run across a situation where I thought it was worth the effort.

    Thanks for this overview. The concepts (Must Override, private in a lib) cover the ideas I came up with. Your experience did add some new aspects. Mainly this assured me, that I didn't miss anything.

    'Abstract' wasn't completely meant in the sense of the 'abstact' statement in other languages, but in the use of all this meta-modelling im into. I could think about instanciating an abstract class but not being able to call the abstract methods. This would be the other way round. I see that you might want to accept the abstract parent class and call the abstract methods of this class because the call dispatches to the child class that has these methods implemented. But I already can do this with interfaces.

    So an 'abstract' statement is just one kind of realization. I'll dig & think further on this topic.

    Just to clarify, they are defined as abstract classes, not Interfaces, right?

    They are interfaces. I guess this is to support for multiple inheritance.

    But I also see a design advantage in this approach. You focus on inheritance and the method declaration only. The implementation is done in a step further down the road.

    If you have a method that you don't want child classes to override, then you make it static dispatch. I use them on occasion but most of my public methods are dynamic dispatch.

    Doesn't make sense for the implementation of eclipse.uml2: the static methods are in the <Class>Operations class and not in the <Class>Impl class. We might be missing something.

    Felix

  9. Thanks Ton for the reminder. But I'm pushing back the design patterns to a later stage of this project.

    First of all, I'm not ignorant of these. I read the GoF book 10 years ago and I frequently re-read them on wikipedia (and if they seem to be relevant, I can cross-check the german and english wikipedia + the linked articles/implementations).

    Second I use the eclipse implementation (it's OpenSource) as a cross-reference. I guess they did a better design job than I am able right now.

    So I'm more struggling with getting these things done in LVOOP with the native by-val behaviour and a lot of things lacking (interfaces, abstrac statement, generics).

    Looking at the java eclipse implementation, I really think that interfaces would do us a favour in the design process (which I really think is a big reason to migrate to OOP, I mean the better 'tools' to do design before coding). In the eclipse code, all uml classes are implemented as interface first, which (in this specific case) is nothing else than designing all function/procedures/methods/properties as a prototype first. In a second step (this is a different folder in the project called 'impl') they do actually implement all these objects (because there is only this single implementation, the other use-cases of interfaces are not applicable).

    They also have another folder in the project called 'operations' (or was it 'util'), in which all static declarations go (named <Interface>Operation, the implementations have <Interface>Imple as name). I must confess that until now, I never thought about using static-dispatch (what are the advantages over dynamic dispatch?); furthermore it seems alien to me to have all these static methods in a different hierarchy (there are calls mainly/only? forth and back between <thisClass>Impl and <thisClass>Operations).

    Felix

  10. I was a bit experimenting in the field of generics. I'll at first give a description of the requirements I have in the uml design, and later go to the LVOOP part.

    uml:

    A lot of attributes or assiciations are defined as 'derived union'. They are similar to an abstract declaration, as they will be defined by child class(es) -> derived. Furthermore they are composed of all subsets -> union. The child classes define there own (derived or non-derived) attributes and declare them as a subset of the parent attribute.

    To make things a bit more complicated, sucvh an attribute can have a multiplicity of [0..1], which is valid if all subsets are either emty or of the same value (the union of all subsets will evaluate to emty or 1 value).

    LVOOP:

    I realize the derived union/subset concept by overriding the derived properties accessor VI to add the subsets that are declared in this class. (Q1)

    So these Accessors (for a correct multiplicity of [0..1]) return an array which is either empty or contains n elements of the same value. So I wrote a vi 'remove duplicates' (I will also need to check for a valid Multiplicity). So input and output of this VI is an array of LVObject. As far as I got, I will always need a for-loop with a to more specific prim. (Q2)

    So far I have only used an array of objects. I haven't explored other concepts of managing the List/Set/Bag. The most simple idea would to use an array of DVR's to the objects. Others would be a by-ref framework class such as linked lists instead of the arrays. (Q3)

    Q1: As far as I know, we don't have any 'abstract' statements in LVOOP. Can you point me to same concepts of implementing this?

    Q2: If I only have a scalar of object, not an array, I can propagate the class type to the output either by dynamic dispatching or the Preserve Run-time Class prim. Any chance I could do this for an array of objects? The array prim's work fine if I'd inline the code... If we can't do this, I'll go and write something for the idea exchange.

    Q3: Will I be able to avoid the type casting if I use any of these concepts?

    Felix

  11. Ok, here we go. Not all accessors are implemented. But the StructuralFeature by-ref class contains a MultiplicityElement by-val class. Exactly: The ME is part of the TD that is inside the DVR of the private data.

    What needs to be done (and this is where I'd code some scripting VIs) is writing the accessors VIs. They do implement all public methods of the delegate and pass the calls to the delegate.

    So actually, this isn't an interface, because the code is in the delegate, but a kind of multiple-inheritance. For an interface, you will have empty methods, inherit them in an abstract parent class and use the must-override flag to force any descendent to implement them.

    Type casting the class to the implemented interfaces is an objectiv I didn't think about yet. But propably with the correct kind of by-ref, the cast would just pass the 'interface-class'.

    The nice thing is, that inheritance works in favour of this concept. The delegate will carry it heriatage (so you can design an interface hierarchy), as well as the class will carry the heritage of all interfaces.

    Felix

    post-15343-127437581413_thumb.png

    post-15343-127437581576_thumb.png

  12. I looked up what an abstraction 'is', so here comes the uml2-spec:

    7.3.1 Abstraction (from Dependencies)

    Generalizations

    • “Dependency (from Dependencies)” on page 62

    Description

    An abstraction is a relationship that relates two elements or sets of elements that represent the same concept at different

    levels of abstraction or from different viewpoints. In the metamodel, an Abstraction is a Dependency in which there is a

    mapping between the supplier and the client.

    Attributes

    No additional attributes

    Associations

    • mapping: Expression[0..1]

    A composition of an Expression that states the abstraction relationship between the supplier and the client. In

    some cases, such as Derivation, it is usually formal and unidirectional. In other cases, such as Trace, it is usually

    informal and bidirectional. The mapping expression is optional and may be omitted if the precise relationship

    between the elements is not specified.

    Constraints

    No additional constraints

    Semantics

    Depending on the specific stereotype of Abstraction, the mapping may be formal or informal, and it may be unidirectional

    or bidirectional. Abstraction has predefined stereotypes (such as «derive», «refine», and «trace») that are defined in the

    Standard Profiles clause. If an Abstraction element has more than one client element, the supplier element maps into the

    set of client elements as a group. For example, an analysis-level class might be split into several design-level classes. The

    situation is similar if there is more than one supplier element.

    Notation

    An abstraction relationship is shown as a dependency with an «abstraction» keyword attached to it or the specific

    predefined stereotype name.

    Felix

    PS: I didn't yet read the dependencies package, so I can't translate this to normal-geek-speak.

  13. Just to keep this updated, I'm moving away from the original topic.

    Today I found the 'Delegate' design pattern on wikipedia, and it was mentioned to be a solution for the multiple-inheritance. Well, coded the MultiplicityElement as a by-val class (first attemt was by-ref) and put this one in the by-ref private data of the 'child'-class (so it is already by-ref, that's why I implement it by-val). Then write the Accessor VI's and voila. Looks good so far.

    I think the wrapping of the 'parent'-class can be automated with scripting. Which means, that we propably are a very short step away from interfaces and multiple inheritance of our own brew...

    I'll dig through the interface implementation thread on LAVA tonight, just to see if I miss something...

    Felix

  14. I agree with Daklu that software developement is to a very big fraction about creating abstractions. If you draw good software, you spend a lot of time on this and not on the functionality of the code: descriptive Icons, 4x2x2x4 connector pane, organizing vi's in directories, folders, libraries, placing code inside SubVIs, if you OOP, a lot more overhead is going into encapsulation...

    Abstraction is beautiful, because it structures our code like nothing else.

    A major advance of good abstraction design is reuse.

    Here is one of my better designs. As part of the project I had a motion controller, which came with a dll driver and a bunch of ugly vi's that did implement the dll calls.

    My lowest level abstraction layer did use the provided vi's, but wrapped them with a 4x2x2x4 connector pane and included error handling. This layer could be directly reused on a diffrent project that had the same motion controller but a diffrent mechanical design.

    The layer above provides the functionality I did need for this project (for the specific mechanical design). It consists of very view vi's that sometimes perform complex operations, like Posisition(x,y), Home, ...

    On top of these vis, there is a single Action Engine (no LVOOP available). This AE is only for encapsulation, so all VIs that deal with motion are grouped in the hierarchy window and the 'handle' for the controller card is hidden from the user.

    So the complete LV code consists of 4 abstration layers:

    1. dll calls

    2. error handling

    3. project specific functionality

    4. encapsulation

    My current studies of the uml architecture also teach me how to design abstraction layers. For each concept that is introduced in the uml architecture, there is a set of deticated classes in the inheritance tree (actually, it's a graph as they allow multi-inheritance). And each set of classes is placed in a package. As an example, the ownership package has the two classes namedElement and Namespace. Together, they provide the funtionality to create a tree of nested elements (namespaces are elements that may contain other elements) and to navigate through this tree using OwnedElements and Owner.

    There is no mixing with other concepts. So one concept -> one layer.

    Felix

  15. Are you trying to create something that will generate code from a uml diagram, or just a uml diagramming tool for Labview? (Either way you certainly aren't shy about jumping into the deep end of the pool when learning how to swim.)

    I aim for a code generation tool, I'm addicted to 'scripting'. But I enjoy the privilege of having this as a private project, so I don't expect any tool in the near future. I fear that a major work far on the horizon will be to get uml adapted to LVOOP specific concepts. There is the redefinition package in the uml framework, but I havn't looked at it.

    I did OOP years ago in JAVA, so the basic OOP concepts are not unfamiliar, neither are some of the GoF design patterns. It is a lot of new concepts though, digging through the 100s of pages of uml specs, LVOOP threads on LAVA, scripting and hooks on LVOOP, the eclipse source code...

    But so far I can manage to break things down into smaller issues, as this is my everyday engineering task.

    I'm heading of for holidays this afternoon and might be back on this the end of next week.

    Felix

  16. Daklu, thanks a lot for the bag implementation. I was trying to avoid this topic and move towards having a real 'uml_class' object. But properties inherit (via structuralFeature) from multiplicityElement. To make things a bit more difficult, multiplicityElement has two attributes: isUnique and isOrdered. So I propably need to cover all 4 cases.

    I think I'll try to make it a List (they call that Sequence in the uml specs). Later I can enforce the uniqueness if isUnique. And I can introduce isOrdered=false later as well.

    Felix

  17. Functionally I don't think there's that much difference between the two, though I have not spent a lot of time playing with the object-in-the-DVR technique. Essentially it comes down to how you expect to use the class in your applications. If you're okay with that class *forever-and-always* being a by-ref class, I prefer putting the class data in a DVR and hiding those details from the class user. If I'm not sure how the class will be used I leave it a regular by-val class--the user can always put it in a DVR if they need an instance to be by-ref.

    That makes perfect sense to have the two approaches!

    1) If I'm the class designer and in need for by-ref -> private-data into the DVR

    2) If I'm the class user and need to use a by-val class as by-ref -> object in the DVR

    1) allows the class user to be ignorant of DVRs, IPEs, ...

    2) allows the class user to be very flexible with objects, like have all the init code by-val and just when he needs to branch the object for parallel task operation, place it into an DVR. After parallel execution, dereference back and operate by-val again.

    So they are not two flavours of implementing the same by-ref. But they are two different use cases: make a class by-ref or use an object by-ref.

    Because I implement an design that is completly traditional (I refere to JAVA, C++) by-ref, I get better code making the class itself by-ref. In other situations I might be better off using by-val or object-inside-DVR.

    For my current implementation, I will consider the object-inside-DVR design for the package class. I will try a brief explanation of the model:

    Almost every class is inherited from the 'namedElement' class. This defines mustBeOwned=true. The only class that overrides this is Package (generalization namespace, mustBeOwned = false).

    Because the package is the only class the is 'creatable' by the class user (I use this term as you find it when using ActiveX e.g. to to interface Excel, where you need to obtain the workbook ref from the Applications Workbooks Collection via some methods like Add, New), you can implement factory methods like CreateClass(name, classType) (the eclipse uml2 implementation does this). Using the factory design pattern, you can hide the Create and Destroy methods from the class user.

    General idea for both by-ref designs: It is a bit cumbersome to do all the repeated DVR/IPE/UnBundle operations by hand. Some will be faster using Reusable VIs with the drop content flag set, some will go as templates, others might be benefit from scripting (like an 'Create Wrappers'-tool for the object-inside-DVR).

    uml-tools:

    - I still don't use StarUML although I've installed it.

    - For fast scetches, I still think dia is the way to go (especially as they have also support for other domains, if you don't have a specific tool and/or just need a scetch, it is easy).

    - For design I'm trying to get used to eclipse. They have a design and modelling branch (I think this equals the galileo package). But it comes with a lot of overhead = full support of project management tools far advanced what you have with your LabVIEW installation (+ all kinds of integration with SCC, issue tracker, ...). I think if you have the need for these things, you'll already go with the toolkits from NI so it's just a duplication (ballast) and you won't want to use your own interfacing with the eclipse enviornment.

    But they really offer the most advanced uml support I've seen in any of the free toolkits.

    Felix

  18. It is still raining, so I was doing some code before going out. One thing seems to be a bit cumbersome in LV.

    In a traditional language I can define a class <list> with all kind of add, clear, ... methods and use that as the type for the accessor Get operation. So I can write something like:

    MyCollection.GetList.Add(Element)

    Using the by ref implementation, it seems that I need to either

    a) rewrite the array as an list object (gives a bad performance).

    b) provide a class locking (semaphores) so I can code lock, checkout, modify, checkin, unlock

    c) write the add, clear ... methods for each 'list'

    Any better approaches.

    Felix

  19. Speaking of Vulcans, can you do a mind meld? I have a horrifying image I need removed from my memory.

    I did stop performing mind melds with people that show emoticons. In fact, I restricted myself to only do mind melds with silicon based life forms that run a graphical programming language.

    Thinking about this, we really should have some LV-style emoticons available. Laughing-numerical-prim.

    Felix

  20. I'm back for the OOP training lessons.

    On this rainy afternoon, I did concentrate on the question of how to do by-ref implementations.

    My first approach (and I see the same in the Tree code from GoGators) was to put the object into the DVR. This seems to be a direct translation from other OOP languages with their pointer based by-ref concept.

    So today I realized that I also can place the data inside a DVR, make the object private data only the DVR and have the referencing/dereferencing inside the accessor methods of that object. This looks much better, as I 'hide' the by-ref implementation from the user (means they need to know nothing about DVR and IPE and less effort to code because they need to be coded only once).

    The self-referencing seems to work the same way via a parent class (placed inside the data TD inside the DVR inside the private data).

    Do these two approches to by-ref differ considerably?

    I don't want to consider for now all the fine details where I can get race-conditions or deadlocks, for this I would just like to have a general judgement approach A or B is more robust.

    If the weather won't change tomorrow, I'll try to face my problems with this way of coding.

    Felix

  21. Both books target beginners according to their description. Bishop already has published a book on older LV versions, so propably having a review on one of those would help you judge the 'value' of the new one.

    To the more interesting part of this thread:

    those that lava are of course Vulcans

    Felix

  22. In germany you have the same issues, and I always change the country settings to US. But then if you create a new user (even worse if the customers are doing this), it might show up as DE again. A lot of software and hardware isn't localized, and I really don't want to care about it. On the other hand, Excel is localized to an incredible amount. All the functions for the spreadsheet are localized! If you do any advanced thing with it via ActiveX from LV, this is unmanagable...

    Felix

  23. First of all, get used to data flow. Use wires instead of locals to have the behaviour of 'variables'. You need to wire the output of i/10 to the = function instead of passing it via a local variable. You have no control of the execution order except data flow, so your loop might run 1 more time than you wish.

    Please keep posting code on the forums, so we can teach you the 'right way'. Don't feel offended, everyone coming from a programming background is doing these mistakes.

    As I can't see the true case, I can't judge if the outer while loop is necessery at all or I tried to solve you problem with it.

    Second, there is a primitive called 'First Call'. Wire it to the Select input of a Switch primitive. The true terminal will be your default starting value while the false terminal will be the feedback node.

    Felix

×
×
  • Create New...

Important Information

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