views:

2268

answers:

3

In response to What is your longest-held programming assumption that turned out to be incorrect? question, one of the wrong assumptions was:

That private member variables were private to the instance and not the class.

(Link)

I couldn't catch what he's talking about, can anyone explain what is the wrong/right about that with an example?

+30  A: 
public class Example {
  private int a;

  public int getOtherA(Example other) {
    return other.a;
  }
}

Like this. As you can see private doesn't protect the instance member from being accessed by another instance.

BTW, this is not all bad as long as you are a bit careful. If private wouldn't work like in the above example, it would be cumbersome to write equals() and other such methods.

Gregory Mostizky
So that private members are private to the class, and an instance can access another instance's private member, correct?
Moayad Mardini
Yes that's correct.
Gregory Mostizky
OK, thanks a lot!
Moayad Mardini
The assumption is that using `private` is a means to protect outside entities from accessing implementation directly. Because this is the same class, it's assumed that we know what we're doing when we access private members of other instances directly. As noted above, this is a good thing: `equals()`, copy constructors (shallow copies/clones, whatever you want to call them), all require intimate knowledge of another instance of the same class to do their job.
Matthew Scharley
I often write equals that way (as if the other object's private fields were inaccessible) anyhow. E.g. class Point2D would have both: public bool equals(object other); and public bool equals(double x, double y); Implementations of equals can get long and messy and I find that to a good way to break them up.
finnw
+2  A: 

Example code (Java):

public class MutableInteger {
    private int value;

    // Lots of stuff goes here

    public boolean equals(Object o) {
        if(!(o instanceof MutableInteger)){ return false; }
        MutableInteger other = (MutableInteger) o;
        return this.value == other.value; // <------------
    }
}

If the assumption "private member variables are private to the instance" were correct, the marked line would cause a compiler error, because the other.value field is private and part of a different object than the one whose equals() method is being called.

But since in Java (and most other languages that have the visibility concept) private visibility is per-class, access to the field is allowed to all code of the MutableInteger, irrelevant of what instance was used to invoke it.

Michael Borgwardt
"and all other language that have the visibility concept, I think" In ruby private is per-object.
sepp2k
Thanks for the info, Michael.
Moayad Mardini
In Scala you can add the context: private[this]
egaga
+2  A: 

Here's the equivalent of Michael Borgwardt's answer for when you are not able to access the private fields of the other object:

public class MutableInteger {
    private int value;

    // Lots of stuff goes here

    public boolean equals(Object o) {
        if(!(o instanceof MutableInteger)){ return false; }
        MutableInteger other = (MutableInteger) o;
        return other.valueEquals(this.value); // <------------
    }

    @Override // This method would probably also be declared in an interface
    public boolean valueEquals(int oValue) {
        return this.value == oValue;
    }
}

Nowadays this is familiar to Ruby programmers but I have been doing this in Java for a while. I prefer not to rely on access to another object's private fields. Remember that the other object may belong to a subclass, which could store the value in a different object field, or in a file or database etc.

finnw