GregFreeman Posted May 14, 2014 Report Share Posted May 14, 2014 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? Quote Link to comment
Neil Pate Posted May 15, 2014 Report Share Posted May 15, 2014 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. Quote Link to comment
drjdpowell Posted May 15, 2014 Report Share Posted May 15, 2014 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. 1 Quote Link to comment
GregFreeman Posted May 15, 2014 Author Report Share Posted May 15, 2014 (edited) 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 May 15, 2014 by GregFreeman Quote Link to comment
mje Posted May 15, 2014 Report Share Posted May 15, 2014 ...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 operationsAs 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? Quote Link to comment
GregFreeman Posted May 22, 2014 Author Report Share Posted May 22, 2014 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. Quote Link to comment
Aristos Queue Posted May 27, 2014 Report Share Posted May 27, 2014 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. 1 Quote Link to comment
MikaelH Posted May 27, 2014 Report Share Posted May 27, 2014 You'll call them in parallel like God and dataflow intended. Awesome. Quote Link to comment
mje Posted May 27, 2014 Report Share Posted May 27, 2014 AQ, that last paragraph confuses me. How does a refnum prevent you from being sure you're read only? Quote Link to comment
Aristos Queue Posted May 28, 2014 Report Share Posted May 28, 2014 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. Quote Link to comment
mje Posted May 28, 2014 Report Share Posted May 28, 2014 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. Quote Link to comment
Aristos Queue Posted May 28, 2014 Report Share Posted May 28, 2014 Part of the API is providing the interface that indicates what concerns the caller needs to have... in this case, that ordering needs to be a concern. The output terminal indicates that, whether it is a written by-value object or a reference object. Quote Link to comment
Daklu Posted May 28, 2014 Report Share Posted May 28, 2014 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? Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.