Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 10/02/2009 in all areas

  1. Here's an updated version of the Interface Framework. Changelist: Refactored out the dependency on the Collection Framework. The Interface Framework is now self sufficient. Renamed "Interface" class to "IUnknown" to help avoid confusion. Renamed "InterfaceCollection" class to "InterfaceBag," since it no longer derives from the Collection Framework. IUnknown now contains an Interfaceable object rather than a DVR to an Interfaceable object. (Thanks kugr!) Removed friend relationship between Baby and ISleepableBaby. (Thanks SciWare!) Added several UML diagrams to the documentation. (Use Star UML to view the core document.) Still trying to figure out a better name for the Interfaceable class. I'm open to suggestions... A few other minor things, but I've forgotten what they were. A couple notes on terminology: In COM and .Net when an object supports a given Interface it is said that it implements the Interface. This makes sense in those languages; the code that executes when an Interface method is called is implemented directly in the class. That terminology doesn't make sense in this framework since each Interface is implemented in its own class rather than as part of the core code of the target class. I prefer to say an object exposes an Interface. Sometimes I'll also say an object has an Interface or supports an Interface, or an Interface is implemented for an object. I'll typically capitalize the word "Interface" when referring to the interface classes and objects described in this framework. I'll leave it lower case when using the word "interface" in the general meaning. "Interfaceable" with a capital 'I' refers to the proper noun, the Interfaceable class. When it is not capitalized, "interfaceable" is an adjective describing a class or object that derives from the Interfaceable class. These are the main diagrams I've included in the documentation. Hopefully they help explain how the framework interacts with the classes that are built on it. Other than vi context help I have not yet developed documentation on steps for class developers to take to implement classes based on the framework. In this framework any class that exposes an Interface must inherit directly or indirectly from the Interfaceable class. All Interfaces must inherit directly or indirectly from IUnknown. InterfaceBag is simply a helper object that holds all the Interfaces an interfaceable object supports. This diagram shows the relationship between the framework and the three classes (at minimum) that must be implemented when using the framework. Interfaces are designed to be reused so usually the Interface already exists, leaving the class developer with only two classes to implement. Classes that inherit from Interfaceable override the _GetInterfaces method, returning an InterfaceBag which contains all the concrete Interfaces the class exposes. How the InterfaceBag gets populated with concrete Interfaces is up to the class developer. Two common methods are by initializing the InterfaceBag in a Create method or by adding the concrete Interfaces to the InterfaceBag at design time and making those values the default. This shows the implementation of the Baby class in the attached example. It has one added complexity over the generic implementation; the Baby class has made the ISleepableBaby class a friend, which allows Baby to expose methods that are only accessable through the ISleepable Interface. This diagram shows the sequence of calls that take place when a class user calls the GetInterface method on an interfaceable object. Note that the class developer only needs to implement the _GetInterfaces method in their class. The rest of the work is handled by the framework. Here is a sequence of calls made when a class user calls a method exposed by an Interface. As expected, the class developer has slightly more work here in deciding exactly how the Interface method applies to this specific interfaceable class. ------------------------------------- What can you do with Interfaces? That's a little like asking what can you do with Play-doh. Undoubtedly there are lots of ways to use them I haven't though of. Here are a few ideas I've been bouncing around: - I really like Kurt's Active Object pattern. It might be worthwhile to create an IActiveObject interface. Still thinking about use cases on this... - I also like using the Observer pattern to separate program logic from the UI. Maybe an IObservable interface? (Though Event Refnums being strictly typed presents some difficulties.) - IPublisher? ISubscriber? - .Net documentation also provides some hints on potential uses. ISerializable? IPersistToFile? - Or getting back to what started me on this journey in the first place, IMeasureVoltage? IMeasureCurrent? [Edit Aug 3, 2010 - Removed pre-release version. Get current version from the Code Repository.]
    1 point
  2. There are interfaces that have methods that are combinations of several other methods on the interface. An interface might expose a DoThis and a DoThat method and a third method that takes a boolean parameter called DoOneOrTheOther. Just an example. In that case the interface still doesn't have any knowledge of the particular class, but it does provide an algorithm as part of itself that takes advantage of the rest of the interface.Which brings me to another thought I've been having about interfaces... the possibility that an interface could declare a private method and expose a public method that uses that private method as part of an algorithm. There are cases where I, as the person implementing the interface, need to write some function that the class must expose in order to plug into some algorithm, but the function itself is one that should never be called except by the algorithm. I know... I'm questioning all sorts of basic assumptions about "what constitutes an interface." But that's my job as a language designer. Just because it works like XYZ in C# or Java doesn't mean that it is how it should be implemented, either in languages in general or in LV specifically. This is a topic on which I'll be playing for a long while yet.
    1 point
  3. In my experience the terms "reference" and "pointer" are often used interchangably. How are you differentiating the terms? They both essentially do the same thing--they refer to a location in memory that contains either the data of interest or the next memory location in the chain. Having parallel wires refer to the same piece of memory is done all the time with refnums, be it named queues, events, fp controls, etc, so it's obviously possible. Branching a DVR results in two parallel wires referring to the same piece of memory. Is this a limitation of dataflow languages in general or specific to Labview's implementation. Obviously there are still aspects of dataflow I don't fully understand. Data on the parallel by-value wire has to exist somewhere in memory. It don't get why a pointer to that memory location would not be meaningful. It would violate the principle of data flow, but there are lots of things within Labview that do that already. --------- Many Hours Later ----------- I had to look at this for a long time. When I first read it I envisioned all sorts of weird schemes under the hood that used the upstream prim to modify a value after it has been sent downstream. Here's a summary of the conversation I had with your alter-ego, Evil AQ (pronounced "evil-ack"), in my head. Evil AQ explained a lot of things to me, but I question his accuracy... you know, what with him being a figment of my imagination and all. (Note: My conversations with Evil AQ tend to be rather caustic.) Me: "Huh? The prim that created the value is what actually performs operations on the value downstream? That implies that rather than the data being passed around between prims, the data remains with the orignating prim and downstream prims are passed to it. How... odd. That seems kind of like functional programming. I thought you used C++ under the hood." Evil AQ: "No you dolt. That wasn't a comment about perpetually persistent primitives. Look, when have you ever seen a value on a wire change? Me: "I see it all the time. Wire an integer through an increment function inside a while loop. The value on the wire changes with each iteration." EAQ: "Let me rephrase... when have you ever seen a value on a wire change without that section of code executing again? Me: "Well, the value on the wire has changed after going through the increment node." EAQ: "Uh uh. That's a different wire. Another rephrase... when have you ever seen a value on any single wire, defined as all branches starting at the source terminal and ending at each destination terminal, change without that section of code executing again? Me: "Never. Duh." EAQ: "It's good to know you're not a complete maroon. This would be tougher to explain if I were restricted to finger paints and monosyllabic words." Me: "Monobillasic... monosymbolic... monosy... what?" EAQ: "Never mind. What would happen if you had a raw pointer to a value on a wire?" Me: "I could have Interfaces!" EAQ: "Slow down there Flash. Think about this for a minute. What would happen to the value on the wire?" Me: "Ohhhh... it would change." EAQ: "Very good. You pumping a full 100 Watts through that brain or is your dimmer switch turned up a little too high?" Me: "What about control refnums? They change values." EAQ: "There's a reason they're called 'control' refnums. They refer to controls, not wires. Control values can change. Wire values cannot." Me: "Oh. Right. Well queues can change the values of items that exist somewhere in memory. What about them?" EAQ: "Yes, but they are changing the value of an item the queue refnum refers to. They are not changing the value of the queue refnum itself, which is what actually exists on the wire." Me: "I see. But in reality by-val wires don't contain the data itself, do they? If they did memory allocations would take place at the moment the wire branches and I've know that's not right." EAQ: "Correct, wires do not contain the actual data." Me: "It actually refers to data that resides elsewhere in memory, right?" EAQ: "Sort of correct. Wires don't refer to a piece of data so much as they refer to a specific terminal on VIs and primitives. A terminal** is essentially something that can define the values of a piece of data, such as a control, indicator, constant, etc. and includes input and output terminals to prims." (**Evil AQ didn't know the correct terminology for this so he used the word 'terminal.' Luckily I knew what he meant.) Me: "So shouldn't it be possible to create a refnum that simply refers to the same memory location that a wire does? Ha!" EAQ: "Well yes, but it won't work in the way you're thinking. Try looking at it this way... by val data exists only in terminals. Wires are simply a graphical representation of how the terminals are mapped to each other. Ostensibly every time data "flows" across a wire a data copy is made and placed in the memory location that represents the destination terminal. While in principle you could have a refnum that refers to the same data the wire 'refers' to, effectively it would be just like a value property node for one of the terminals. (It doesn't matter which one, since they all contain the same data values.) That scheme would consume LOTS of memory, so the Labview compiler is smart enough reuse memory when it can. For example, since all the terminals a wire connects to must contain the same data values after executing, the memory locations that are represented by the terminals are actually pointers that refer to a single piece of data. Sometimes the memory location of that data can be reused by other terminals further downstream. Sometimes it can't. Ironically, obtaining a reference to that memory location is one way to guarantee it can not be reused." Me: "Really?" EAQ: "Well yeah. You're referencing the value in the terminal, which doesn't change until that section of code executes again. If downstream operations change the value a new copy must be made to avoid corrupting the old copy, which you have a reference to." Me: "I get it now. Thanks Evil AQ. You're the greatest." EAQ: "You sound like my mother. Now beat it punk, I'm trying to sleep." So did Evil AQ do a decent job of explaining things to me?
    1 point
  4. [speaking purely as a developer myself, not speaking in any way for NI for this post.] Oh, yeah, I've made this mistake before. Not with LV... another tool. In my case it was choosing to use Oracle (licensed to my employer) instead of MySQL (freeware tool). I left that employer and my tools were dead -- I had copies of all my databases, but no way to use them. In a case where I made the right decision, my copy of CorelDraw is mine, paid for out of my pocket, even though Iuse it frequently at work. NI probably would've bought Corel for me once I showed a need for it in my work, but all of my personal graphics projects are in Corel and I don't want to lose access to them if I everleave NI. Essentially, bsvingen faces a rather classic problem. He used a license registered to entity A to produce software for entity B, and now without access to person A's license, he's stuck without the ability to continue working on the project for entity B. The solution is not, IMHO, to say, "Never use the licensed tool, always use the free tool." The actual answer is, "Never start a project using tools that have licenses that differ from the owner of the project." In other words, if the project is for entity B, don't use entity A's licenses to develop it. So if this is my personal project, I need a personal license, rather than relying upon my office license, otherwise I end up one day not having access to that license. Is a personal copy of LV cheap? Heck no. But neither is a personal copy of a lot of cool software. I'd like to say, "use LV for everything it is appropriate for." But I'd also like to get a paycheck every couple weeks, which means LV costs money, which means "use LV if you can afford to use it in all the times where it is appropriate". It'd be nice if it were down around $250, like Visual Studio, but we don't have anywhere near the volume that MS does to be able to make back our expenses at that low a price. I don't think the licensing takes away from the *language* being a general purpose programming language -- by which I mean, if you have access to LV, you can use LV for any programming project, effectively and efficiently, to the same degree as any other programming language. Every language has its strengths and weaknesses, and LV's particular set of trade-offs are no worse than a lot of other languages. But I do agree with bsvingen that the licensing takes away from the development tool being a general purpose development tool -- by which I mean not all developers will have access to it. That's really what's at the heart of the open source/free software arguments, but while I definitely use open source stuff, and I've contributed back to a few open source projects, and I wrote a lot of shareware back in history, I don't think anyone has figured out how to pay a staff of programmers while charging nothing for the software.
    1 point
×
×
  • Create New...

Important Information

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