0

“Exposing the rep” of an object can be caused by which of the following:

  1. Not declaring variables in its class as private.
  2. Allowing a variable in the object to refer to an object passed to it as an argument to its constructor.
  3. Allowing a reference stored in a variable in the object to be passed as the return value of a method called on that object.
  4. All of the above.

I know the answer is 4 but i'm not sure why, my understanding of what exposing the rep is not completely clear.

Edit: for clear answers

ruakh
  • 175,680
  • 26
  • 273
  • 307
user3364498
  • 489
  • 1
  • 9
  • 14
  • 2
    representation maybe? – emesx Mar 19 '14 at 21:58
  • 3
    Probably this: http://stackoverflow.com/questions/14124683/findbugs-real-threat-behind-ei-expose-rep – maksimov Mar 19 '14 at 21:59
  • 3
    If you know the answer is 4, what exactly is your question? – JB Nizet Mar 19 '14 at 22:00
  • 3
    His question is "what exposing the rep [means]". The answer is "Exposing the internal class' representation". – maksimov Mar 19 '14 at 22:02
  • Thanks, i meant representation but wanted to leave it exactly how the question was phrased. I'll continue my research, thanks to maksimov for the link and the answer. – user3364498 Mar 19 '14 at 22:05
  • Does anybody know what #2 means? – ajb Mar 19 '14 at 22:18
  • @ajb I assume #2 is similar to #3 in that storing a reference to a mutable object in a constructor will allow the constructing code to modify the mutable object in ways that the object may not expect. – clstrfsck Mar 19 '14 at 22:41
  • @msandiford So if you call `BufferedInputStream(InputStream in)` and it saves `in` in a member field, this exposes the internal representation of `BufferedInputStream`? I guess "can" (_can_ be caused by...) is the operative word here, depending on what the object reference is used for... – ajb Mar 19 '14 at 23:30

1 Answers1

2

I had never heard that term, so I googled it. This article explained it quite clearly:

http://www.cs.newpaltz.edu/~pletcha/oop_chap5_1.html

Exposing the rep means to violate the rule that an object's methods control its state. For example, if an object has instance variables and mutators to change their values, then the object has a means of controlling its state. If I call foo.setBar(5), then foo.getBar() better return 5 if the documentation says getBar returns the value set by setBar.

I will explain why each of the three descriptions you gave exposes the representation of an object (or put more generally, breaks encapsulation):

Not declaring variables in its class as private.

This one is the easiest. If the instance variables are public, anything in the JVM can change their values from outside of code within the same object/class. If we call foo.setBar(5) and then foo.getBar(), we may get something other than 5 because bar is public scope so another area of code could have mutated it.

Allowing a variable in the object to refer to an object passed to it as an argument to its constructor.

This one took me a minute to understand, but it makes sense if you think about an object and its dependencies as a single unit.

If a Foo has a Bar and Bar has int called x, then Foo can see and control the x property on bar because it has a reference. If I create an instance of Foo and pass a reference to an instance of Bar in Foo's constructor, it gives the appearance that Foo has complete control. But it does not. Example:

public class Foo {
    private Bar bar;

    public Foo(Bar bar) {
        this.bar = bar;
    }

    // immutable property - can only be read once this object is instantiated
    public Bar getBar() {
        return this.bar;
    }
}

public class Bar {
    private int x;

    public Bar(int x) {
        this.x = x;
    }

    public int getX() {
        return this.x;
    }

    public void setX(int x) {
        this.x = x;
    }
}

// some other java class
Bar bar = new Bar(10);
Foo foo = new Foo(bar);
bar.setX(5);

This code exposes the rep because foo has made a critical assumption that it controls bar. Notice its reference to bar is immutable. But it isn't really immutable. Only the reference itself is immutable. The code that created foo still has a reference to bar and can mutate it without foo knowing about it.

Put more simply, foo has a dependency on bar and considers it part of itself. But bar can actually change independently and therefore foo's state changed indirectly without it knowing.

Allowing a reference stored in a variable in the object to be passed as the return value of a method called on that object.

This is easiest to explain through a collection.

public class Foo {
    private Collection<Bar> bars = new ArrayList<Bar>();

    // immutable property - can only be read once this object is instantiated
    public Collection<Bar> getBars() {
        return this.bars;
    }

    public void addBar(Bar bar) {
        this.bars.add(bar);
    }

    public int getBarCount() {
        return this.bars.size();
    }
}

Foo foo = new Foo();
foo.getBars().add(new Bar(someUnexpectedBar));
System.out.println(foo.getBarCount());  // -> 1

This violates the contract. To add a bar, you are supposed to call addBar. That is why the method is exposed. By returning a reference to the collection in getBars, the underlying collection can be manipulated.

This seems trivial at first. But if Foo makes this rule and the above usage violates it, then what would happen if I want to refactor Foo to this (let's say for performance):

public class Foo {
    private Collection<Bar> bars = new LinkedList<Bar>();
    private int barCount;  // for faster inserts, use a linked list and to maintain fast counts, track the count ourselves by tracking the adds.

    // immutable property - can only be read once this object is instantiated
    public Collection<Bar> getBars() {
        return this.bars;
    }

    public void addBar(Bar bar) {
        this.bars.add(bar);
        this.barCount++;
    }

    public int getBarCount() {
        return this.barCount;
    }
}

Foo foo = new Foo();
foo.getBars().add(new Bar(someUnexpectedBar));
System.out.println(foo.getBarCount());  // -> 0

Functionally, it's identical. If you use the methods in it appropriately, there would be no difference. But we cheated. We grabbed the underlying collection and mutated it. Now the getBarCount() method returns the wrong answer (0).

The way around this is to return a new collection with a clone of the original.

    public Collection<Bar> getBars() {
        return new ArrayList<Bar>(this.bars);
    }

or even

    public Collection<Bar> getBars() {
        return Collections.unmodifiableCollection(this.bars);
    }
Brandon
  • 9,822
  • 3
  • 27
  • 37
  • So if I understand it, #2 is a problem because `Foo`'s code, in this case, is assuming it controls `bar`--but doesn't that depend on how `Foo` is written? And if `Foo` is written with the understanding that `bar` could be changed underneath it, then it's not a problem, I'd think. That's the only way I can make sense of it. The idiom (setting up an object that refers to another object) seems to be an indispensable one, if done right; I've already found it in one place in the JRE and I'm sure I could find many others as well as examples in "Design Patterns". – ajb Mar 20 '14 at 01:55
  • Exactly. It depends on what the design / intent / contract of `Foo` is. I gave sample code that would help illustrate the intent of controlling the instance. It's perfectly possible for a class to simply not care about this. – Brandon Mar 20 '14 at 02:07
  • An even better example I just thought of: HashMap. When you call `HashMap.put`, the key is hashed to find the right bucket. But the key could be mutated afterwards in a way which alters its hash code. I can't speak for the design intention of `HashMap`, but it is generally assumed, at least I generally assume, that when adding an object to a HashMap, its hash code does not ever change. This would be one of the worst kinds of bugs because figuring it out would be a nightmare. – Brandon Mar 20 '14 at 02:14