Sign in to follow this  
Concentrate

I hate Java pass-by-reference-by-value .

Recommended Posts

Once again, java pass by reference by value kills me. This code :
public Position<T> insert(T obj) { 
	return _insert(_root,obj);
}
calls this private helper :
/* Helper functions */
private Position<T> _insert(BTreeNode<T> root, T insertValue)
{
	if(root == null){
		root = new BTreeNode<T>(insertValue);
	}
	else
	{
		int result = insertValue.compareTo(root.element());
		
		if(result < 0){ //value < root
			_insert(root.getLeft(),insertValue);
		}
		else if(result > 0){ // value > root
			_insert(root.getRight(),insertValue);
		}
	}
	return root; //either a new leaf or the position with the same data
}
It does not work because I can't change the reference of the root. Any one wanna just throw some ideas around?

Share this post


Link to post
Share on other sites
Well, you can always simulate "pass T by reference" with passing a reference to a one-element array by value...

public static void changeString(String[] array)
{
array[0] = "updated";
}

public static void main(String[] args)
{
String[] array = {"original"};
changeString(array);
System.out.println(array[0]);
}

Share this post


Link to post
Share on other sites
I guess, but thats kind of ugly. I would do an iterative solution, but am required
for a recursive one. Do you think I can add another parameter and use that
somehow Plus I am not allowed to change the _root type.

Share this post


Link to post
Share on other sites
You could return the new root as a BTreeNode, and then assign the returned value to root, left or right where appropriate.

I'm not entirely sure what distinction there is between Position<T> and BTreeNode<T>, but I think something like the above will work. It might be easier still to move the _insert implementation into the BTreeNode<T> type.

Share this post


Link to post
Share on other sites
If you keep the "null root" as the base recursive case, it becomes a little more elegant looking.

Plus that code looks dangerously like it could clear the tree every time a second element is added.

I have a draft implementation, but this looks like homework so I'll refrain from posting it until you get a little closer.

Share this post


Link to post
Share on other sites
Yes this is H.W. I got it to work, however I guess it doesn't look very elegent
as a C++ tree would. Thanks for not posting the code.

public Position<T> insert(T obj) {
if(_root == null){
_root = new BTreeNode<T>(obj);
return _root;
}
else
return _insert(_root,obj);
}
/* Helper functions */
private Position<T> _insert(BTreeNode<T> root, T insertValue)
{
BTreeNode<T> ret = null;

if(root != null )
{ //compare value
int result = insertValue.compareTo(root.element());
//if value < root
if(result < 0){
if(root.getLeft() == null){ //check if we should add it to left
//add newNode to the left
root.setLeft(new BTreeNode<T>(insertValue));
ret = root.getLeft();
}
//else transversal left
else _insert(root.getLeft(),insertValue);
}
//if value > root
else if(result > 0){
//check if we should add it to the right
if(root.getRight() == null){
//add leaf to the right
root.setRight(new BTreeNode<T>(insertValue));
ret = root.getRight();
}
//else move
else _insert(root.getRight(),insertValue);
}
else ret = root; //node with the same data
}
return ret;
}


Share this post


Link to post
Share on other sites
For what it's worth, this is one of the many things about Java that make me hate with a passion reserved for few things in life.

How simple is it in practically every other language in the world to write a function that returns multiple values? For example, suppose you have some item cache and for speed you want to write a TryGet function that if successful returns true as well as the item, and if failed simply returns false? Simple in every language in the world except Java. In Java you have to do something crazy like create a new class just for the return value, like:


public class CacheLookupResult<T>
{
public bool found;
public T item;
}

public CacheLookupResult<T> TryGetItem(int key)
{
}

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
For what it's worth, this is one of the many things about Java that make me hate with a passion reserved for few things in life.

How simple is it in practically every other language in the world to write a function that returns multiple values? For example, suppose you have some item cache and for speed you want to write a TryGet function that if successful returns true as well as the item, and if failed simply returns false? Simple in every language in the world except Java. In Java you have to do something crazy like create a new class just for the return value, like:

*** Source Snippet Removed ***


Really??? Just return null - it's just as easy to check for null as for false.

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
For what it's worth, this is one of the many things about Java that make me hate with a passion reserved for few things in life.

...

*** Source Snippet Removed ***


You're being silly. This is what null is for, just like kaffiene said. I hope your other grievances with Java are more substantial :-)

Share this post


Link to post
Share on other sites
Quote:
Original post by lightbringer
Quote:
Original post by cache_hit
For what it's worth, this is one of the many things about Java that make me hate with a passion reserved for few things in life.

...

*** Source Snippet Removed ***


You're being silly. This is what null is for, just like kaffiene said. I hope your other grievances with Java are more substantial :-)


Yea, assuming null isn't a valid value for an entry. Point is that you can't easily return multiple values from a function. I don't think that's an insubstantial grievance.

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
Yea, assuming null isn't a valid value for an entry. Point is that you can't easily return multiple values from a function. I don't think that's an insubstantial grievance.


Yeah, you can't return multiple values from C, C++, or C#, either. (which can be considered Java's alternatives, for the most part)

Of course, in C, C++, and C#, you have explicit references/pointers, which can be used to resolve the issue [wink]


public bool TryGetItem(int key, ref T item)
{
if (...)
{
item = ...;
return true;
}
return false;
}


Your specific example in Java would be better written as:

public boolean TryGetItem(int key, T[] item)
{
if (...)
{
item[0] = ...;
return true;
}
return false;
}

It does require you to declare your item in an array, but it's cleaner than creating a whole class for it.

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
Yea, assuming null isn't a valid value for an entry. Point is that you can't easily return multiple values from a function. I don't think that's an insubstantial grievance.


You could throw a checked exception if you really wanted to, but you did say it had to be fast, so I would just leave the interpretation of null to the application developer. This is also the default behavior of the Java Collection classes (at least those that permit mappings to null values). You could also complain about operator overloading... Java trades some shortcuts for safety and simplicity - I consider it beautiful and elegant and clean, but obviously your experience has been different :-) Java is not without shortcomings obviously, but I don't think this is one of them.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
My hint is that if the line "_root = new BTreeNode<T>(obj);" stays inside the helper function _insert(), there are less special cases to handle. My solution is remarkably close to your original attempt.



So I am guessing the base case would be :

if(_root == null){ _root = new BTreeNode<T>(obj); return _root; }
else { ... }

Any more hints. Should I return instead a new BTreeNode ?

Share this post


Link to post
Share on other sites
how's this rip-off :

private BTreeNode<T> _insert(BTreeNode<T> Node, T val){
if(Node == null){
if(isEmpty()) return (_root = new BTreeNode<T>(val));
else return (Node = new BTreeNode<T>(val));
}
else{
int result = _compare(val,Node.element());
if(result < 0) Node.setLeft( _insert(Node.getLeft(),val) );
else if(result > 0) Node.setRight( _insert(Node.getRight(),val) );
return Node;
}
}


Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
For what it's worth, this is one of the many things about Java that make me hate with a passion reserved for few things in life.

How simple is it in practically every other language in the world to write a function that returns multiple values? For example, suppose you have some item cache and for speed you want to write a TryGet function that if successful returns true as well as the item, and if failed simply returns false? Simple in every language in the world except Java. In Java you have to do something crazy like create a new class just for the return value, like:

*** Source Snippet Removed ***


You aren't the only one. In University, my compilers prof's idea of a joke was to get us to generate a partial grammar for Java. Then we generated one for LISP. We were only graded on the second :).

If you find yourself having to work in Java, ever again, Someone wrote a tuple library. I suspect it was because they got tired of having to work around Java's limitations.

Share this post


Link to post
Share on other sites
Essentially that is what I had come up with, except my code had a bug in it that always replaced the root of the tree [embarrass] That bug made the insert logic look simpler.

Now that I see the complete solution, it is not really an elegant solution at all, despite having a little less code that your intermediate attempt. I don't like it because it involves lots of redundant assignments and the strange logic for handling the root case.

I still think that insert logic belongs inside the BTreeNode type. It is a little longer than the other version, but is both easier to read and easier to reason about (the BTreeNode type can maintain internal invariants on the left and right references). This code would be similar to your intermediate attempt, but without the bug where the function returns null for non-root inserts.

A simple way to see this bug is if you use multiple returns. By having a placeholder return value at the top that returns null, the compiler will not warn you about control paths that fail to logically return a value (because they never write to the "result" variable).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this