Newbie Question - ArrayLists and methods

T

Taria

Hello all (again),

My problem here is that I'm trying to build a list of ArrayLists that
hold data and I want to add the newly derived data into a table where
it's dependent on the first row. A short version of my program to
illustrate what I mean:

import java.util.*;
public class MyProg2 {
public static void main(String[] args) {
List table = new ArrayList ();
List <Integer> data = new ArrayList <Integer>();
data.add(1);
data.add(3);
data.add(4);
table.add(data);

System.out.println ("table(0) = " + table.get(0));

ArrayList <Integer> newNode = new ArrayList <Integer>();
newNode = createNode((ArrayList)table.get(0),0);
table.add(newNode);
System.out.println ("Added in a new row and table is now:");
System.out.println ("table(0) = " + table.get(0));
System.out.println ("table(1) = " + table.get(1));

} //end main driver
public static ArrayList createNode(ArrayList items,int lParen){
int a = 0; int b=0; int c=0;
if (items.size() >= 2){
a = Integer.valueOf(items.get(lParen).toString());
b = Integer.valueOf(items.get(rParen).toString());
c = a + b;
items.remove(lParen);
items.remove(lParen);
items.add(lParen,c);
}
return items;
}
}

(I'm unable to get rid of all the unchecked msgs because putting the
<Integer> tag sometimes made the program uncompilable. Use --nowarn
when you compile this program. :)

Iin this code, row 0 of table is changed in the method while it
creates row 1, but I don't understand why and don't know how to keep
it from changing. From this behavior, it's leading me to believe
ArrayLists are passed by value or is this the way of ArrayLists? I
thought parameters were passed by reference? What am I missing here?

-t
 
J

Joshua Cranmer

Taria said:
Hello all (again),

My problem here is that I'm trying to build a list of ArrayLists that
hold data and I want to add the newly derived data into a table where
it's dependent on the first row. A short version of my program to
illustrate what I mean:

import java.util.*;
public class MyProg2 {
public static void main(String[] args) {
List table = new ArrayList ();

List said:
List <Integer> data = new ArrayList <Integer>();
data.add(1);
data.add(3);
data.add(4);
table.add(data);

System.out.println ("table(0) = " + table.get(0));

ArrayList <Integer> newNode = new ArrayList <Integer>();
newNode = createNode((ArrayList)table.get(0),0);

.... so you can change this line to:
newNode = createNode(table.get(0),0);
table.add(newNode);
System.out.println ("Added in a new row and table is now:");
System.out.println ("table(0) = " + table.get(0));
System.out.println ("table(1) = " + table.get(1));

} //end main driver
public static ArrayList createNode(ArrayList items,int lParen){

public static List said:
int a = 0; int b=0; int c=0;
if (items.size() >= 2){
a = Integer.valueOf(items.get(lParen).toString());
b = Integer.valueOf(items.get(rParen).toString());

typo? I see no `rParen' defined anywhere.
c = a + b;
items.remove(lParen);
items.remove(lParen);
items.add(lParen,c);
}
return items;
}
}

Here is my rough estimate of what the second method should look like:
public static List<Integer> createNode(List<Integer> items,
int leftIndex, int rightIndex) {
// Create a copy so we can modify without changing...
items = new ArrayList<Integer>(items);
if (items.size() >= 2){
int sum = items.get(leftIndex)+items.get(rightIndex);
// Remove from the right first -- otherwise we're off by one.
items.remove(rightIndex);
items.remove(leftIndex);
items.add(leftIndex,sum);
}
return items;
}
(I'm unable to get rid of all the unchecked msgs because putting the
<Integer> tag sometimes made the program uncompilable. Use --nowarn
when you compile this program. :)

Have you read up on generics?
Iin this code, row 0 of table is changed in the method while it
creates row 1, but I don't understand why and don't know how to keep
it from changing. From this behavior, it's leading me to believe
ArrayLists are passed by value or is this the way of ArrayLists? I
thought parameters were passed by reference? What am I missing here?

Row 0 is changing because the parameters are being passed by reference.
You send in the list of items, and it simultaneously affects both the
to-be-returned value and the input (rows 1 and 0, respectively). To keep
it from changing, you want to create a copy of the row, which is what
the first line of my method does.
 
L

Lew

Joshua said:
Row 0 is changing because the parameters are being passed by reference.

According to Sun and the language lawyers, the parameters are passed by value.
The values happen to be references.
You send in the list of items, and it simultaneously affects both the
to-be-returned value and the input (rows 1 and 0, respectively). To keep
it from changing, you want to create a copy of the row, which is what
the first line of my method does.

As did the code I posted to the first version of this question.
 
T

Taria

Looking back, I see it now. To be honest, Lew, your code intimidated
me because of all the new statements it (new to me anyway.) There are
quite a few new keywords I liked that I want to try using once I get
the basic structure down for my program. Your code is one of those
things that I have to read multiple times on different days to
understand like Cormen's book.

Thanks to Daniel, Donald and Lew, I now understand how to manipulate
an ArrayList within a block and method. I think I can finish this
homework project that I have to do with the concepts I have learned in
the last few days. I'm about 15% done.

Personally, I think it's odd that you have to make a copy of a passed
parameter before using it to avoid modifying it within a method. I
thought that the parameters retained their value (if passed by
reference) despite modification during the course of the method
activation. I'm going to have to try experimenting with this part
after I'm done with this program! :)

-t (the grateful Newbie Java programmer)
 
D

Daniel Pitts

Taria said:
Personally, I think it's odd that you have to make a copy of a passed
parameter before using it to avoid modifying it within a method. I
thought that the parameters retained their value (if passed by
reference) despite modification during the course of the method
activation. I'm going to have to try experimenting with this part
after I'm done with this program! :)

-t (the grateful Newbie Java programmer)
Actually, the way it works, is when you use "new Something", it
allocates the room for the Something object, and does all its
initialization "magic".

After that, you have exactly one Something, and anything that references
it references the exact same Something object. The references
themselves are copied, but the object they reference isn't copied or moved.

In other words, the semantics of Java parameters are that primitives and
references are passed-by-value, but objects are only accessible through
a reference, so the objects are never passed-by-value.

Hope this clarifies things.
 
R

Roedy Green

Personally, I think it's odd that you have to make a copy of a passed
parameter before using it to avoid modifying it within a method. I
thought that the parameters retained their value (if passed by
reference) despite modification during the course of the method
activation.

You don't quite get it yet. Let me try yet another explanation.

When you call a method, a COPY of the value of the argument is passed
to the stack to become the local parameter inside the method. If you
modify it in the method, it won't charge any variables in the caller,
but it will change the value of your local variable.

If you use the word "final" on your parameter, if you try to modify
the value, the compiler won't let you.

If you need both the original value of the argument and a modified
value, you will need two variables, one to hold the old and one to
hold the new value. However, even in that case the caller's variables
will be untouched.

See http://mindprod.com/jgloss/parameter.html
http://mindprod.com/jgloss/argument.html
 
C

Curt Welch

Roedy Green said:
Personally, I think it's odd that you have to make a copy of a passed
parameter before using it to avoid modifying it within a method. I
thought that the parameters retained their value (if passed by
reference) despite modification during the course of the method
activation.
[snip]

If you need both the original value of the argument and a modified
value, you will need two variables, one to hold the old and one to
hold the new value. However, even in that case the caller's variables
will be untouched.

I generally try to not modify pass by value parameters as a matter of
style. I don't always follow my own rules but most the time, if I need to
modify it, I will normally create a new local variable and only modify the
local variable. I find that it's very common that you will need the
original value at some point in the future and it's also common to not
always notice that the argument was modified locally. It's a nasty way for
obscure bugs to creep into the code when the argument is only modified on
certain rare conditions so the code added later that assumes it is working
with the original value only breaks on the rare conditions.

I find it's best to logically think of arguments as final (aka read only).
Logically, it's better to treat the parameter as belonging to the calling
code and not belonging to the local code even though pass by value
arguments are technically local. I think it helps you keep the correct
mindset when you deal with the parameters that aren't passed by value (the
contents of all objects and arrays).
 
R

Roedy Green

I find it's best to logically think of arguments as final (aka read only).
Logically, it's better to treat the parameter as belonging to the calling
code and not belonging to the local code even though pass by value
arguments are technically local.

I have got into the habit of marking everything final, then removing
the final if I have to. It is amazing when you do that how few
non-final variables there are. I almost wish variables were final by
default and you had to declare them "mutable".
 
D

Daniel Pitts

Roedy said:
I have got into the habit of marking everything final, then removing
the final if I have to. It is amazing when you do that how few
non-final variables there are. I almost wish variables were final by
default and you had to declare them "mutable".
True that.
 
C

Chris ( Val )

I have got into the habit of marking everything final, then removing
the final if I have to.

[snip]

That sounds like a good idea. I got into the
same habit when passing objects around in C++.

But this leads me to a question.

In C++, if I marked a parameter of a function as
'const', then I could not operate on that parameter
at all, no matter if I used pass by value or pass
by reference semantics, for objects or primitive
types.

However, in Java, when using the 'final' keyword in
method parameters for reference object types, it does
not provide the same protection, as the object can still
be modified, and only the reference itself can't be changed.

So my question question is:

How do you stop the modification of an object, via
the client working directly on the method parameter?
 
L

Lew

Chris said:
How do you stop the modification of an object, via
the client working directly on the method parameter?

Make the parameter be of an immutable type.

If you must use a mutable type, have the subroutine make a defensive copy of
the argument and work on that instead.
 
C

Curt Welch

Lew said:
Make the parameter be of an immutable type.

If you must use a mutable type, have the subroutine make a defensive copy
of the argument and work on that instead.

The object which is being passed must protect itself if it doesn't want to
be changed. To start with, the instance vars can be changed to private or
protected to keep outside code from referencing or changing the instance
variables directly, and then the protection is a function of what methods
are available. Making instance variables private by default is good
practice in general.

If the issue is that the calling object doesn't want the object passed to
be modified, there is no simple way to do it. If possible, make a copy of
it before you pass it as Lew said. Or you could wrap it in a wrapper class
which is a subclass of the object it is wrapping, and override all the
methods which mutate the object and disable them. But that's a excessive
measure if you only goal is to reduce the odds of bugs in the code.

There are no simple keywords like const to disable all modifications to a
passed argument.
 
C

Chris ( Val )

Make the parameter be of an immutable type.

If I have control over the class design, I guess that is one way.

Or, did you perhaps mean to wrap up the object?
If you must use a mutable type, have the subroutine make a defensive copy of
the argument and work on that instead.

I was afraid of that, as it ultimately puts a
lot more responsibility on the developer.

Thank you.
 
D

Daniel Pitts

Lew said:
Make the parameter be of an immutable type.

If you must use a mutable type, have the subroutine make a defensive
copy of the argument and work on that instead.
Actually, in reality this defeats several OO principals. If you think
of the method call as a message, then that message handler should be
free to issue other messages to any objects that it knows about. If you
have a good design, then the handler (method) won't do something its not
supposed to.

Indeed, if you have an ill-behaved object that modifies its own state
when it shouldn't, then you need to make a defensive copy.

Well, that's true in theory at least. I haven't played around with that
concept, so take that advice with a grain of salt and think for yourself
what fits bets :)

Daniel.
 
L

Lew

Daniel said:
Lew said:
Make the parameter be of an immutable type.

If you must use a mutable type, have the subroutine make a defensive
copy of the argument and work on that instead.
Actually, in reality this defeats several OO principals [sic]. If you think
of the method call as a message, then that message handler should be
free to issue other messages to any objects that it knows about. If you
have a good design, then the handler (method) won't do something its [sic] not
supposed to.

A good design might include making a defensive copy so that the handler method
won't do something it's not supposed to do.

There is no violation of "OO" principles there.
 
T

Taria

Roedy Green said:
quoted or indirectly quoted someone who said :
Personally, I think it's odd that you have to make a copy of a passed
parameter before using it to avoid modifying it within a method. I
thought that the parameters retained their value (if passed by
reference) despite modification during the course of the method
activation.
[snip]

If you need both the original value of the argument and a modified
value, you will need two variables, one to hold the old and one to
hold the new value. However, even in that case the caller's variables
will be untouched.

I generally try to not modify pass by value parameters as a matter of
style. I don't always follow my own rules but most the time, if I need to
modify it, I will normally create a new local variable and only modify the
local variable.

I definitely like that idea of making a local variable and only
modifying that instead of the passed variable. I think I will adopt
this style.
 
L

Lew

Taria said:
I definitely like that idea of making a local variable and only
modifying that instead of the passed variable. I think I will adopt
this style.

public class Eg
{
public static void modify( Foo foo )
{
Foo local = foo;
local.setName( "bar" );
}
}

If another method calls modify(Foo) then the name attribute of the passed
object will change.

public void cranitz()
{
Foo arg = new Foo();
arg.setName( "arg" );
Eg.modify( arg );
System.out.println( arg.getName() ); // displays "bar"
}

If the called method copies the passed object, then the method is unable to
alter the original object. If it merely points a local variable to the
(mutable) passed object, naturally the method can alter the object through its
local pointer.
 

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

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top