Jump to content

JackDunaway

Members
  • Posts

    364
  • Joined

  • Last visited

  • Days Won

    40

Everything posted by JackDunaway

  1. Since subclasses inherit state from the parent, it could be desirable to ensure the parent object is constructed properly by imposing 'Must Call Parent' in addition to 'Must Implement'. (Any parent enforcing 'Must Implement' without specific functional requirements such as this is probably is better designed without the contract, allowing the subclass designer the freedom to construct the object with a constant and setters.) And 'Must Call Parent' also can ensure atomicity on construction when it's important to fully construct the object before invoking any methods on it. It sounds like the overzealous parent class designer you describe is taking contracts to an extreme, and has crossed the line of "strategically-placed contracts to make the class easy to use correctly and hard to use incorrectly". Just for clarity: do you suggest 'Private' scope should not exist, or should developers just consider 'Protected' way more often?
  2. This sounds like you need to ensure that the Math Kernel Libraries are included into your installer. Specifically, if you have downloaded the full RTE to your computer and run the self-extracting archive, it's the MSIs at the location: C:National Instruments DownloadsLabVIEW Run-Time Engine2012 (32-bit) f3ProductsMKL_2012 It's often possible to include only segments of the RTE without requiring the 200MB+ footprint; in this case, I think it's MKL for ya. Hope this helps!
  3. I tend to agree; Send.vi is an invocation of the message transport mechanism -- Messenger.lvclass -- and Construct.vi (i prefer this terminology to Write.vi) is a member of a concrete instance of Message.lvclass -- something I realized a while back after naïvely convolving the message with the messenger. This aside, i still want to impose 'Must Implement' on Construct.vi for Message.lvclass, yet it clearly cannot be 'Must Override' because message construction has a unique ConPane for each concrete message type. An object always carries 'data' -- even if it's payload-free, the type carries information about the message. There still exists benefits for requiring Construct.vi for these payload-less message objects -- even though that method effectively takes no inputs to construct.
  4. Completely agreed; this is precisely the sentiment and context in which 'Must Implement' was proposed. A good article on this topic is Make Interfaces Easy to Use Correctly and Hard to Use Incorrectly. Any of the arguments above about contracts making a library harder to use, or promoting hacks to simply fulfill a contract in order to subclass, just seem... misguided. The whole point of 'Must Implement' or 'Must Override' (or any strategic contract, such as timing requirements) is to make the library easy to use correctly and hard to use incorrectly. Consider for Actor Framework, if Message.lvclass were to define 'Must Implement' on Send.vi (as it already specifies 'Must Override' on Do.vi). Do you agree this as a good use of the contract to make subclass creation more robust and even simpler? Does this example better explain my sentiment for wanting 'Must Implement'?
  5. This was my first thought also. This is an extremely handy method for performing VI server tasks on a single VI that don't require its static hierarchy to be loaded (psstt... this method can be orders of magnitude faster than Open VI Ref since, not only does it not load static dependencies, it does not load the owning library definition or sibling members).
  6. I want to acknowledge this, and will get back with a proper response (after the mad rush to the #CLASummit). In the meantime, here's a fun article. It's an ironic allegory comparing Functional to Object-Oriented programming: http://steve-yegge.blogspot.de/2006/03/execution-in-kingdom-of-nouns.html A few great quotes: This article comes down a little hard on OOD, but I think its in good fun; his conclusion and the spirit to to embrace the merits of both OO and Functional! They're not mutually exclusive!
  7. This sounds like a different set of business and technical parameters than "i have a relatively simple test program I'm writing...I doubt this device will ever change...I don't know if with this necessary quick turnaround time it's worth writing a parent class"
  8. "this consideration is one that can easily take seconds and affect end-user experience of your application" is an oversimplification. For my app, there are numerous independently lazy-loaded application components. If all were to be loaded at once, it would take seconds. By ensuring loose coupling by eliminating static dependencies between these applications components, they are able to load independently. (It didn't always work this nicely) And I agree with the sentiment of your concern. You don't ever have to worry about dependencies until you do, and you will.
  9. This general question is well-characterized and addressed by YAGNI. My anecdotal advice, initially suspect all code as a liability, not an asset. No code is better than no code. (***Edited, to link to en.wikipedia.org/wiki/YAGNI since BBCode apparently chokes on unescaped apostrophes in URLs)
  10. Reword your question to "how big is your library and its static dependencies that it would take seconds to load the entire thing?", and perhaps we can lower those red flags.
  11. Congrats to the strong CLA showing in France, just in time for your hosting of the #CLASummit! Look forward to seeing you in Austin or in Paris in a month or two
  12. Great feedback on the example. To tweak the example, consider a base class called ProbeDisplay.lvclass whose job is to show a human-readable string for the Probe Watch Window. One could imagine there might be a lot of VIServer legwork and IDE voodoo in the base class (since it's desirable to reuse these abilities through inheritance), whereas child implementations such as ProbeDisplay.lvclass and ProbeDisplay-MyClass.lvclass would be relatively simple: serializing unique datatypes, and for the sake of illustration even sets of datatypes with multiple inputs on the ConPane if we could create some new WackassProbeExecutiveAggregator.lvclass child implementation. Now, it's clear you cannot just say "all implementations should be strings" -- now what do you do? OK, in the meantime rewriting this post, you came in with some good reference material that will take time (read, maybe days, weeks, after CLA Summits even) to chew on: In return, here's a link that has helped me, from which I recognized the name Uncle Bob (who has 3 contributions on this list): 97 Things Every Programmer Should Know And finally... It would be eternally helpful to do a post mortem on what the *right* solution would have been if you're able to share. (Or if Shaun is game, let's tackle his example in post #23) Perhaps, we decide the 'correct' solution is syntactically way too burdensome and in the architectural atmosphere, but at least we would feel less icky about the solutions as developed.
  13. No, the other way around: a child can always statically determine the ConPane of the parent (right?) -- I'm just suggesting parent does not necessitate the ConPane of an Implemented child method, like with an Overridden method. The child class must mark at least one method as Implementing the parent method. Maybe it has the same filename; not necessarily (if GUIDS in the class definition could establish this relationship). There would exist a facility for marking the child method as Implementing the parent requirement (currently, the facility for marking a method as Overriding is purely filenaming convention; if we all agree that this would be better served by GUIDS, with the ability to freely name files, we still need to develop a non-implicit facility for marking a method as Overriding a parent method!!) Can you comment on the specific example of NotifyUser.lvclass and its children? (from post #7, the tl;dr version copied below for convenience) I can't think of a better example; sorry. Consider the class, NotifyUser.lvclass which only has one method, DisplayMessage.vi, whose purpose is to display a string to a user. Later down the road, you consider it worthwhile to display other types of things to users, like Bools and Numerics, so you decide to subclass NotifyUser.lvclass since it's already got all the business logic for displaying messages. The illustration below shows this: Notice how the two implementations have separate ConPanes from the parent.... That's where Must Implement saves us -- the ability to establish a relationship between child and parent methods, without requiring them to have the same interface. Another thing to note above is that the two children are broken with the message "This VI attempts to override a static VI in an ancestor class." This is due to today's design limitation that subclasses cannot have the same method names as parent methods, except in the case of overrides. Further, note that in the middle diagram, use of the "Call Parent Method" is unrecognized. These two issues would be addressed by a "Must Implement" feature, shown below... Now, with "Must Implement", we have the ability to contractually require functionality in subclasses while maintaining the ability to extend parent class functionality, having acknowledged that Dynamic Dispatch is the incorrect tool when distinct function interfaces are desirable.
  14. Then you're totally with the consensus on this thread. So does this mean you don't use the 'Must Implement' flag? Or if you do, is it just strictly in the context of ensuring run-time polymorphism won't encounter an unimplemented method? (these questions are open to all, not just drjdpowell)
  15. For clarity, the reason this is not valid syntax is explained by this error: "This VI attempts to override a static VI in an ancestor class. An ancestor class has a VI by the same name that does not have a dynamic dispatch input terminal. Only dynamic member VIs can be overridden in child classes. To correct this, change the name of this VI so that it does not match any ancestor VI names or edit the ancestor to include a dynamic dispatch input terminal." I think you're hinting that this error and problem does not exist in non-LVOOP, 'classic' LabVIEW -- true. (And the consensus seems to be that we would like to see this relationship defined by an abstracted GUID rather than filenaming enforcement, but I digress...) Yet this "classic labview behaviour" does not exist as you suggest (in any manner other than adherence to convention), since there's no concept of the "Call Parent Method" node or an inheritance relationship defined. Call this pedantic, but those relationship/constructs/contracts do help establish intent for subclass design, and ensure certain essential parent abilities are called from the subclass.
  16. OK. Here are pictures. And since those pictures describe a problem that could probably be solved with a Generic input, look at this picture, yet instead of having two methods DisplayMessage-Bool-YesNo.vi and DisplayMessage-Bool-YeaNay.vi, consider just one method DisplayMessage-Bool.vi that has two inputs: the Bool to display, and a second Enum which defines how to localize the message (e.g., {"YeaNay", "YesNo"}) Here's the setup: when inheriting from parent classes, a subclass might redefine behavior of the parent. This redefinition of behavior may even be required by the parent, with "Must Override". Additionally, the parent may specify "Must Call Parent" in order to ensure some essential task is performed. Here's the problem: Dynamic Dispatch defines and requires an interface -- a ConPane -- a function prototype (this is clearly a requirement for run-time polymorphism). Additionally, only Dynamic Dispatch affords the contracts of Must Override and Must Call Parent. I find myself wanting to enforce these types of contracts ('Must Implement' and 'Must Call Parent'), yet with a separate ConPane for the concrete implementation. Here's something that I've observed many smart people do (and done myself): Put a variant (or another stringly-typed parameter) on the ConPane of a Dynamic Dispatch VI because strong-typing was in some manner breaking their inheritance mojo. Or, a more 'sophisticated' approach is to replace this input with an object. The problem is now 'fixed' on the Dynamic Dispatch method, but pushed into another location (e.g., the construction of this object and/or the handling of this object inside the method), *and* now with a larger codebase. (*** EDIT *** One additional code smell is the presence of an "unused input") Here's where everyone keeps getting hung up on this thread: Dynamic Dispatch affords the ability of run-time polymorphism. I'm specifically stating that sometimes it's desirable forgo this ability in favor of a more descriptive concrete API -- defining concrete methods with more specific ConPanes and Function names -- yet without losing the ability to define a linkage between parent and child abilities. It bugs me to see dozens of Do.vi functions in a big LabVIEW app implementing the Command Pattern, or in the Head First Design Patterns book see the Animal method makeNoise() abound instead of quack() or moo() or bark(). I totally understand that many application domains require run-time polymorphism (including the Command Pattern) or dependency injection (including not knowing which Animals might makeNoise() in an app) -- but for the many application domains that don't have these requirements, concrete implementations tend to be far easier to implement and maintain. It's much easier to work with a composition of one cow and one duck than anArbitrarySetOfAnimalsWhoImplementBarnyardInterfaces[], both as a human with finite cranial horsepower, and with a system whose types can be checked with static analysis rather than probing around run-time errors. Here's a request: Please don't quote me as an arguing against Dynamic Dispatch or interfaces or inheritance or generic programming or... Each of these concepts has merits, and application domains where they shine. Don't misquote me saying static composition is better than dependency injection, or Implemented methods categorically allow more coherent APIs than Overridden methods. (I love the opportunities to work on systems that require these higher-level abstractions.) But what you can quote is my pragmatic desire to decouple some components of our beloved language in order to allow random access to each of its merits -- in this case, Inheritance of abilities and Implementation contracts, yet without Run-Time Polymorphism and specified interfaces. Here's what I'm proposing: Right now 'Must Override' and 'Must call parent' come with the requisite usage of Dynamic Dispatch and a specified interface. Let's change the name of 'Must Override' to 'Must Implement', then allow this and 'Must call parent' as attributes of any given class member, not just Dynamic Dispatch methods. Here's where you come in: Is there a better solution to the problem? Is the presence of the perceived problem (wanting a more descriptive API for concrete implementations and a language-feature for linking implementations to parent behaviors) indicative of a bad programming practice on my part? What other languages address this issue? It's nearly inconceivable to assume this issue has not been either: 1) already implemented in a language or 2) characterized then rejected as an anti-pattern -- so I'm eagerly awaiting links to answers if this sounds familiar to anyone!
  17. Yes, functional; definitely not imperative/procedural, which is roughly on the same spectrum (yet in a less-desirable direction) as OO. But functional is orthogonal to this spectrum, and promotes at least one tenet that typically competes with imperative and object-oriented programming: minimizing mutable state, and ideally statelessness. An OO approach to the NotifyUser.lvclass example might suggest setting property SetMessage.vi and then invoking DisplayMessage.vi, in the meantime storing Message in the class private data. Functional Programming promotes statelessness, so we would strive to implement Display Message with a ConPane with the complete set of parameters necessary to perform the action. Not coincidentally, this style marries beautifully with event-driven programming. For this reason, I want child class functionality to implement and "override" (I use the term "override" loosely) with different ConPanes than the parent. And I'm clearly stating that this request does not jive with OO purism, so I completely agree with (yet reject as a argument against "Must Implement: ) all sentiments in this thread that "Must Implement" does not adhere to the interface as defined by the parent. Fair enough; but we can predict some. Likewise, I rarely use these either. (yet, mainly because of the limitations described in this thread!! e.g., wanting unique ConPanes for child Implementations). Your second sentence above is perhaps a better verbalization of my sentiments; a subclass who Implements a parent, yet does not Implement a certain method that would be best marked as "Must Implement" (yet not Dynamic Dispatch) is effectively breaking the functionality of the class. The reason the class designer would flag "Must Implement" goes beyond vacuous expectations of what ought a child class to do; it's an indication that "something is broken with this inheritance unless this obligation is being fulfilled". We would probably agree that if the class designer uses this contract much beyond ensuring things don't "break", that the contract is probably being overused and/or misused. This crusade is for a desire to minimize mutable state. Reduce asynchronization between an object's cached state with the subject's physical state. Reduce cognitive overhead of understanding systems (i.e., reading code). Increase opportunities for parallelizability. These are my perceived benefits of functional programming over imperative programming, and why a healthy dose thrown is thrown in with the benefits of LVOOP. It won't necessarily relieve the issues described in this thread; but generally agreed that it will relieve other issues, and is a much welcome improvement. 100% agreed, and you're not on a limb. Consider my calling it a 'compromise' a friendly euphemism for 'mortal sin' This is a new, interesting discussion altogether, but not the solution. It breaks down simply when you want different numbers of parameters on the ConPane for child implementations. (Whereas, genericity describes unknown type for any one parameter) That being said, genericity might alleviate (even, significantly) some of the root problems here.
  18. No -- again, I see *no* negative side effects, no yellow warnings, no linker/compiler errors... let's take this offline, and I can report back to this thread if we learn anything of interest.
  19. So, there's definitely something wrong here. My sanity says 'thanks' for this info. Attached is a snippet that shows just the first few hundred 'issues' -- feel free to run it yourself on your own project; the values from my run are set as default data on the indicator. And again, 'issues' notwithstanding, nothing in the project is broken.
  20. Reviving a bit of an old thread... So when I click on the root project item and invoke "Find Items Incorrectly Claimed by a Library", it returns a list of hundreds of VIs, nearly all of which are in vi.lib. But a few dozen were in my codebase, and so I fixed them; fair enough. (The trivial fix is to manually drag offending members out of the library and then back in; a bit tedious for a few dozen items, but it could be automated through VI Server) Just trying to learn more about this, so... What is the benefit of resolving this 'condition'? What are negative consequences of not resolving this non-reciprocation? I have yet to run across any concrete problems caused by this condition, other than an icky feeling. (Case in point: vi.lib ships with many library members who don't acknowledge their ownership, apparently without problems)
  21. Great tip! Hearty +1! In the past, I've brokered resize events from the parent into the children using the application's interprocess messaging -- using Pane resize events will simplify this :-)
  22. I'm not necessarily looking for a resolution of a problem; rather just comparing notes to what seemed like a similar scoping construct -- mine was one of those ideas that has never graduated past a 30sec stream-of-consciousness dump onto the LV IdEx Google Task list :-) It would be interesting to hear more about the specific context in which you originally envisaged this feature.
  23. Here's a direct copy-and-paste from a note I wrote a couple years ago on the "potential IdEx Candidates" list: The gist is to truly scope data to the BD of a single VI, discouraging abuse of exposing data across a SubVI (or even structure) boundary where it does not belong. Is this idea kinda like what you're proposing? Or an alternate solution to solve the same problem? (One obvious difference: this declaration would be held at the VI level, not the object level)
  24. Can you give a concrete example? For this new feature, do you envision restricting fields to exactly 1 class method, or a defined subset of class methods?
  25. Not really a joke -- some branches of design (Metro, notably) actually are headed toward flat and rectangular, like the current rasterization of LabVIEW -- didn't mean to sound flippant. Maybe you'll find ways to accomplish your goals using the Icon API directly from <vi.lib>LabVIEW Icon API; or perhaps with the LV2012 Icon Editor source; hope this is helpful.
×
×
  • Create New...

Important Information

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