teaching machines

CS 1: Lecture 16 – Shortcircuiting

October 13, 2017 by . Filed under cs1, cs145, cs148, fall 2017, lectures.

Dear students,

Let’s start with a little number I like to call What Do This Do?. I will show some code, you will inspect it silently for a moment, and then you will argue with your neighbor about what it does. Here we go:

Next up we’ll examine the following piece of code. What is the output from each statement?

public static void main(String[] args) {
  boolean b;

  // Ands
  b = getTrue() && getTrue();  // pretend we output a line break after each of these
  b = getTrue() && getFalse();
  b = getFalse() && getTrue();
  b = getFalse() && getFalse();

  // Ors
  b = getTrue() || getTrue();
  b = getTrue() || getFalse();
  b = getFalse() || getTrue();
  b = getFalse() || getFalse();
}

public static boolean getTrue() {
  System.out.print("T");
  return true;
}

public static boolean getFalse() {
  System.out.print("F");
  return false;
}

It’s my hope that you printed two letters for each statement. However, when we actually run this, we observe that some statements only print one letter. What gives? Well, we know that && requires both its operands to be true. If the first is false, why bother even asking about the second? This is called short-circuiting because we give up early. Short-circuiting is present in most mainstream languages. With ||, if the the first operand is true, who cares about the second?

This idea is not unique to programming. It is fundamental human logic. Suppose you’re crossing a street and there’s traffic in the nearest lane. You needn’t bother even checking the far lane—especially if it’s empty, as you’ll only get frustrated. Suppose you want to bake cookies, but have no chocolate chips. Why bother checking the cupboards for flour and baking powder? These examples are both short-circuited ANDs. Consider this OR: suppose you accept cash or credit. If somebody gives you cash, you don’t also ask for a credit card.

You might think of short-circuiting as just a technical curiosity, but it probably is more important than that. For one, see question 2 at the bottom of this job ad. For two, if often comes in hand to guard against a possible unsafe operation. We might right the dangerous operation as the right operand and the safeguard as the left:

safeguard && unsafe

If the safeguard condition isn’t met, we don’t do the unsafe thing. Consider this unsafe method:

public static boolean hasSameFirstTwoLetters(String s) {
  return s.charAt(0) == s.charAt(1);
}

This is unsafe because s might not have two letters. We can safeguard it:

public static boolean hasSameFirstTwoLetters(String s) {
  return s.length() >= 2 && s.charAt(0) == s.charAt(1);
}

This rounds out our formal focus on the various boolean operators. Next time, we start talking about conditional statements, which use these booleans to decide what to execute next.

Here’s your TODO list to complete before we meet again:

See you next class!

Sincerely,

P.S. Here’s the code we wrote together in class…

FileFoo.java

package lecture1013;

import java.io.File;

public class FileFoo {
  public static void main(String[] args) {
    File file = new File("/Users/johnch/Desktop/cats.png");
    System.out.println(file.getName());
    file.delete();
  }
}

Fairness.java

package lecture1013;

import java.util.Random;

public class Fairness {
  public static boolean isDouble(Random g) {
    return g.nextInt(6) == g.nextInt(6);
  }
  
  public static void main(String[] args) {
    long n = 6000000000L;
    long nDoubles = 0;
    Random g = new Random();
    for (long i = 0; i < n; ++i) {
      if (isDouble(g)) {
//        nDoubles = nDoubles + 1;
//        nDoubles += 1;
//        nDoubles++;
        ++nDoubles;
      }
    }
    System.out.println(nDoubles);
    System.out.println(nDoubles / (double) n);
  }
}

BooleanStuff.java

package lecture1013;

public class BooleanStuff {
  public static boolean getTrue() {
    System.out.print("T");
    return true;
  }
  
  public static boolean getFalse() {
    System.out.print('F');
    return false;
  }
  
  public static boolean hasSameFirstTwoLetters(String s) {
    return s.length() >= 2 && s.charAt(0) == s.charAt(1);
  }
  
  public static void main(String[] args) {
    System.out.println(hasSameFirstTwoLetters("."));
    
//    
//    boolean b;
//    
//    b = getTrue() && getTrue(); System.out.println();
//    b = getTrue() && getFalse(); System.out.println();
//    b = getFalse() && getTrue(); System.out.println();
//    b = getFalse() && getFalse(); System.out.println();
//
//    b = getTrue() || getTrue(); System.out.println();
//    b = getTrue() || getFalse(); System.out.println();
//    b = getFalse() || getTrue(); System.out.println();
//    b = getFalse() || getFalse(); System.out.println();
  }
  
  
}

RectangleUtilities.java

package lecture1013;
public class RectangleUtilities {
  public static boolean isInside(int x,
                                 int y,
                                 int x1,
                                 int y1,
                                 int x2,
                                 int y2) {
    return x1 <= x && x <= x2 &&
           y1 <= y && y <= y2;
  }
  
  
  
  
  
  
  
  
  
  
  
  
  public static boolean isColliding(double leftA,
                                    double rightA,
                                    double bottomA,
                                    double topA,
                                    double leftB,
                                    double rightB,
                                    double bottomB,
                                    double topB) {
    return false;

  }
  
  public static boolean isCollidingHorizontally(double leftA, double rightA, double leftB, double rightB) {
    return false;
  }
  
  public static boolean isCollidingVertically(double bottomA, double topA, double bottomB, double topB) {
    return false;
  }
}

Zomple.java

package lecture1013;

import java.io.File;
import java.util.GregorianCalendar;

public class Zomple {
  public static void main(String[] args) {
    GregorianCalendar cal = new GregorianCalendar(2002, 9, 24);
    File f = new File("sdfdas");
    f.
    System.out.println(cal.getTimeInMillis());
//    System.out.println(cal);
  }
}

DoubleDouble.java

package lecture1013;

import java.util.Random;

public class DoubleDouble {
  public static boolean isSomething(Random g) {
    return g.nextInt(6) == g.nextInt(6);
  }
  
  public static void main(String[] args) {
    Random g = new Random();
    long n = 50000000000L;
    long nDoubles = 0;
    for (long i = 0; i < n; ++i) {
      if (isSomething(g)) {
        nDoubles = nDoubles + 1;
      }
    }
    System.out.println(nDoubles / (double) n);
  }
}

BooFun.java

package lecture1013;

public class BooFun {
  public static boolean getTrue() {
    System.out.print('T');
    return true;
  }
  
  public static boolean getFalse() {
    System.out.print('F');
    return false;
  }
  
  public static String String() {
    return "String";
  }
  
  @SuppressWarnings("unused")
  public static boolean hasSameFirstTwoCharacters(String s) {
    
    
    
    String String = new String(String()).toString();
    
    
    
    return s.length() >= 2 && s.charAt(0) == s.charAt(1);
  }
  
  public static void main(String[] args) {
    System.out.println(hasSameFirstTwoCharacters("?"));
//    boolean b;
//    
//    b = getTrue() && getTrue(); System.out.println();
//    b = getTrue() && getFalse(); System.out.println();
//    b = getFalse() && getTrue(); System.out.println();
//    b = getFalse() && getFalse(); System.out.println();
//    
//    b = getTrue() || getTrue(); System.out.println();
//    b = getTrue() || getFalse(); System.out.println();
//    b = getFalse() || getTrue(); System.out.println();
//    b = getFalse() || getFalse(); System.out.println();
  }
}