03-09-2024 11:13 PM - edited 03-09-2024 11:18 PM
Hi All,
For everyone who is an avid LabVIEW Object Oriented Developers, I would like to share my LV_Abstract Libraries.
LV_Abstract is a set of Abstract classes for almost all LabVIEW data types including:
Boolean
String
Single
Double
Extended
Complex Single
Complex Double
Complex Extended
I8
I16
I32
I64
U8
U16
U32
U64
Time Stamp
Variant
Waveform
Plus a set of Constants, Simple Variables, Basic Maths, Logic, Comparisons and Conversion Classes. Each with a matching polymorphic VI to simplify usage.
I started creating and using basic abstract types (String, Boolean and Numeric) in my OO code and wished NI provided abstract classes for all of their types, like other OO languages. So with Inspiration from Small Talk, Java and Python I created my/our own abstract type class.
So far I have created 466 classes and 2043 VI's for this library, but there is much more to do.
So far I plan to add is some form of collections/vectors/.. classes, more math classes, more String, Variant, Waveform Function classes and 100% coverage of the unit tests.
The basic Type Hierarchy
One of a number of Class VI hierarchy Tree's
All this code is made Open Source under a GPL-3.0 License.
The Github Project is here:
https://github.com/timstreeter/LV_Abstract
Released VIP's are available here:
https://github.com/timstreeter/LV_Abstract/releases
I have submitted them to be available via the VIPM but they haven't been released yet.
Thank you for your time reading this and enjoy this code.
And if you want to help you can join me on GitHub
Tim
03-10-2024 12:51 AM
It is up now on VIPM
03-10-2024 05:00 AM - edited 03-10-2024 05:06 AM
An interesting effort but I’m a bit concerned about performance. Part of Python’’s rather slow execution is its “everything is an object” paradigms. jave uses for exactly that reason fundamental types for the standard data types and only provides minimal object semantics for them.in the case of Python it has been somewhat circumvented by creating libraries such as numpy, which implement the heavy lifting in an external shared library written in C and providing object interfaces for the entire collection of values but it’s a lot of effort.
Last but not least maintaining a library of 500 different classes does sound like a nightmare to me. How do you handle changes that spread through half of your classes when you need to extend the system somehow for a new feature? Making such changes backwards compatible frequently turns into inelegant architecture, but incompatible changes make-the library very difficult to use for others, and yourself too.
Also, while 20 and even 50MB LabVIEW and other executables are not an exception anymore, it’s still huge. And an application using these classes throughout will quickly grow exponentially when starting to write real world applications.
03-11-2024 04:04 AM
Hi Rolf,
To answer your critiques:
Performance. This is a critique of all OO languages including LabVIEW. I am not making any special performance claims here. I have included a very basic math library that extends this API it is not a numpty replacement.
Number of Classes. Sure there are a lot of classes, but this is not a complicated library. To make a function polymorphic you need a copy for each of the types it supports, so there are a lot of very simple classes. To create a lot of simple classes I made one good class of one type and then used scripting to make copies for all of the other types. I then used unit testing to provide test coverage.
The size of the built application. Have you written and built an application using these libraries or just making broad generalisations? Sure size can be an issue, but that is why I didn't put the classes in a library, so when you add a class it may add others but not the whole lot.
I agree OO should not be used for everything, it's not the fastest end it can add to the size of the applications, but OO can be used to scale applications and to promote code reuse.
All I am providing is a free tool to extend LabVIEW's capabilities, you can choose to use it or not, until you understand and use them as intended then your criticisms are not valid.
Tim
03-11-2024 04:45 AM
Hello
Nice job. But what are the benefits of using Objets and not native types for you? In which cases you see a big value?
03-11-2024 06:46 AM
How about support for enums (U8, U16, U32, U64)?
Math on enums is quite interesting. To\From string gets more complicated, as storing as integer looses the text, storing the text looses the value. Storing both could cause conflict... It's really up to the user to decide.
How about clusters and arrays? That would add value, although it requires recursion and type\size checking.
Esp. for a formula\expression library, support for arrays can have huge performance impact.
03-12-2024 02:10 AM
The most common use of this type of abstraction layer is as the basis of an Hardware Abstraction Layer (HAL). A function can then be written with a "Read" and "Write" methods to/from IO that hasn't be defined until run-time. What I have done is to extend that concept to include some math and logic that can be applied to the IO or variable before passed into the function.
This a quick bit of code I created to demo the capability.
Not exactly useful but it illustrates the concepts, the read methods inside the loop are updating to the values defines outside the loop.
03-12-2024 02:34 AM - edited 03-12-2024 02:35 AM
Supporting enum's is way too difficult. The code to make ingress native NI enum is difficult but not impossible and uses variant tricks to access the enum strings at runtime, but getting the read method to output the same native enum type would involve scripting.
One option would be to use either and unsigned integer or variant abstract type and cast them to the matching enum when it needs to be read.
Alternatively you can define what you want the enum to do and make a class that extents the unsigned integer types but has a method that out put the enum string.
Clusters and Arrays. The library supports variants, which can be used to pass anything you want as long as you know the original type when you read it out.
I did am thinking of supporting an 1 and 2 dimension native array for each type, but for each dimension supported would multiply the number of supporting classes.
If you are thinking of having array objects that abstract and array and have methods to work on the array, this is a possiblity. There are many ways to do this and I am open to suggestions here.
03-12-2024 06:26 AM
@LV_Tim wrote:
Supporting enum's is way too difficult. The code to make ingress native NI enum is difficult but not impossible and uses variant tricks to access the enum strings at runtime, but getting the read method to output the same native enum type would involve scripting.
One option would be to use either and unsigned integer or variant abstract type and cast them to the matching enum when it needs to be read.
Alternatively you can define what you want the enum to do and make a class that extents the unsigned integer types but has a method that out put the enum string.
Yes, obviously you don't want VI's that returns the enum, except a variant or it's value as an integer. That would require something like class templates, or malleable classes.
You can store the enum as a variant though, or as an integer, or store the variant for the type, and the integer for value...
03-12-2024 06:30 AM
@LV_Tim wrote:If you are thinking of having array objects that abstract and array and have methods to work on the array, this is a possiblity. There are many ways to do this and I am open to suggestions here.
I'd say wait until you run into a use case, and go from there.
It's hard to design solutions when you don't have defined problems.