pass-by-reference

M

Mark

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?
 
M

Mark

Mark said:
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?

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.
 
E

Eric Sosman

Mark said:
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;

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?

"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.
 
M

Mark

Eric said:
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, ...


"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.

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.
 
T

Tom Forsmo

Mark said:
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...

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?

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
 
M

Mark

Tom said:
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?


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

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.
 
M

Michael Rauscher

Tom said:
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
 
T

Tom Forsmo

Mark said:
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
 
T

Tom Forsmo

Michael said:
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
 
C

Chris Uppal

Eric said:
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
 
L

lordy

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
 
N

Niklas Matthies

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/>

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
 
E

Eric Sosman

Niklas Matthies wrote On 11/02/06 14:52,:
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.

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?
 
M

Mark

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..
 
N

Niklas Matthies

Niklas Matthies wrote On 11/02/06 14:52,: :
The idea is not to "expose" the root of the tree at
all, but to keep it internal to the Tree implementation. :
... he makes the insertion operation a method of the Tree
class itself and just writes

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,260
Messages
2,571,039
Members
48,768
Latest member
first4landlord

Latest Threads

Top