Java Forum / General / November 2006
pass-by-reference
Mark - 02 Nov 2006 03:49 GMT yeah, I know java is pass-by-value, but there *must* be a way to do something like this...
private Node root = null;
public void insert(Comparable o) { insert(o,root); }
private void insert(Comparable o, Node n) { if( n == null ) n = new Node(o); else if( o.compareTo(n.o) < 0 ) insert(o,n.l); else insert(o,n.r); }
basically.."root" never gets modified after calling something like insert(5); how do I fix this problem?
Mark - 02 Nov 2006 04:06 GMT > yeah, I know java is pass-by-value, but there *must* be a way to do > something like this... [quoted text clipped - 19 lines] > insert(5); > how do I fix this problem? oh God.. what a hideous solution.
private Node root = null;
public void insert(Comparable o) { root = insert(o,root); }
private Node insert(Comparable o, Node n) { if( n == null ) n = new Node(o); else if( o.compareTo(n.o) < 0 ) n.l = insert(o,n.l); else n.r = insert(o,n.r); return n; }
shame on Java.
lordy - 02 Nov 2006 17:51 GMT > shame on Java. I think your are confusing language with data structures. All you need is a single root tree object and your problem goes away, not to mention a lot of superfluous null tests And you can invoke methods on empty trees (eg addNode). Your (arguably) incomplete data structure is leading to awkward workarounds in your code which you them blame on Java and not the real source of the problem.
eg Consider a one node tree. Call deleteNode() and then call addNode() in sequence....
Lordy
Eric Sosman - 02 Nov 2006 04:20 GMT > yeah, I know java is pass-by-value, but there *must* be a way to do > something like this... Must there, indeed? Perhaps you read too much Dr. Seuss as a youngster:
"And it should be, it SHOULD be, it *SHOULD* be that way"
This is from "Horton Hatches the Egg," in which an elephant broods on an abandoned bird egg, which then hatches into a tiny elephant with wings. Nice tale for the kiddies, but if that's your sort of reality, well, ...
> private Node root = null; > [quoted text clipped - 16 lines] > insert(5); > how do I fix this problem? "This problem," I guess, is that the reference `n' is passed by value, and nothing you do to that value propagates back to the caller. What happens in Vegas stays in Vegas. Consider that the call could have been insert(o, new Node()) or insert(o, fetchNodeFromDatabase()), and you'll see why things are so.
So "this problem" cannot be "fixed." Your code, though can be. One way is to introduce a class whose job is to hold the Node reference:
class Nodule { private Node node; void setNode(Node node) { this.node = node; } Node getNode() { return node; } }
private Nodule rootHolder = new Nodule();
public void insert(Comparable o) { insert(o, rootHolder); }
private void insert(Comparable o, Nodule r) { Node n = r.getNode(); if (n == null) { r.setNode(new Node(o)); } else if (o.compareTo(n.o) < 0) insert(o, n.l); else insert(o, n.r); }
Another way is to have the insert method return a reference to the root of the tree, and make it the caller's responsibility to assign the returned value to root:
private Node root;
public void insert(Comparable o) { root = insert(o, root); }
private Node insert(Comparable o, Node n) { if (n == null) n = new Node(o); else if (o.compareTo(n.o) < 0) insert(o, n.l); else insert(o, n.r); return n; }
Still another way -- and better than either of the above, IMHO -- is to reconsider whether "null" is the right way to represent an empty tree. See Knuth, volume I.
 Signature Eric Sosman esosman@acm-dot-org.invalid
Mark - 02 Nov 2006 06:22 GMT > > yeah, I know java is pass-by-value, but there *must* be a way to do > > something like this... [quoted text clipped - 95 lines] > Eric Sosman > esosman@acm-dot-org.invalid haha..
well, when I said there *must* be a way to do "something like this", I didn't quite mean "pass by reference", I simply meant what I had intended to accomplish with my code. And indeed there was a way...just not a way I like very much.
And just when I was starting to like Java... C++ steals my heart away yet again.
The idea of having another class, Nodule, to wrap a Node.. that's..well, the idea disgusts me, even if it works. I barely like the idea of a Node.. it's nested enough as is.
We have our BinarySearchTree..which manages a bunch of Nodes..which will contain WordPairs..which must implement Comparable..
*shivers*
But thank you. Your third suggestion intrigues me.. perhaps I shall look into this.
Chris Uppal - 02 Nov 2006 14:33 GMT > Dr. Seuss [...] Knuth, volume I. It's not just anybody who could mention those two in one post ;-)
BTW, I agree with your diagnosis that the real problem here is null-abuse.
For Mark: consider -- an empty tree is still a tree (just as an empty set is a set, or an empty array is an array). You should be able to ask it how many elements it contains, and so on. You can't do that if you have represented it by null. What is, perhaps, even worse than the logical oddness, is that your code which uses such trees will be cluttered with endless null-tests:
if (tree == null) ... else ...
<shudder/>
-- chris
Niklas Matthies - 02 Nov 2006 20:52 GMT > For Mark: consider -- an empty tree is still a tree (just as an > empty set is a set, or an empty array is an array). You should be [quoted text clipped - 9 lines] > ><shudder/> Well, but with an empty-tree instance his code will likely be cluttered with:
TreeNode root = tree.getRoot(); if (root == null) ... else ...
It might not be that much of an improvement.
Personally, I had a similar problem with a TreePath class (similar to javax.swing.tree.TreePath): Either I use null for the empty path, or else I need to always check path.lastElement() == null (or path.length() == 0). I wasn't happy with either, but it turned out that the former provoked less special-case checks overall.
-- Niklas Matthies
Eric Sosman - 02 Nov 2006 21:41 GMT Niklas Matthies wrote On 11/02/06 14:52,:
>>For Mark: consider -- an empty tree is still a tree (just as an >>empty set is a set, or an empty array is an array). You should be [quoted text clipped - 20 lines] > > It might not be that much of an improvement. The idea is not to "expose" the root of the tree at all, but to keep it internal to the Tree implementation. That is, instead of
TreeNode root = tree.getRoot(); if (root == null) tree.insertAsRoot(newNode); else if (newNode.compareTo(root) < 0) root.insertToLeft(newNode); else if (newNode.compareTo(root) > 0) root.insertToRight(newNode); else throw new DuplicateTreeNodeException();
... he makes the insertion operation a method of the Tree class itself and just writes
tree.insert(newNode);
Other operations that "need" access to the root can also be written as methods of the Tree class: delete(), find(), iterator(), preorderIterator(), ...
Now, I'm not saying this will solve everything: he might want to do something with his Tree that just doesn't fit well as a method of Tree, and this "something" might need explicit access to the root, or might need to do an externally-operated traversal of some kind. If so he'll need to check for the null root of an empty tree -- but since he'll need to check for the null descendants of leaf nodes anyhow, this might not be any extra code.
And besides: When was the last time you needed access to the root node of a java.util.TreeSet?
 Signature Eric.Sosman@sun.com
Mark - 03 Nov 2006 05:54 GMT wow.. lots of posts. okay..
uhh.. well, all I really want is a simple binary search tree. doesn't need anything fancy..
you guys are suggesting that I don't make the root null? how would I avoid this? something like
o | o / \ o o / \ \ o o o
? i'm not sure if that really simplifies anything for me..
Niklas Matthies - 03 Nov 2006 10:51 GMT > Niklas Matthies wrote On 11/02/06 14:52,: : [quoted text clipped - 5 lines] > > tree.insert(newNode); No, for that you use a tree builder class, of course. :) (I'm actually serious.)
> Other operations that "need" access to the root can > also be written as methods of the Tree class: delete(), > find(), iterator(), preorderIterator(), ... Tree traversal algorithms and tree (data) models are seperate concerns, they shouldn't be put into the same class. Otherwise you'll require each tree model implementation to reimplement all traversal algorithms. That way lies insanity (or at least unmaintainability).
> And besides: When was the last time you needed access > to the root node of a java.util.TreeSet? I don't think I ever used java.util.TreeSet. But in my HTML tree control class I need to access the root of the tree model quite often.
-- Niklas Matthies
Tom Forsmo - 02 Nov 2006 10:42 GMT > I know java is pass-by-value, java is not pass by value but by reference. This means that for objects the reference passed in can not be changed but the contents of the object can. Of course for native types, this is the same as pass-by-value.
so what is your problem?
>but there *must* be a way to do > something like this... [quoted text clipped - 19 lines] > insert(5); > how do I fix this problem? Are you complaining that you can not modify the root reference/object or that you can?
If you could explain, in a bit more detail, what you want to do and what you perceive the problem to be, perhaps we might be able to provide you with better help.
tom
Mark - 02 Nov 2006 10:56 GMT > > I know java is pass-by-value, > [quoted text clipped - 36 lines] > > tom The problem was that I could not modify the root object. But by returning it, I have come up with a solution. I believe that this would all be much easier if I could pass by reference however (as in C++), but that's just not going to happen.
Tom Forsmo - 02 Nov 2006 12:42 GMT > The problem was that I could not modify the root object. But by > returning it, I have come up with a solution. I believe that this > would all be much easier if I could pass by reference however (as in > C++), but that's just not going to happen. I still don't understand, if you are trying to modify the root object just go ahead and do so, what's the problem? Since it is only the reference to the root object that is passed along, the object can be changed where ever you like in the code.
If you want to change the reference to the root object, i.e. make the reference point to another object, then that is a different matter, and is not very clear in your original question. If that is the case then it should be no problem, because you don't need to keep the old reference in the collection (or similar) you are inserting the object into, just replace the reference in the collection with the new objects reference.
tom
Michael Rauscher - 02 Nov 2006 11:21 GMT Tom Forsmo schrieb:
>> I know java is pass-by-value, > > java is not pass by value but by reference. Anything in Java is passed by value. So is a reference. The method gets a copy of the reference, so the original reference will leave untouched.
Of course, there's a way to simulate pass by reference by using wrapper objects (arrays for example).
Bye Michael
Tom Forsmo - 02 Nov 2006 13:16 GMT > Tom Forsmo schrieb: >> [quoted text clipped - 3 lines] > > Anything in Java is passed by value. So is a reference. sorry, you are correct, I was confused by the names, but
The method gets
> a copy of the reference, so the original reference will leave untouched. it still works is as you say, which I also stated in my previous post.
> Of course, there's a way to simulate pass by reference by using wrapper > objects (arrays for example). Yes, but that's only if you really need it, which I think is quite seldom if you have designed you application correctly. (Yes i know it would be nice if dealing with immutable objects that needs to be changed and returned but otherwise...)
tom
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|