Jump to content

Components vs. Functions (newbie warning)


Recommended Posts

Hi all,

A million years ago I went straight from C programming to LV 2.5 and have rarely, if ever, looked back. So, IOW, I missed the whole Object Oriented paradigm shift.

I have at various times looked at OOP and tried to figure out how to apply it to my coding. I was usually in the midst of some huge application, tho, and backtracking was impo$ible.

But here I am at the beginning of a (not so) huge project and I thought I'd give it a try again. I've gone thru as many of the links listed here and NI that I can find, and many of the posts to this forum. I'm stuck at a fundamental issue of OOP being about programming "components" as opposed to "functions".

I understand the Climate Control example. Its got clearly defined components in its heater/cooler/fan/etc. Ditto for the "dog" class examples. But what if the only tangible component of your system is a computer?

For example, one of my current projects is a data recorder (to vastly over simplify it). I need to set up a connection to a data server, read data, save data, manipulate data in different ways, and then save the results. I would usually write this as a series of modules that perform those functions. Is my only class "Data Recorder" and all of those functions methods of that class?

Over the years I have written tons of code that basically does just this. I can't imagine it all falls under 1 class. It seems rather ridiculous to have an Ethernet Card class and a CPU class and a RAM class, and a Hard Drive Class, but that's the only other way of looking at this I can come up with.

Am I making this too hard?

Cat

Link to comment

QUOTE (Cat @ Apr 21 2008, 01:45 PM)

... Am I making this too hard? ...

... I'm stuck at a fundamental issue of OOP being about programming "components" as opposed to "functions" ...

Cat

I will be paying close attention to this thread. I hope we get a good dialog going. I, too have been trying to understand OOP when it comes to LV. And I, too have spent hours on NI, LAVA, Googling and reading about it. I'm working with OO programs every day now at work and really need to get a handle on it.

We are making this hard. Besides programming components and functions and methods there are issues regarding writing to classes by reference or by value.

I can grasp the ideas behind OO programming fairly easily. But we have way too many LV implementations floating around. LVOOP, OpenGoop, Endevo (same thing?), numerous other 3rd-party OO applications, one that I am working on right now. And almost all of the lower-level vi's/repositories are "password protected" making it difficult to see the nuts and bolts.

You are in a good position Cat. Starting a new application from scratch and thinking of an OO design. I can't think of a better way to learn. But as much as I love OpenG stuff I think I would stick with NI's LVOOP. If forced to make a choice, just out of sheer survival I would go with NI first. I can pick up the others later.

Good luck. Keep us posted.

Link to comment

QUOTE (PaulG. @ Apr 21 2008, 01:27 PM)

I will be paying close attention to this thread. I hope we get a good dialog going.

I'll cast my hat into the ring as well. I've had a void to fill ever since getting through all those NI courses just in time for LVOOP to be released. :(

I've worked with C++ OOP, which seemed almost intutive to pick up. I agree that there seems to be too many different implementations out there (which is probably to be expected at this point since OOP is relatively new to LabVIEW). I also would like to at least be very, very familiar with the standard installation's version as priority one, so that I can make an informed decision about which direction I'm going to go with this.

Link to comment

QUOTE (Cat @ Apr 21 2008, 01:45 PM)

But here I am at the beginning of a (not so) huge project and I thought I'd give it a try again. I've gone thru as many of the links listed here and NI that I can find, and many of the posts to this forum. I'm stuck at a fundamental issue of OOP being about programming "components" as opposed to "functions".

Am I making this too hard?

I had a lot of trouble with OOP at first, partially because (in my opinion) the NI examples tend to not be very "real world". It's nice that animals are composed of cats and dogs and sheep, but how do I abstract that to my problem? Of course, this is an issue with describing any feature for a wide audience.

I have two systems where I've implemented an object-like structure. The first is a test stand where the error handling is an object, the database access is an object, the test sequencer is an object, etc. The objects, in this case, are subsystems of the large application. I was explaining the code to a layman today and he descibed the structure as an API for a [Windows] service.

The second system I have with objects is a test plan editor. The editor can load and edit multiple test plans at a time; think similar to the way Microsoft Office applications work. A "test plan" object makes it much easier to deal with data than a 1D array of a cluster of.... This also allowed me to create "properties and methods" of the test plan object to perform all of the creation, opening, and editing into individual VIs; readability and maintenance was much easier with this structure.

The by-reference object is more similar to C++ than the by-value object; I find the by-reference object more useful to me (more-so with the first implementation). I've played with the by-value object a bit and can see where I may have use for it in the future (as in the second implementation). As with any tool, though, it only makes sense to apply it where appropriate (using a screwdriver for a hammer is not advised).

Link to comment

You shouldn't confuse the various GOOP frameworks (which work by-ref) with the native LVOOP, as they are very different from each other.

In general, most GOOP toolkits work like this: When you call a constructor you get a reference to a new object. The class methods accept this reference and use it to manipulate the data in a shared cluster. The GOOP framework is responsible for making sure that calling methods from two different places in the code does not cause race condition when working with the shared cluster.

The actual methods used by the GOOP tools vary (CINs, reentrant LV2 globs, single-element queues, etc.), but the high level concept is the same and so doesn't require understanding how the framework actually works. That said, most free ones have the source code open (e.g. OpenGOOP, dqGOOP, Sciware GOOP). Most of them don't support inheritance and can't force encapsulation.

LVOOP is much newer and works completely differently. It's by-value, integrated into the environment, supports inheritance and enforces encapsulation. Understanding when to use it should be important.

Cat, which classes you create depends on your system, but it is definitely possible you will only want one class (or no classes at all). A couple of examples of classes which might be relevant in your situation: Maybe the data server can have all kinds of features (e.g. TCP connection, Serial connection, DLL connection, Data from a file etc.) and so you might want to make it into a few classes. Maybe you have different kinds of data and you want to make each kind of data into a class, all of which inherit from a common data class.

Link to comment

QUOTE (PaulG. @ Apr 22 2008, 07:26 PM)

But it still doesn't help me with all the LV OOP applications that deal only with references - which is all of them. :(

There are wrappers to allow LVOOP to work by-ref. One example ships with LV. Another is Endevo's GOOP which has some OpenG classes. I haven't used any of them (I'm only getting into 8.x now myself) so I can't comment on how they work.

Link to comment

QUOTE (Cat @ Apr 21 2008, 12:45 PM)

For example, one of my current projects is a data recorder (to vastly over simplify it). I need to set up a connection to a data server, read data, save data, manipulate data in different ways, and then save the results. I would usually write this as a series of modules that perform those functions. Is my only class "Data Recorder" and all of those functions methods of that class?

I imagine a lot of that is dependent on just how much effort you want to put into making stuff applicable to reuse. Just as you could put all your code into one gigantic top-level VI, you could put all this stuff into one class. Or you could break it up into subVIs which make the code easier to read and enable reuse, just as you can create multiple classes.

For example, when you save data, don't think of it as saving data. Think of it as sending your data to some external sink. In your case, that sink is a file being written to disk. But it could also be a chart. You could have a top-level Saver class and FileSaver and ChartSaver subclasses. But do you want to go to the work of making the top-level class and then a child class for this one project you're working on?

Java, for example, has the OutputStream class that sends data elsewhere. You can have a FileOutputStream for writing to a file, or a PipedOutputStream for sending to a different thread.

I never really thought of this before, but it just seems really odd to me that NI didn't release any implementations of anything in LVOOP. That makes it really hard to build a LVOOP class because you have nothing to build on top of. Again, look at Java. There's a huge library of classes that, if you can't find one that does exactly what you want, you can subclass and add functionality.

Link to comment

QUOTE (eaolson @ Apr 22 2008, 07:48 PM)

it just seems really odd to me that NI didn't release any implementations of anything in LVOOP.

LVOOP is still relatively new. It's only been around for a couple of minor versions, so it's still in an early stage. If you're interested, you can find all kinds of examples of stuff NI folks did which could be used. A couple of examples include the LVOOP based error handler AQ posted and the LVOOP based getting started window which Christina posted on her blog (and which made its way into 8.5).

Link to comment

QUOTE (Cat @ Apr 21 2008, 05:45 PM)

For example, one of my current projects is a data recorder (to vastly over simplify it). I need to set up a connection to a data server, read data, save data, manipulate data in different ways, and then save the results. I would usually write this as a series of modules that perform those functions. Is my only class "Data Recorder" and all of those functions methods of that class?

Over the years I have written tons of code that basically does just this. I can't imagine it all falls under 1 class. It seems rather ridiculous to have an Ethernet Card class and a CPU class and a RAM class, and a Hard Drive Class, but that's the only other way of looking at this I can come up with.

Am I making this too hard?

I can't pretend to be an OOP guru - lI too have spent most of my programming time working in non-OOP languages (and a lot of that in LabVIEW at that). Because of this, I've never really done much with the various GOOP frameworks, on the otherhand I have found that I'm gradually shifting more of my coding over to LVOOP where the by-value encapsulation of data and inheritance seem to work reasonably naturally to my mind.

Where I've found myself writing LVOOP classes in measurement code has been in two distinct ways:

- I've converted a lot of my instrument drivers to a LVOOP heirarchy - I have a base Instrument class that providess methods like Initialise and Close and protected methods like Wrtie-Read, and some utilitiy methods for doing things like reading data from SCPI compliant nstruments. On top of this I layer classes that define generic instruments e.g. source-meter, temperature controller, lockin - these just define an interface but don't implement any actual code themselves. Finally, I write classes for each instrument that implements one of the generic instrument classes - this my measurement program can be written in terms of "Source-Meter" class and its methods, but then switching between e.g. Keiithley 24xx and 26xx source meters is just a question of sending the right child class down the wire. This makes adding new instruments to the code base really very easy...

- Most of the measurements that we do boil down to "measure y=f(x,a1,a2,...an), extract some parameters, adjust a1,a2,...an, repeat. So I've started to write classes heirarchies that implement this - I have a base X-Y class which I then create child classes for doing e.g. I-V measurements with a source meter, G-V measurements with a current source and a lockin - again adding a new measurment just means implementing a new child class and common methods like saving data, plotting data are defined only in the parent class. Similiarly I'm doing classes to adjust the a1,a2 parameters - which are typically temperatures, magnetic fields, gate voltages.

None of this is rocket science, and I keep discovering that I've made some error in my design of the class hierarchy, but I think it gives a flavour of how OOP (and for me LVOOP in particular) can be made to work in "real-world" applications. As for the by-ref vs by-value debate - I can see that for experienced C++ programmers by-ref is the only way to go, I suspect for LabVIEW developers who have never done any OOP, by-value seems more natural modulo those times when you have a class representing a physical thing that you need to work with in parallel loops, when by-ref is the only sensible way. It's certainly not worth a jihad :)

Link to comment

QUOTE (Yen @ Apr 22 2008, 01:43 PM)

There are wrappers to allow LVOOP to work by-ref. One example ships with LV. Another is Endevo's GOOP which has some OpenG classes. I haven't used any of them (I'm only getting into 8.x now myself) so I can't comment on how they work.

But would they need to be created as LV "Classes"? If so, they would not work in RT - which is one of the reasons I don't want to waste a lot of time learning LV Classes if I can learn something else that is a little more flexible. All the OOP jargon fit together very well for me in the LVOOP Classes presentation, but by reference seems to be almost a cross-language industry "standard" if there is such a thing. Anyone want to comment?

Link to comment

QUOTE (PaulG. @ Apr 22 2008, 10:54 PM)

But would they need to be created as LV "Classes"? If so, they would not work in RT

Yes to both.

QUOTE

All the OOP jargon fit together very well for me in the LVOOP Classes presentation, but by reference seems to be almost a cross-language industry "standard" if there is such a thing.

By-ref is very useful, but that does not mean that by-val is not. The key is in understanding that the use cases for LVOOP might not be the same use cases that you're used to - there are use cases which do not require access to the same instance from multiple places in the code.

If you haven't read it yet, there is an NI document called "the decisions behind the design" which goes into this in some detail. There are also quite a few threads here.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

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