November 11, 2012

Tidbits from my Java class

Don't quite understand immutability yet, so I'm gonna try to learn the crap out of it

So, first, of all, we have to understand why this code is crappy:
(Before osu's cse department decides to sue me, this is all info from here)
public class Period implements FixedEpoch {
   private Date start;
   private Date end;

   public Period (Date start, Date end) {
      assert (start.compareTo (end) < 0); // start < end

      this.start = start;
      this.end = end;
   }

   public Date getStart() {
      return start;
   }

   public Date getEnd() {
      return end;
   }

}
So why is this like the worst code ever?

ALIASING!!!!!!!!!
The assignment in the constructor (public Period (Date ..) ) creates an ALIAS - the client and component both have references to the same Date object.

So why is this a problem?

Take this code:
Date t1 = new Date (300);
Date t2 = new Date (500);
Period p = new Period (t1, t2);
t2.setTime (100);


So now, p is modified even though we might not have wanted it to be.  Oh noes!

But there is a solution: "defensive copying", where the constructor creates a copy of the arguments.
For example, here is a better Period class:
public class Period implements FixedEpoch {
   private Date start;
   private Date end;

   public Period (Date start, Date end){
   assert (start.compareTo (end) < 0);
   
      this.start = new Date (start.getTime() );
      this.end = new Date (end.getTime() );
   }

   public Date getStart() {
      return start;
   }

   public Date getEnd() {
      return end;
   }
}

But we can still improve this.  Notice how the check, (assert...) is BEFORE the copy?  Well, when making a defensive copy of constructor argument, you're supposed to FIRST copy and arguments, and THEN check the validity of the parameters.

Why?  Multithreaded code, I'll review that later..

But anyhoo, here's an even BETTER implementation:
public class Period implements FixedEpoch {
   private Date start;
   private Date end;

   public Period (Date start, Date end) {
      this.start = new Date (start.getTime() );
      this.end = new Date (end.getTime() );

      assert (this.start.compareTo (this.end) < 0);
   }

   public Date getStart() {
      return start;
   }

   public Date getEnd() {
      return end;
   }
}

So now this follows the good practice of copying first, then checking

But oh no there's another problem!  --> ALIASING!  Again!  Where???

Notice the return start, return end creates an alias.  We made sure to create new Date objects for start and end, but by calling getStart() or getEnd() the client can still access the internal workings of our Period object.

For example:
Date t1 = new Date (300);
Date t2 = new Date (500);
Period p = new Period (t1, t2);
Date rawr = p.getEnd();



But there is a solution again: defensive copying.  The accessors create a copy of start and end in Period p, and the copy is returned to the client.

Let's try again:
public class Period implements FixedEpoch {
   private Date start;
   private Date end;

   public Period (Date start, Date end) {
      this.start = new Date (start.getTime() );
      this.end = new Date (end.getTime() );

      assert (this.start.compareTo (this.end) < 0);
   }

   public Date getStart() {
      return new Date (start.getTime() );
   }

   public Date getEnd() {
      return new Date (end.getTime() );
   }
}

So we've learned that it's Good Practice to make Defensive Copies.  Alias undermine the privacy of a field, copies prevent aliases to fields.  Blehh aliases
Typical examples of evil aliases are:
   - parameters in constructors and mutators
   - return value from any method
Like the ones we've seen above!

*Note that the benefit we get from creating a safe object costs us in memory and speed.  Creating a new object for each distinct value can get costly

BUT, there are some fields of fields where aliasing is never a concern!  Fields that are primitive!  (int, float, etc.)  Fields that are enumerations!  (suit, colors, etc.)  Fields that are immutable!

What?

Yeah, immutable.  Not mutable.  Where the abstract value can never change.  We want this because aliasing an immutable is safe!  We don't need defensive copies!  (well, not for the class.. we might, inside the internals of the class).

How we do write an immutable class?
Well, don't write mutator methods.
Make all fields private
And if the class has fields that refer to mutable objects:
  - make defensive copies of parameters in constructors and methods
  - make defensive copies for return values from methods
  - like above!
And, note that defensive copies are not needed for fields that are primitive, enumerations, or refer to immutable objects

Think about Period.  It has fields that refer to mutables (Date) so we needed defensive copies.
On the other hand, think about String.  It has methods that look like mutator - toUpperCase(), replace (char, char) but these methods actually return a String

The slides say to declare all fields to be final, and the class to be final.  So I'm not sure why yet but I'll read up on it.  But they DO point out that only the ABSTRACT state needs to be immutable, the concrete state (fields) can change as long as client-side view stays the same.

And the slides also talk about wrapper classes, boxing, and unboxing.. Ugh.  Well all I got was that every primitive type has a corresponding wrapper class.  And boxing.. so boxing goes from primitive to wrapper?  Like Integer integerObject = new Integer(42)
So 42 was the Integer, integerObject is Integer with another layer added on I guess.
And unboxing is opposite, goes from wrapper to primitive.  Like int i = integerObject.intValue();
So integerObject was the wrapper which goes to the primitive int it
And Java does this AUTOMATICALLY

But whatever.  I guess I understand immutability more now.  You basically want it so the client can't inadvertently (or advertently) screw with your code, and so it prevents a lot of bugs that would otherwise be hard to trace.

As Joshua Bloch touts,  a well-designed module is different from a poorly designed module because the well-designed one HIDES its implementation from the user - ENCAPSULATION.  Encapsulation can be also thought of information hiding, and it's useful because it prevents a lot of crap from happening
--> A good way to do this is to make every class or member as inaccessible as possible.  BUT, public classes are allowed to expose constants through public static final fields (this is where names have all capital letters)
--> Basically, should always aim to reduce accessibility as much as possible!!!
Yay.. because this is what immutability is all about.  When you create an instance for an immutable class, it starts as some initial value and STAYS THAT WAY.  It STAYS THAT WAY, does NOT CHANGE.  Establish a class invariant, and stick with it!  Nothing throughout the lifetime of this object will change it.  (Yes I know I'm repeating the same thing over and over again but it took me a while to get this concept straight in my head).
--> Classes should be immutable unless there's a good reason for them to be mutable!  The only disadvantage of immutable classes is the performance, in some cases

Immutability, ladies and gentlemen.