Jump to content

Different default values for different class levels


Recommended Posts

Hi,

I have a class hierarchy of multiple classes in LVOOP. Let's call my top most parent class "Car". I define it a private data member which I'll call "top-speed". I set default value to 0 as my general car doesn't have top speed. The I create a child class called "Ferrari". As I know that my Ferrari top speed is 200MPH, I'd like my Ferrari class constant to really represent this value. So the question is, is there a way to define different default value for the parent private data in a decendent class so that when I drop Ferrari constant to the block diagram, it would at least have correct properties for Ferrari.

There are no constructors in LVOOP so I cannot use constructors to take care of the task as in other OOP languages. I can write an initialization function, but I wonder if it could be avoided. I guess not... (perhaps this post should be in the wish list section and not here).

Link to comment
Hi,

I have a class hierarchy of multiple classes in LVOOP. Let's call my top most parent class "Car". I define it a private data member which I'll call "top-speed". I set default value to 0 as my general car doesn't have top speed. The I create a child class called "Ferrari". As I know that my Ferrari top speed is 200MPH, I'd like my Ferrari class constant to really represent this value. So the question is, is there a way to define different default value for the parent private data in a decendent class so that when I drop Ferrari constant to the block diagram, it would at least have correct properties for Ferrari.

There are no constructors in LVOOP so I cannot use constructors to take care of the task as in other OOP languages. I can write an initialization function, but I wonder if it could be avoided. I guess not... (perhaps this post should be in the wish list section and not here).

No method exists. This is noted in the design documents white paper as a limitation that needs to be addressed in future versions.

Link to comment
Write a constructor. It will contain the class object and set data for the class. Instead of putting the reference on the diagram you put this vi.

That doesn't provide the initialization guarantee that Jimi is hoping for -- a scoundrel programmer on your team could still drop the class directly instead of dropping the initializing VI.

Jimi: I did think of one workaround.

Parent has member data "speed" which is a double.

Parent also has member data "default speed" which is a boolean.

Parent has a protected dynamic member VI "GetDefaultSpeed" which returns a double.

Parent has a public static member VI "SetSpeed" which sets the value of "speed" AND clears the "default speed" boolean.

Parent has a public dynamic member VI "GetSpeed" which checks the boolean. If the bool is true, it calls GetDefaultSpeed, which dynamically dispatches out to children. If the bool is false, it returns the current value of "speed"

Each child then overrides GetDefaultSpeed with their desired value.

I know -- a lot of overhead for the programmer. I have a solution in mind, but it's going to be a while (almost certainly not the next release) before I can get to this.

Link to comment
That doesn't provide the initialization guarantee that Jimi is hoping for -- a scoundrel programmer on your team could still drop the class directly instead of dropping the initializing VI.

I don't see the difference. a scoundrel programmer could drop the the class and not use this method. One way you insist the programmer drops a vi to construct a class, the other you insist the programmer drop a method everytime he construsts a class. I don't care either way but I do not see any improvement. Either way you have to do extra and define rules as a work around for this limitation. Programmers choice.

Link to comment
That doesn't provide the initialization guarantee that Jimi is hoping for -- a scoundrel programmer on your team could still drop the class directly instead of dropping the initializing VI.

Jimi: I did think of one workaround.

Sorry AQ, it doesn't work in my case. It's the class private methods that should see the correct value in the private data and it's too large an overhead to require all the class methods to access class private data using class methods instead of directly accessing the data. The real reason I asked this question is that I've an application that needs to initialize an object huge number of times (order of million times a run). As calling initialization method is an overhead in this case, I though of by-passing method-based initialization and using contant-based initialization. However it appeared not to be possible. So when you will work on constructors for LVOOP in the future, please use "constant folding" so that constant initalization would be computed already at compile time if just possible to speed up the execution.

Link to comment
I don't see the difference. a scoundrel programmer could drop the the class and not use this method. One way you insist the programmer drops a vi to construct a class, the other you insist the programmer drop a method everytime he construsts a class. I don't care either way but I do not see any improvement. Either way you have to do extra and define rules as a work around for this limitation. Programmers choice.

Suppose I drop a block diagram constant of Car. That Car will have whatever the default values is, since no method has ever modified it. If I wire it to "Get Speed." Jimi would like the value of zero to come out. If I drop a block diagram constant of Ferrari, it will also have default values for all of its private data, including the default value of zero for speed, and if I wire it to "Get Speed", I will get the value of zero. But Jimi wants a way such that a virgin instance of Ferrari will give a value of 200 when passed to Get Speed.

We could require that any time you drop a BDConst of Ferrari, you must wire it to an initialization method that sets 200 into the speed field. But that puts the burden on the user of the class to remember to initialize. That's problematic.

Ideally the language would have support for letting a child class set the initial values for its parent fields. I know a way to make LV robust in this manner, but it is non trivial to implement correctly, and there are other higher priorities. So as a workaround, I'm suggesting that we add a boolean, "Virgin speed?" that defaults to TRUE. Then when Get Speed is called, it can output 200 for Ferrari if and only if that boolean is set. If the boolean is not set, then output whatever the current value for speed happens to be. The work around makes it so that virgin instances of child classes behave as if they have different default values than the parent class.

A slight simplification would be to have the default value of speed be something special, say NAN (not a number). "Get Speed" would detect NAN and output the correct constant value for the class if NAN was detected, and otherwise output whatever value had been set into speed. This eliminates the need for a separate boolean field. If you have many fields that need to differentiate, then this would be a better way than having a different boolean for each field.

The problem with just letting the child class fill in values for its parent fields to be used in all default instances is that those values might not be legal values, as defined by the parent's API. We're going to have to work into LV a way to initialize those fields through calling a VI that can call parent API functions, instead of just setting the fields directly. That's a more challenging integration into the language, especially since, as Jimi points out, such initializations would want to be able to be constant folded. Doable, but not immediately.

Link to comment
That doesn't provide the initialization guarantee that Jimi is hoping for -- a scoundrel programmer on your team could still drop the class directly instead of dropping the initializing VI.

There is not any guarantee of data-to-real-world consistency with the current system anyway, as you can split a wire at any place and create (what we earlier called) a parallel universe.

Joris

Link to comment
There is not any guarantee of data-to-real-world consistency with the current system anyway, as you can split a wire at any place and create (what we earlier called) a parallel universe.

Now that I've used LabVOOP very extensively over the past few months, I must defend NI here. LabVOOP is not a traditional OOP language and it should not be considered to be a traditional OOP language. There defenitely is a need for by-reference implementation in some use cases, but not all. Indeed, by-value implementation provides a very powerful tool for some other use cases. By-value implementation allows the developer very efficiently to parallelize the processing as objects share no common memory segments. This becomes a very important fact as we are beginning to see super scalar processors with eight or even sixteen cores. As objects do not share common memory, the computation can easily be distributed around a cluster which will really provide huge benefits over shared memory processing of by-reference implementation.

I do not think that by-value and by-reference implementations are mutually exclusive, e.g., C++ has both variations side by side. Although LabVOOP doesn't currently have a by-reference mechanism, that can be added later on whereas by-value implementation cannot be added on top of by-reference implementation, at least not any straight-forward way. (Single-element-object-queues cannot be considered a by reference mechanism as queues cannot be passed to subVIs with a parent class input connector.)

Instead of blaming the current LabVOOP implementation of pitfalls, we developers should be constructive and suggest how LabVOOP can be further developed into a more powerful programming language. NI cannot go back and change the current implementation any more, but it can go forward and make it more flexible and even include by-reference objects. Those developers blaming that the by-value implementation is purely wrong should stop thinking if they can also take benefit from the super scalar nature of the by-value implementation. I myself am currently working on a project where we try to write a massively multithreaded application totally based on LabVOOP classes.

p.s. There still is a by-value object use case I do not know how to implement using LabVOOP elegantly... anybody smart enough to come up with an elegant solution?

Link to comment
A slight simplification would be to have the default value of speed be something special, say NAN (not a number).

That'd be my approach, but you also need to consider datatypes where an obvious "I-don't-contain-anything-useful-yet"value doesn't exist - eg: the Boolean.

The problem with just letting the child class fill in values for its parent fields to be used in all default instances is that those values might not be legal values, as defined by the parent's API.

...and that's why I think this can't work generically. Personally, I think that having default values for all data items is dumbing down OO too much. If you have a target userbase that doesn't understand that they need to write a value to a data item before they can read it (eg: I'm talking about you creating and distributing a class) then you need to wrap it and impliment your own layer between the user and the class.

Link to comment
If you have a target userbase that doesn't understand that they need to write a value to a data item before they can read it (eg: I'm talking about you creating and distributing a class)

I would include the teammate sitting at the next desk. Remember that a lot of OO stuff is about enabling team programming as much as it is about creating encapsulated distributable libraries. And it isn't so much about them not understanding. It's a case of remembering to do so. The goal is to cut down on the memory load of the other developers.

then you need to wrap it and impliment your own layer between the user and the class.

That would also work, but honestly the language ought to handle this. It's a problem to consider in the long run.

Link to comment
...it isn't so much about them not understanding. It's a case of remembering to do so. The goal is to cut down on the memory load of the other developers.

Well, if that's the way you look at it then I figure having default data is okay, as long as there is that Boolean input you mentioned to init the field(s) when creating data item(s).

Link to comment
By-value implementation allows the developer very efficiently to parallelize the processing as objects share no common memory segments. This becomes a very important fact as we are beginning to see super scalar processors with eight or even sixteen cores. As objects do not share common memory, the computation can easily be distributed around a cluster which will really provide huge benefits over shared memory processing of by-reference implementation.

There is no reason why the efficient processing would not be possible with a referencing wire. The "sharing memory" problem would only occur if you modify the same data on two different processors, which would not be the case very often. As I've indicated many times before the problem is much worse with the current by-value implementation because you have to split the data into two objects and later have to merge the data again. Or alternatively serialize the actions, which requires some self-implemented error-free locking.

I do not think that by-value and by-reference implementations are mutually exclusive, e.g., C++ has both variations side by side.

This comparison is flawed as C++ has pointers, and LV has not. It is obvious that we don't want pointers. It would be fairer to compare to Java, which has a similar safety as LabVIEW. Java does not have both by-ref and by-value. Only basic variables by-value, objects are by-ref.

Instead of blaming the current LabVOOP implementation of pitfalls, we developers should be constructive and suggest how LabVOOP can be further developed into a more powerful programming language. NI cannot go back and change the current implementation any more, but it can go forward and make it more flexible and even include by-reference objects.

Indeed, NI can switch to referenced objects without significant problems and all 8.20 code will still run. It will require an upgrade process when upgrading VI's to a higher version, but NI does that for other things as well.

If we assume the concept class to be more like a class in other languages, it would need a constructor and destructor. This way a programmer of the class can enforce real-world consistency when an other programmer uses his class. I.e. the second programmer can make much less mistakes.

The upgrade process would need to do the following:

- Insert a copy constructor where an object wire branches.

- Add a copy constructor to each class that requires the above insertion.

It would also allow for auto destruction (maybe a version later). That would require to maintain a reference count each object. When a reference wire ends and the referenced object is not used anywhere else anymore the destructor should be called and the object deallocated (just like it already done with queue refs). This assures you can for example properly close a communications channel when the object using it is not used anymore. This can be done in a deterministic way too, no need for the feared background scavangers.

Then all LV8.20 code would still work even though the wires have become referencing !

A starter programmer does not even see the difference but advanced programmers can start taking real advantage of classes in LabVIEW.

Joris

Link to comment
This comparison is flawed as C++ has pointers, and LV has not. It is obvious that we don't want pointers. It would be fairer to compare to Java, which has a similar safety as LabVIEW. Java does not have both by-ref and by-value. Only basic variables by-value, objects are by-ref.

C++ has references in addition to values and pointers. I don't think this comparison is flawed.

Indeed, NI can switch to referenced objects without significant problems and all 8.20 code will still run. It will require an upgrade process when upgrading VI's to a higher version, but NI does that for other things as well.

Honestly I don't think this suggestion is realistic. I also don't understand how the ability to use by-value objects harms those who want to use only by-ref objects.

Link to comment
Honestly I don't think this suggestion is realistic. I also don't understand how the ability to use by-value objects harms those who want to use only by-ref objects.

I think the question should be the other way round: you should wonder whether the having by-ref objects harms those who want to have by-value objects. I don't think that's the case. So by-ref works for everyone. Don't you think ?

Why do you think the suggestion is unrealistic ?

It is a misconception which returns over and over again, that by-value works simple. It only seems simple but it is actually not simple to work with it, because you have to write complex structures to use the objects in a practical and safe way. Starters don't manage to build/use those structures and they end up with bad programs that don't do what they want. That is something that the language should prevent. So the current implementation is IMHO not good for starters and it is also not good for advanced users.

Whereas by-ref wires are good for advanced users and they don't make things any more complicated for starters compared to by-value wires.

<META>It seems you repeat earlier made statements again, which I've replied to and to which no re-reply came. So I've repeat my counter-argument. </META>

C++ has references in addition to values and pointers. I don't think this comparison is flawed.

Should I conclude that you want to work with references in the same way as you work with references in C++ ? How ?

Is Java not a better comparison anyway because of the security it offers ?

Doesn't Java offer a enough features for a professional environment ?

I don't want all those scary C++ features... Pointers, templates (in the C++ implementation) ouch. C++ has so many things you really don't want. If Straustrup learned anything from the development of C++ it was that he should be very precise on what features he allowed in. He was not happy with the endresult of C++ which has practicall all proposed features, causing the language to be difficult to understand. It's important to keep things simple, to stick to a limited number of basic rules. For that reason I am against two different ways to work with objects. It will make things confusing if you can work with an object by-value AND by-ref.

Joris

Link to comment
Why do you think the suggestion is unrealistic ?

It's unrealistic to expect NI R&D leaders to make their developers to rewrite existing code. From a business decission point-of-view there simply is not enough proof that the current method is not working. So that decission will not be made. If the current implementation later on prooved to be total catastrophy (which I dout), then the NI leaders could make that decission. But defenitely not yet. That's just how large organization work. So it is not realistic from a organizational psychology point of view. Techically your suggestion is probably feasible.

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.