Graphic by Keith Ohlfs

CS111, Wellesley College, Fall 1999

Problem Set 4

Due: Friday, October 15 by 4:00 p.m.

[CS111 Home Page] [Syllabus] [Lecture Notes] [Assignments] [Programs] [Documentation] [Software Installation] [FAQ] [CS Dept.] [CWIS]

Problem Set 4

Reading on Style

A programming task involves many decisions. We get to choose names for variables, parameters, and methods. We figure out what the patterns are and whether or not we create methods for them. A good programming style produces code which is easy for others to understand. Some general guidelines follow:

Reading on Invariants

When we write methods, we need to define for ourself and others how we expect our environment to be before and after the method. If the method takes an action that affects objects in Object Land, the actions must be clearly defined. On the other hand, if the method is used to ask questions about objects in Object Land, it should not change the state of the environment. We say, in this case, that the method meets an invariant.

As an example, let's write a method that will determine if there is a wall to our buggle's right. Well, we could do the following:

public boolean isWallToRight () {
  this.right(); // turn right
  return isFacingWall(); // return the result from asking if we're facing a wall
}
So, what's wrong? Well, nothing initially, the method does give us the answer we want. However, things get confusing if we try to use it in a program. After we've asked the question, our buggle is no longer facing its original direction. Instead, it's facing the direction that's to the right of its original direction. Ok, no problem. Let's do the same thing for figuring out if there is a wall to our buggle's left:
public boolean isWallToLeft () {
  this.left(); // turn left
  return isFacingWall(); // return the result from asking if we're facing a wall
}
Again, this works. However, if you ask the buggle if there is a wall to its left, it will end up facing the direction left of its original direction. Where is the problem? Let's say we want to figure out whether or not our buggle is in a hallway. Our buggle is in a hallway if there is a wall to the left and to the right of the buggle. So, let's define a new method called isInHallway like so:
public boolean isInHallway () {
  return (isWallToLeft() && isWallToRight());
  // buggle is in hallway if there is a wall to the left and to the right
}
Does this work? No. Why not?
Well, let's assume that the buggle is in the middle of a hall (so there is no wall in front or behind). When we ask isWallToLeft, the buggle turns to the left and answers true. Now when we ask it isWallToRight, the buggle turns to the right and gives us what answer? Well, the buggle is now facing it's original direction with no wall in front, so it tells us false. Therefore, our method isInHallway also returns false (since true && false = false). In order for our isInHallway method to work, we need to have the buggle figure out whether there are walls to its left and right without changing its position. It's not really possible to do so without changing the buggle's position, but we can put the buggle back into its original position before answering the question. So, the better way to write isWallToLeft and isWallToRight follows:
public boolean isWallToLeft () {
  this.left();    // turn left
  boolean result = isFacingWall(); // store result from inquiry
  this.right();   // return to the original position; undo the this.left()
  return result;
}

public boolean isWallToRight () {
  this.right();   // turn right
  boolean result = isFacingWall(); // store result from inquiry
  this.left();    // return to the original position; undo the this.right()
  return result;
}
With the redefined methods above, our isInHallway method will now work correctly.

Moral of the story: Methods that answer questions about the state of the environment should not change the state of the environment!