Jump to content

"Rebundling" into class private data.


Recommended Posts

I am curious how people have handled this issue seeing as LabVIEW is by-val. The attached screenshot shows me accessing a particular class's private data using a private method (note, I'm not pulling private data outside the class to modify it, just using a private subVI to keep some stuff clean). But, then the block's private data is updated in one of the methods that is called, so it needs to be rebundled. However, there is no clear way of showing that a particular method has modified private data within itself. Are there any conventions you guys use to indicate that a method actually modifies private data? Or, do you just make the assumption that any method modifies private data and needs to be rebundled unless it's a getter or setter?

 

post-15770-0-43777100-1400104602_thumb.p

 

 

 

 

Link to comment

I usually unbundle and then rebundle. It depends... sometimes I do but it depends on how deep in the call hierarchy the code exists in.

 

If I have a Manager type class then I normally like to not expose the inner working (i.e. private classes) so that the "Block" class never actually gets exposed to the outside world, i.e. there is no get/set "Block" accessor in Executive Functionality. This can be a pain though as it often feels like you are writing the same method for various levels of the hierarchy. 

Link to comment

I don’t have a consistant plan, but I usually tend to assume it modifies the object (or could at some future point be changed such that it modifies the object).  If I’m sure it doesn’t (and never will), then I consider removing the object output, which is the clearest indication you can have that you aren’t changing the object.  

 

One can also use the IPE structure to unbundle, instead of a private accessor method as you are using.   Then one is required to connect up the output.  Connecting the output never hurts.

  • Like 1
Link to comment
I usually unbundle and then rebundle. It depends... sometimes I do but it depends on how deep in the call hierarchy the code exists in.

 

If I have a Manager type class then I normally like to not expose the inner working (i.e. private classes) so that the "Block" class never actually gets exposed to the outside world, i.e. there is no get/set "Block" accessor in Executive Functionality. This can be a pain though as it often feels like you are writing the same method for various levels of the hierarchy. 

Well, therein lies the problem. I am not actually exposing the inner workings because the get current block method I have shown is private. The Executive Functionality class already owns the list of blocks. This private method is just so I don't have to put an index array element 0 everywhere I want to get the first block in the list, but instead can encapsulate that functionality into a method in case the way we determine the "current block" ever changes (which is probably won't but this is just one use case. This could be an issue with other private methods that have more advanced functionality to determine what to return). Part of the misunderstanding here is probably due to the fact I wasn't clear that the "Get Current Block" method isn't just a normal getter but has some additional logic inside of it. 

 

 

If I’m sure it doesn’t (and never will), then I consider removing the object output, which is the clearest indication you can have that you aren’t changing the object.  

That's not a bad idea.

 

Thanks guys, I figured there was no clear cut answer but this at least points me to some different ways of mitigating the problem.

Edited by GregFreeman
Link to comment
...If I’m sure it doesn’t (and never will), then I consider removing the object output, which is the clearest indication you can have that you aren’t changing the object.
I agree with James. When designing an API I do this. I had often wondered if it was good form until I saw it all over the actor framework. Also helps with dynamic dispatch, it's a clue to the implementing class that the consumer of the API doesn't expect or handle state changes. I tend to however ignore the "rule" for accessors since they're usually just inlined bundle/unbundle operations

As to the original question, I'd wonder why your containing class is storing state data that is calculated by something else that it contains. Couldn't that data be stored in the inner object?

Link to comment
As to the original question, I'd wonder why your containing class is storing state data that is calculated by something else that it contains. Couldn't that data be stored in the inner object?

Potentially, but I am taking a bit of a break from this for a couple days. When I get back to it I'll have a look.

Link to comment

I have a personal convention for indicating this, but many people hate it: remove the "object out" terminal for any subVI that does not modify the private data.

 

If it has an "object out" then it modified the data. If it doesn't have an "object out" then it didn't modify the data.

 

Q: But, oh, how will we railroad track our VIs when calling multiple read methods?!

A: You won't. You'll call them in parallel like God and dataflow intended.

 

In my personal code, the only time I'll have an object out for a read-only method is when the class contains a refnum -- because by reference, you cannot be sure anything is read-only, and thus there is always a data dependency between function calls.

  • Like 1
Link to comment

mje: Because we aren't really interested in "read only" ... what we're really interested in is "state dependence".

 

If you have a pure by value object, if you only read the fields, there's no downstream dependence on what happened in that node.

 

But if the object contains a reference, there's a timing dependency potentially. Consider an easy example of an object containing a DVR. If the first node just opens the DVR and reads a value out, the second node may be a writer node that needs to guarantee that it doesn't write the value until after the read is finished. With a by value object, if you forked the wire to a reader and a writer, it wouldn't matter which executed first because each branch of the fork is working on an independent copy of the object (LV's compiler may optimize those copies away at its discretion). But with a reference, each branch is working on the same copy, so you may need an ordering between the read and the write, so containing a reference turns the whole object into behaving like a reference and thus needs an "object out" terminal on every node, regardless of the work that node does.

Link to comment

Gotcha, I suspected as much.

 

It's more of a potayto-potahto thing. I'd argue the state dependence is a sequence issue and the responsibility of the calling code to manage call order. To each their own.

Link to comment

I've never thought of eliminating the object out for methods that do not change state... interesting idea.  One side effect of doing that is you are also ensuring no child classes can ever change their state in the overriding method either.  That may or may not be desirable in any given situation.

 

Just out of curiosity AQ, how do you arrange your block diagram when making calls to multiple non-state-changing methods?  Do you just run the class wire underneath the methods that don't return an object?

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.