aspose file tools*
The moose likes Java in General and the fly likes Set Behavior Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Set Behavior" Watch "Set Behavior" New topic
Author

Set Behavior

Cory Hartford
Ranch Hand

Joined: May 16, 2011
Posts: 82

Hi folks.
I had a homework assignment that ended up kicking my butt and after discovering the problem, I'm still not sure why things acted like they did. It was based on Prim's algorithm but I won't go into that.

I had two Hash sets; call them L and Ez. The requirement was that I perform the following operation on them

(L Union Ez) - (L^Ez) (By the way the message filter kicked out the union symbol because it thought I was trying to use an abbreviation of "you")

Easy enough right? I discovered quickly that you can't perform compound operations like this using the standard set API (that I could find).
Using addAll(), retainAll(), and removeAll() would accomplish the union, intersection, and difference that I needed. However, I needed a way to be able to make two uniques sets: 1 representing the union and one representing the intersect.

My first attempt (and looking back my BIG mistake ) was passing the Set L to another object, performing the union or intersect on it and returning the resulting set. Keep in mind, L in the original was supposed to stay unchanged.
This is where I get mind warped. Any other data type or collection passes a copy of itself; where Sets appear not to do that at all. If you pass a set and do something to the set in another object, the original set is modified!

So all the while I was assuming L was staying in it's original state and it wasn't. Performing unions, intersects and differences using L weren't working correctly because L was changing.
I eventually solved the issue after I was able to identify what was going on; I "laundered" the set through an arraylist and then back to a set.

Anyway, I was just curious if you guys could help me understand why this is the way it is with sets and not other collections and data types.



‎"The greatest of all weaknesses is the fear of appearing weak." - JB Bossuet
Matthew Brown
Bartender

Joined: Apr 06, 2010
Posts: 4467
    
    8

How did you "pass it to the other object"? You should be able to create a separate copy of a Set by using a copy-constructor. E.g.:

If you did it in a different way, it's going to depend on exactly what operations you used.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39865
    
  28
Use escape sequences, eg ∪ = ∪, ∩ = ∩ for your union and intersection operators in HTML.You can find which methods mimic union difference and intersection from the Set interface and ctrl-F “union” etc. Or you can find Set in the Java™ Tutorials and look up the “bulk operations”. You will also find code surprisingly similar to what I wrote a few lines back, but with the gaps filled in
Remember difference is asymmetrical; there is s1 \ s2 and s2 \ s1, which may be different from each other.
Cory Hartford
Ranch Hand

Joined: May 16, 2011
Posts: 82

Matthew Brown wrote:How did you "pass it to the other object"? You should be able to create a separate copy of a Set by using a copy-constructor. E.g.:

If you did it in a different way, it's going to depend on exactly what operations you used.


Thats what I could have (and should have done). I passed it directly thinking it would act like a primitive type and it doesn't. I just tested an ArrayList and sure enough it acts the same way as the set. Learned something new!
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Cory Hartford wrote:I passed it directly thinking it would act like a primitive type and it doesn't.


No, passing a reference works exactly like passing a primitive. In both cases, the value of the expression is copied and passed to the caller. That is, Java is always "pass-by-value". Note, however, that it's only the references you're passing, never the object.

Your misunderstanding appears to have been not in how parameters are passed, but rather in what the value of the variable is.
Cory Hartford
Ranch Hand

Joined: May 16, 2011
Posts: 82

Campbell Ritchie wrote:Use escape sequences, eg ∪ = ∪, ∩ = ∩ for your union and intersection operators in HTML.You can find which methods mimic union difference and intersection from the Set interface and ctrl-F “union” etc. Or you can find Set in the Java™ Tutorials and look up the “bulk operations”. You will also find code surprisingly similar to what I wrote a few lines back, but with the gaps filled in
Remember difference is asymmetrical; there is s1 \ s2 and s2 \ s1, which may be different from each other.


Thanks for the escape sequence tip Campbell. The section on non-destructively operating on sets is super helpful and if I had it to do over again is the method I would have used. Luckily, I had a static equation so my difference order was defined.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8244
    
  23

Cory Hartford wrote:This is where I get mind warped. Any other data type or collection passes a copy of itself.

Don't know where you got that idea from
someList.addAll(someOtherList)
will result in someList being modified, as will
someMap.putAll(someOtherMap)

I eventually solved the issue after I was able to identify what was going on; I "laundered" the set through an arraylist and then back to a set.

Seems like overkill to me. In addition to Matthew's suggestion, most Set implementations are Cloneable, so you could have just used
L.clone()
(BTW, variables should generally start with a lower-case letter).

Furthermore, if you don't want your Set to be modified, you should use Collections.unmodifiableSet().

Anyway, I was just curious if you guys could help me understand why this is the way it is with sets and not other collections and data types.

See above.

Winston


Isn't it funny how there's always time and money enough to do it WRONG?
Articles by Winston can be found here
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Cory Hartford wrote:
This is where I get mind warped. Any other data type or collection passes a copy of itself; where Sets appear not to do that at all.


No, what's passed is exactly what you pass, and passing a parameter never copies an object. Internally a given method or constructor might do so, but it will be documented if it does.

Can you show code that demonstrates this difference you think you see?

If you pass a set and do something to the set in another object, the original set is modified!


Exactly the same as with any other collection. Or any other object for that matter.
Cory Hartford
Ranch Hand

Joined: May 16, 2011
Posts: 82

Jeff Verdegan wrote:
Cory Hartford wrote:I passed it directly thinking it would act like a primitive type and it doesn't.


No, passing a reference works exactly like passing a primitive. In both cases, the value of the expression is copied and passed to the caller. That is, Java is always "pass-by-value". Note, however, that it's only the references you're passing, never the object.

Your misunderstanding appears to have been not in how parameters are passed, but rather in what the value of the variable is.


Hmm. So how can the original object be changed if only the copy is being sent?
For example, take these two classes


The output:
Original List is [2, 3]
New List is [2, 3]
0
1


In the case of the ArrayList the original object was modified. In the case of the Integer (primitive) it wasn't.
Cory Hartford
Ranch Hand

Joined: May 16, 2011
Posts: 82

Winston Gutkowski wrote:
Cory Hartford wrote:

I eventually solved the issue after I was able to identify what was going on; I "laundered" the set through an arraylist and then back to a set.

Seems like overkill to me. In addition to Matthew's suggestion, most Set implementations are Cloneable, so you could have just used


It was total overkill; I see that now.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8244
    
  23

Cory Hartford wrote:In the case of the ArrayList the original object was modified. In the case of the Integer it wasn't.

Ooof. Where to start.

First, the variables are not Integers, they're ints, which are modifiable (although your example isn't actually modifying the source at all).
Second, a reference holds the location of an object, not the object itself, so if you copy a reference, you are copying a location not an object.

The only ways to copy an object are
1. If it is Cloneable, to call its clone() method.
2. If it has a public copy constructor or factory method, to call it.
but all the above rely on the designer providing these things for you.

Winston
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Cory Hartford wrote:
Jeff Verdegan wrote:
Cory Hartford wrote:I passed it directly thinking it would act like a primitive type and it doesn't.


No, passing a reference works exactly like passing a primitive. In both cases, the value of the expression is copied and passed to the caller. That is, Java is always "pass-by-value". Note, however, that it's only the references you're passing, never the object.

Your misunderstanding appears to have been not in how parameters are passed, but rather in what the value of the variable is.


Hmm. So how can the original object be changed if only the copy is being sent?


As I said, a copy of the reference is being passed. So now the method and the caller each have a reference to the same object.

In the case of the ArrayList the original object was modified. In the case of the Integer (primitive) it wasn't.


You're still thinking a variable's value is an object. It's not. It's a reference.

The difference in behavior you're seeing is because, unlike primitive variables, reference variables point to objects, and can be dereferenced. That "extra layer" isn't there with primitives. It terms of how things are passed and the fact that they can't affect the "original value" (caller's value), there's no difference.
fred rosenberger
lowercase baba
Bartender

Joined: Oct 02, 2003
Posts: 11480
    
  16

Cory Hartford wrote:
Hmm. So how can the original object be changed if only the copy is being sent?

A copy of the ADDRESS (more or less) is being passed.

Let's say you have your home address written on a piece of paper. You hand me a copy of that address, and tell me to go paint the master bedroom of that house.

Would you be surprised to go to the address on your slip of paper and find the master bedroom their has been painted?

Cory Hartford
Ranch Hand

Joined: May 16, 2011
Posts: 82

Thanks Jeff and Fred; that makes perfect sense as to why the ArrayList was modified. Both caller and and the method have the same reference (address) to the ArrayList. So the same ArrayList gets painted whether I paint it in the caller or the method.
I'm still not sure I entirely understand the int behavior. I tried redeclaring like Integer i = new Integer(0) thinking this was what you were referencing Jeff when you were talking about primitive versus reference variables. I got the same result so I'm sure that I misunderstood.


Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Cory Hartford wrote:
I'm still not sure I entirely understand the int behavior I tried redeclaring like Integer i = new Integer(0) thinking this was what you were referencing Jeff when you were talking about primitive versus reference variables. I got the same result so I'm sure that I misunderstood.


Not sure what you mean by same results, but here's a quick overviw:



In #1, were are dereferencing the list variable to change the contents of the object it points to. That is, we are painting a wall in a house whose address is written on both the method's piece of paper and the caller's piece of paper. So naturally, both the method and the caller see the same result.

In #2, #3, and #4 we are erasing what's written on the method's piece of paper, and writing something different on there. In none of these cases does the caller see any effect. He has no way of knowing what the method does with his pieces of paper after the caller copies stuff onto them and hands them to the method.

The difference between the primitive int paper and the other reference papers, is that the primitive int paper doesn't have the address of a house with contents. What's written on the primitive int paper is a value that we care about and use directly. The value 123 means something to us in this case. For the reference papers--i2 and list--we don't care about the value on the paper in and of itself; it's only a means to get to the house whose contents we care about.

So, the way the values are passed to the method is identical. What's different is in what the values mean and how we use them. Directly, for the value itself (primitives) vs. just as a way to get to a house (object) whose contents we are interested in (for reference variables).

Now, the other difference here, totally independent of primitive vs. reference, and totally independent of how things are passed, is the fact that the Integer class happens to be defined to be immutable, while the ArrayList class happens to be defined to be mutable. That is, Integer, like all the other primitive wrappers, and like String, and like any class you could write yourself, does not provide a means to change its internal state (its contents) after it has been created. This in contrast to ArrayList (and LinkedList, and Date, and any class you could write yourself), which does provide ways to change its state after creation. To stretch the analogy to its limits, an ArrayList house has an unlocked front door, while an Integer house lets you look in the windows to see what color the walls are painted, but its front door is locked.

Finally, one more thing that can confuse the issue is autoboxing. When you do Integer i2 = 456; the compiler turns that into a call to Integer i2 = Integer.valueOf(456); which either produces a new Integer object or returns a reference to one in the constant pool. The key point, here, is that it's an object, even though using the 456 directly may make it look similar to a primitive.

I know that's a lot of information, but it's necessary to show the major pieces to be able to explain what you're seeing in the code you're playing with. Does it make sense now, or is something still unclear?
Cory Hartford
Ranch Hand

Joined: May 16, 2011
Posts: 82

Jeff Verdegan wrote:

I know that's a lot of information, but it's necessary to show the major pieces to be able to explain what you're seeing in the code you're playing with.



Nope; its perfect. I just need to re-read it and digest it. Thanks for taking the time to explain it.
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

You're welcome!
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Set Behavior