Jump to content

Class vs. Library?


Recommended Posts

Consider a LVClass that has been reduced to the point where it has no Class Private Data - its objects are stateless. Also, consider this class is not part of a class hierarchy, so inheritance does not come into play.

  1. Should I "demote" this class to a "mere" Library?
  2. Is it inelegant or misleading to leave the class as a class?
  3. If it is to remain a class, is it inelegant or misleading to have Object In and Object Out terminals on the methods?

Link to comment

Consider a LVClass that has been reduced to the point where it has no Class Private Data - its objects are stateless. Also, consider this class is not part of a class hierarchy, so inheritance does not come into play.

  1. Should I "demote" this class to a "mere" Library?
  2. Is it inelegant or misleading to leave the class as a class?
  3. If it is to remain a class, is it inelegant or misleading to have Object In and Object Out terminals on the methods?

I would say, yes, you should demote it to a mere library (although, since it already is a mere library -- because a class inherits from a library and thus fulfills the "is a" relationship -- it might be better to say "only a library"). If the situation is as you describe, then the functions are just a collection of VIs. Creating a data type and then not using it is just wasting system resources, however small they might be. And, implied in that, I would not have Object In and Object Out terminals. What would be the point? If you wired them, all you would be doing is creating false data dependencies between functions.

Now, having said all that ,before you actually build the new library, I'd pause a while and ask, "Am I absolutely certain that these functions belong together at all? What data *are* these functions operating on? Should they be packaged with whatever class represents that data?" Maybe they really are math operations or string utilities, but I don't see many programmers creating large libraries of those.

  • Like 2
Link to comment
Maybe they really are math operations or string utilities, but I don't see many programmers creating large libraries of those.

What a coincidence. I was just about to move my large collection of string functions into a library. From your comment, do you think this is a bad idea, or is it just not that common?

Link to comment

Should I "demote" this class to a "mere" Library?

FWIW, Javascript has a Math Object that is an organisation object. It is a collection of math related functions and constants - but it has no state. The Class is used purely to group the related functions (methods). Granted, that JS is considered not to be a real OO language, and they don't have something similar to Project Libraries (.lvlibs), I still thought the comparison to another language may be interesting?

Anyways, changing the namespacing would be the only thing I would worry about - i.e. if its easy to update all linking VIs (from .lvclass to .lvlib) or not.

Link to comment
Consider a LVClass that has been reduced to the point where it has no Class Private Data - its objects are stateless. Also, consider this class is not part of a class hierarchy, so inheritance does not come into play. Should I "demote" this class to a "mere" Library?

I'd say yes. OO's big three are encapsulation, instantiation, and inheritance. Since you don't have any privates (*giggle*) you don't need encapsulation (unless you want private *methods* - that's an important distinction), instantiation isn't limited to LVOOP since everything's by-val anyway) and you don't need ingeritance. That said, there's no harm in leaving it as a class - as jgcode said, namespacing could be an issue, and if you're okay with the class as it is, then I don't think you need to demote it.

Is it inelegant or misleading to leave the class as a class?

Hmmmm - that's a good question. I don't think it's an issue. I see a lvlib as a collection of related VIs, whereas a class is a collection of related VIs that act on an object - I'm assuming that you're still going to have an object, right? Like a cluster of something that passes between the VIs? If so, I'd stay with a class - it's easier to manage (the prototype of the object is in the class, not as a separate ctl file).

If it is to remain a class, is it inelegant or misleading to have Object In and Object Out terminals on the methods?

Using the work "Object" doesn't mean that it must be of type class. If it can be considered an object (eg" a file, something in the real world, a DAQ card, etc) then that's fine. That said, I usually don't use the word "object" in the names of my objects - because that's the type of the input/output. It'be like calling your numeric inputs and outputs "Numeric In" and "Numeric Out" - call them what they actually represent (eg: "Configuration File" or "DAQ Card", etc).

Link to comment

I'd say yes. OO's big three are encapsulation, instantiation, and inheritance. Since you don't have any privates (*giggle*) you don't need encapsulation (unless you want private *methods* - that's an important distinction), instantiation isn't limited to LVOOP since everything's by-val anyway) and you don't need ingeritance. That said, there's no harm in leaving it as a class - as jgcode said, namespacing could be an issue, and if you're okay with the class as it is, then I don't think you need to demote it.

Libraries allow for private methods, so the encapsulation of methods would not be a reason to keep these collections as classes.
I'm assuming that you're still going to have an object, right?
No, he's not. That's the whole "stateless" part of his original post. With no data in the cluster, and no inheritance to add any (either real data or the meta data of runtime type), there's no object instantiation at all.
Using the work word "Object" doesn't mean that it must be of type class.
I would consider it a style fail to name a terminal "Object" unless the terminal was some type of class (LV class, .NET class, VI Server class, etc).
Link to comment

One scenario for class usage:

Extension through inheritance (by the user of the class).

Special consideration: the child-classes can override methods (not only add new ones)!

Really powerful actually, if those methods are called from other methods of that class (where you'd use a protected 'statement'). Kind of hooks (just generic empty-implementation of pre- and post for all functions).

But do you need to alter your math-lib in this way? :ph34r:

Well, if this would be a product where the class user won't have access to the source, it could be useful (maybe an explanation for the JS implementation?).

Felix

Link to comment

You mentioned "demoting," implying you have already implemented the classes. In that case, I probably wouldn't bother converting them to a lvlib unless there are specific performance issues you are concerned about. If it's not buying you anything, don't spend time on it. Just make a mental note for future dev work.

Felix raised a good point. There's no inheritance now, but what about in the future? If you can envision a scenario where you might want to override a function in the library, it may be better to leave it as a class even if there's no state data associated with it.

Link to comment

I'm assuming that you're still going to have an object, right?

No, he's not. That's the whole "stateless" part of his original post. With no data in the cluster, and no inheritance to add any (either real data or the meta data of runtime type), there's no object instantiation at all.

AQ is right - no object, no state, no ref (and definitely no clusters!) passing between member VIs. To be fair, my original wording - "its objects are stateless" - is misleading. The absence of an object connotes statelessness.

Today, my original questions seem pretty asinine basic (actually, let's allow #3 to remain asinine :lol:), so maybe it would help to know where I was coming from - I had just finished revisiting an old class, hacking and slashing dozens of redundant data members and accessors, until, alas!, virtually nothing but a few stateless utility methods remained. Could I believe my eyes? Could such a substantial class structure be reduced to a wee library? Retrospectively, yep. Just needed a second set of eyes to confirm I wouldn't get snagged by some unforseen caveat (namespacing, common Icon, access scope, folder items for organizing project tree - all the goodies are still available, so .lvlib is go for launch).

Thanks for all the responses!

Link to comment
Libraries allow for private methods, so the encapsulation of methods would not be a reason to keep these collections as classes.

No, he's not. That's the whole "stateless" part of his original post. With no data in the cluster, and no inheritance to add any (either real data or the meta data of runtime type), there's no object instantiation at all.

I agree.

I would consider it a style fail to name a terminal "Object" unless the terminal was some type of class (LV class, .NET class, VI Server class, etc).

I disagree. I think of the thing on the FP and connector pane as the thing - not the type of thing. If you can use a more specific name then go for it, but if it really is an "object" in whatever field it's being applied to then I say use that name - don't avoid it just because there's a LabVIEW datatype with the same name.

Link to comment

You mentioned "demoting," implying you have already implemented the classes. In that case, I probably wouldn't bother converting them to a lvlib unless there are specific performance issues you are concerned about. If it's not buying you anything, don't spend time on it. Just make a mental note for future dev work.

This sparks an interesting idea - would anyone else see benefit in a "Convert from Class to Library" and vice-versa on the context menu of a project item? How often would you use this button? (From my experience, once, ever).

Another interesting point - the burden of relinking all library items may overwhelm the benefit of a more coherent library choice (Class or Library), but in my case the relinking burden was small so I favored coherence.

Felix raised a good point. There's no inheritance now, but what about in the future? If you can envision a scenario where you might want to override a function in the library, it may be better to leave it as a class even if there's no state data associated with it.

Again, I considered this, but with no definite or even likely plans to ever subclass, the more coherent choice is Library.

I'll close by saying that with my particular case, it looks like a .lvlib, quacks like a .lvlib, and swims like a .lvlib, so by golly I'm going to make it one. But you may find compelling design reasons to use a .lvclass when a .lvlib would suffice.

Link to comment
I disagree. I think of the thing on the FP and connector pane as the thing - not the type of thing. If you can use a more specific name then go for it, but if it really is an "object" in whatever field it's being applied to then I say use that name - don't avoid it just because there's a LabVIEW datatype with the same name.
That's the inverse of what I was arguing... you're saying "don't use Object if there's a more specific term that applies." I'm saying "If you do use Object, it better be because you're applying to a generic hierarchy."
Link to comment
I'm saying "If you do use Object, it better be because you're applying to a generic hierarchy."

No, you said:

I would consider it a style fail to name a terminal "Object" unless the terminal was some type of class (LV class, .NET class, VI Server class, etc).

Which I took to mean I couldn't use the word "object" unless it refered to a software engineering object. The generic hierachy could be anything, not necessarily a software engineering class.

Link to comment

I disagree. I think of the thing on the FP and connector pane as the thing - not the type of thing. If you can use a more specific name then go for it, but if it really is an "object" in whatever field it's being applied to then I say use that name - don't avoid it just because there's a LabVIEW datatype with the same name.

That's the inverse of what I was arguing... you're saying "don't use Object if there's a more specific term that applies." I'm saying "If you do use Object, it better be because you're applying to a generic hierarchy."

And for reference I'll quote my original question #3:

If it is to remain a class, is it inelegant or misleading to have Object In and Object Out terminals on the methods?

I can understand how the tangent of terminology arose from the way I worded this question, but I was referrering to the use of a Class Control and Class Indicator (with whatever name label) wired into the top I/O ConPane terminals, and a straight wire shorting the input to the output on the class (a straight wire connecting the two, because without any private data elements, you couldn't do anything else!). The purpose of this practice would allow the dynamic dispatch ability, but this contradicts with my other constraint of no inheritance.

If we bring inheritance and function overrides back in play, a DD input is required, whether it's misleading or not (there is argument whether the output should exist since the method is not able to modify an object that contains no elements). Asking #3 remains asinine, because the object input terminal is a requirement, not a matter of elegance or coherence.

My bad.

Link to comment

This sparks an interesting idea - would anyone else see benefit in a "Convert from Class to Library" and vice-versa on the context menu of a project item?

Personally... no. I typically know going into my design whether some chunk of related functions is going to be a class or a library.

If we bring inheritance and function overrides back in play, a DD input is required, whether it's misleading or not (there is argument whether the output should exist since the method is not able to modify an object that contains no elements). Asking #3 remains asinine, because the object input terminal is a requirement, not a matter of elegance or coherence.

I read the question as, "If I leave it as a class but don't need state data or inheritance, is it inelegant or misleading to have class terminals on the methods?"

To that I'd answer it's probably inelegant but not necessarily misleading. It could be *more* misleading to use class terminals with an object that doesn't maintain state data. A lot of it depends on the class name, the methods' names, documentation, etc. I have implemented class methods that simply pass class data through untouched as well as methods that don't have class terminals on them.

In any event, it sounds like you made the right decision.

Link to comment
I can understand how the tangent of terminology arose from the way I worded this question, but I was referrering to the use of a Class Control and Class Indicator (with whatever name label) wired into the top I/O ConPane terminals, and a straight wire shorting the input to the output on the class (a straight wire connecting the two, because without any private data elements, you couldn't do anything else!). The purpose of this practice would allow the dynamic dispatch ability, but this contradicts with my other constraint of no inheritance.

If we bring inheritance and function overrides back in play, a DD input is required, whether it's misleading or not (there is argument whether the output should exist since the method is not able to modify an object that contains no elements). Asking #3 remains asinine, because the object input terminal is a requirement, not a matter of elegance or coherence.

I read the question as, "If I leave it as a class but don't need state data or inheritance, is it inelegant or misleading to have class terminals on the methods?"

I think it's misleading - you've essentially got inputs and outputs that aren't used for anything (no state data, no inheritance), so why have them there? It would lead me to think that there's either state data (more probable) or you're forcing inheritance (less probable). Why have any inputs/outputs that aren't doing anything? Doing so suggests to others that they have a purpose. Unless, of course, you're reserving them for future fucntionality, and then you should label them so and make them "Optional" connections.

Link to comment

I think it's misleading - you've essentially got inputs and outputs that aren't used for anything (no state data, no inheritance), so why have them there?

Yeah, my response wasn't very clear. Reading it this morning it took me a few minutes to figure out what I was talking about. It must have been after the stupid hour when I posted that.

I meant to say that in the case of a stateless, non-inheritable class, leaving the class terminals in place could be more more confusing that not having any class terminals on the methods, because of the inherent expectation of class state. Using a project library is obviously preferable, but if changing the namespace introduces too much risk I wouldn't feel bad about using that particular shortcut.

FWIW, when I do have public, non-overridable class methods that don't use the class data, I'll tag the terminal "Recommended." The terminals are there simply to help keep the wiring clean. I reserve "Optional" for 'special case' inputs that are rarely needed.

I'm not sure if I've had public methods without class terminals. If so it doesn't occur often. Protected or community methods without class terminals is much more common. (And private, but that's hardly even worth parenthetically mentioning.) For example, sometimes I have a predefined set of error codes/descriptions that I want to make available to child classes. To do that I create a protected RaiseError.vi with a connector pane similar to Error Cluster From Error Code.vi. This doesn't apply to Jack's question since he specified no inheritance, but I brought it up to illustrate there are valid use cases for methods without class terminals.

Link to comment
  • 1 year later...

Two years later -- I'm reporting back that .lvlib is absolutely better than .lvclass without the concept of an "object" or "statefulness".

 

An important performance consideration -- previously unmentioned in this thread -- is that when a member of an .lvclass is statically linked to a caller, the entire .lvclass and its members and their static dependencies are loaded into memory. On the other hand, an .lvlib grants random access to its members without loading the entire library and dependencies.

 

Typically, I'm not one to promote performance micro-optimization, but this consideration is one that can easily take seconds and affect end-user experience of your application.

 

(And a few tags for the googles: Dependency management, static linkage, lazy-loading)

Link to comment
  • 3 weeks later...
Typically, I'm not one to promote performance micro-optimization, but this consideration is one that can easily take seconds and affect end-user experience of your application.

 

I'm not discounting your experience, but this comment does raise flags.  Exactly how big is your library that it would take seconds to load the entire thing?

Link to comment
I'm not discounting your experience, but this comment does raise flags.  Exactly how big is your library that it would take seconds to load the entire thing?

 

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.  :lol:

Link to comment

Okay, that lowers them a little bit, but not completely.  There are a few things I'd look into to see if there are potential issues in the design.  (Note I'm not claiming your design is bad.  Rather these things *may* indicate future trouble spots.  They are simply things to consider, not reasons to change the design.  Alternatively, if I were in a design review these are the questions I'd ask.)

 

It sounds like your functions may have a large degree of fan-out.  (Fan-out in this context = the number of unique sub vis called by the vi.)  High fan-out isn't inherently bad, but it may be indicative of a problem.  Functions with high fanout are harder to describe and understand.  Furthermore, they are more succeptable to requiring changes in the future simply by virtue of having a lot of dependencies.  (A change to any of the dependencies may necessitate a change in the caller.)

 

I take it each function in your library has a mostly unique set of static dependencies? (Otherwise the additional overhead to load the unused functions would be imperceptable.)  Given that, do these functions really belong in the same library?  Labview lacks good support for namespacing independent of library membership, so sometimes I bundle things in a library for the namespacing benefit, even if they would be better off in separate libraries.  Still, it's worthwhile to ask the question and understand why they are in the same library.

 

And to be crystal clear, whether or not you can answer these questions to my satisfaction is irrelevant.  What's important is that you can answer them to your satisfaction.

  • Like 1
Link to comment
And to be crystal clear, whether or not you can answer these questions to my satisfaction is irrelevant.  What's important is that you can answer them to your satisfaction.

 

:thumbup1:

 

"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.

  • Like 1
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
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
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.