slanted W3C logo

Day 07 — Contracts

In today's class we discuss how we can think of an API as being a contract between the client and the component. We will look at some "contracts" from the java.lang.Math utility and use some of its features to solve some simple problems.

Contracts

contract
a binding agreement

In software engineering, the notion of a contract is used as a metaphor for the design and documentation of software components. For example, when a client decides to invoke a method on an object we can think of the client and the object as entering into a contract.

The client has certain obligations:

The method of the object also has certain obligations:

Preconditions

precondition
something that must be true immediately before the method is invoked

Many methods have parameters; that is, they require the client to supply arguments (data) to the method. Often, the method will have conditions attached to the parameters. For example, the fictitious method:

double squareRoot(double x)

might require that the parameter x always be greater than or equal to positive zero. Such a condition is called a precondition, because it must be true before the method can be successfully invoked.

It is the client's responsibility to ensure that the precondition is true. If the client fails to ensure the precondition, then there are no guarantees on the behavior of the method.

Postconditions

postcondition
something that must be true immediately after the method returns

If the client satisfies the preconditions then the method must meet its contractual obligations. Satisfying the postconditions is the responsibility of the method.

Example with Precondition

double squareRoot(double x)
Returns the positive square root of a double value.

Parameters:
x – a value

Precondition:
x >= 0.0

Returns:
the positive square root of x

Postcondition:
the return value is as stated above

Example without Precondition

double squareRoot(double x)
Returns the positive square root of a double value.

Parameters:
x – a value

Precondition:
true

Returns:
the positive square root of x

Postcondition:
the return value is as stated above if x >= 0.0;
the return value is NaN otherwise

Normally we omit the Precondition section if there are no preconditions.

Normally, the Postcondition section is merged with the Returns section.

double squareRoot(double x)
Returns the positive square root of a double value.

Parameters:
x – a value

Returns:
the positive square root of x if x >= 0.0;
NaN otherwise

Example with Exception

Notice that computing the positive square root of a value requires that the value be greater than or equal to 0.0; this condition can be verified inside the squareRoot method at runtime.

One way to deal with the case where a client asks for the square root of a negative value is to indicate to the client that an error has occurred. The mechanism for doing so in Java is to throw an exception object.

An exception object is a particular type of object that contains information about the nature of the error. When an exception is thrown, the method stops execution (i.e. it does not return a value) and the runtime system searches for a client that is willing to handle the exception; if no client can be found, the program will terminate (with some sort of error message hopefully).

A method that might throw an exception when it detects an error will advertise this fact in its API. For example:

double squareRoot(double x)
Returns the positive square root of a double value.

Parameters:
x – a value

Returns:
the positive square root of x if x >= 0.0;

Throws:
IllegalArgumentException if x < 0.0

Example from the java.lang.Math Utility

The java.lang.Math methods do not have any preconditions nor do they throw any exceptions.

double sqrt(double a)
Returns the positive square root of a double value. Special cases:
If the argument is NaN or less than zero, then the result is Nan.
If the argument is positive infinity, then the result is positive infinity.
If the argument is positive zero or negative zero, then the result is the same as the argument.
Otherwise, the result is the double value closest to the true mathematical square root of the argument value.

Parameters:
a – a value

Returns:
the positive square root of a. If the argument is NaN or less than zero, the result is NaN.

import java.io.InputStream;
import java.io.PrintStream;
import java.util.Scanner;

public class SqrtExample
{
   public static void main(String[] args)
   {
      InputStream in = System.in;
      PrintStream out = System.out;

      Scanner input = new Scanner(in);

      out.print("Enter a number to find its square root: ");
      double value = input.nextDouble();
      double root = Math.sqrt(value);
      out.print("The square root is: ");
      out.println(root);
   }
}

Hangtime

Elite basketball players seemingly defy gravity by hanging in the air.

In his prime, Michael Jordan's vertical leap was approximately 1.2 meters. Assuming that the acceleration due to gravity is g = 9.8 m/s2, MJ would have to jump vertically with an initial velocity of v0 = 4.8497 m/s to acheive a maximum height of 1.2 meters.

How much time does MJ spend in the top 20 cm of his jump?

To solve this problem, you need to solve the following equation for the time t:

(1/2)gt2 - v0t + 1 = 0

Recall that the quadratic formula solves for the roots of a quadratic equation.

Note: The total amount of time MJ spends in the air is 0.9897 s

Constants

On occassion, you will find that your programming problem involves a literal value such as 12 (the number of months in a year), 3.1415 (pi), or in this case 9.8 (acceleration due to gravity). You should avoid using the literal values and create a named constant instead.

In Java you create a constant value by declaring a variable as final. The keyword final means that the variable can only be assigned to once. By convention, the names of final variables are spelled with capital letters:

public class Hangtime
{
   public static void main(String[] args)
   {
      final double ACCEL_G = 9.8;
      final double INITIAL_VEL = 4.8497;
      
   }
}

You should try to solve the rest of the problem.

Rocket Mass Ratio

The mass ratio of a rocket is defined as the mass of the fuelled rocket (plus payload) divided by the mass of the unfuelled rocket (plus payload). Using the ideal rocket equation, the mass ratio can be derived as:

eΔv/ve

where Δv is the change in the rocket's velocity and ve is the effective exhaust velocity. To achieve low earth orbit, the value of Δv is approximately Δv = 10 km/s.

Write a Java program that asks the user for a rocket's exhaust velocity and outputs the mass ratio. You will find the following features in java.lang.Math to be useful:

static final double E
The double value that is closer than any other to e, the base of the natural logarithms.

static double pow(double a, double b)
Returns the value of the first argument raised to the power of the second argument.
Lots of special cases here...
Parameters:
a – the base
b – the exponent

Returns:
the value ab

Self Check

  1. Key concepts at the end of Chapter 2.
  2. Review questions at the end of Chapter 2.

To Do For Next Lecture

  1. Read Sections 3.1 and 3.3 in the textbook.