5. Expressions, Types, Messages

Key concepts

  1. Expressions and evaluation
  2. Statements, sequences of statements.
  3. Arithmetic operators
  4. Kinds (types) of things
  5. Errors: syntax, semantic, pragmatic
  6. Argument evaluation
  7. Input and Output

Story

Let's quickly review what we know. We know how to create new objects. We know how to name objects. We know how to send simple messages to objects. In this lesson, we'll do more of the same, but we'll scale it up a little bit.

Expressions and arithmetic operators

Circle theBall = new Circle(10, 20, 30);
The stuff on the left of the '=' is the kind of thing we are naming and the name we have chosen. But what's that stuff on the right? What happens to it? Before we give the thing a name we need to figure out what it really is. To figure out what something really is, we need to evaluate it. Evaluation just means that the stuff we write (which we call an expression) is allowed to express its true self. What kinds of expressions can we write? An expression can be:
  1. a literal representation of an object
  2. the generation of a new object (using new)
  3. the name of an object
  4. the result of sending a message to an object
  5. combinations of the above
Here are some example expressions:
1
"hello"
aSquare
aSquare.width()
new Square(10, 20)
The first two items are literal representations of objects; the third is a name of an object; the fourth is a message send; and the final line shows a request to have a new object created.

We can now slightly formalize our naming pattern:

<The kind of thing> <the name> = <expression>;

Arithmetic operators

Java provides us with mathematical operators that allow us to write mathematical expressions. The basic operators are:

SymbolMeaningExample ExpressionValue if y is 11
+addy + 516
-subtracty - 56
*multiplyy * 555
/dividey / 52
%remaindery % 51

We sometimes call the operators in the above table binary operators because they operate upon two subexpressions. What if I want to negate a value? In Java you can use the minus symbol in a unary manner to do this, just like in regular math:

 
int q = x * - y;
Mostly, these operators work just like they work in normal math, with the standard precedence rules. If you're unsure about precedence, you can always use parenthesis to make yourself sure. Here are some examples:
int y = 4;                 
int x = 2;
int m = x + y * 8;       // Q: What's the value of m? A: 34
int n = (x + y) * 8;     // Q: What's the value of n? A: 48
Wait, what's the weird stuff after the "//" on the right? If you think it doesn't really look like Java, you're right. Java lets us add comments to programs which it dutifully ignores. A comment serves to make a program more readable to another human. Everything from the "//" to the end of the line is ignored by Java.

Note that division between integers behaves somewhat differently than you might expect. If I ask you, "What is 5 divided by 2?", you'll correctly answer "Two and a half". But now, let's look at the following Java fragment:

int x = 5;
int y = x / 2;    // Q: What's the value of y?  A: 2
In the above example, we're in a little bit of a pickle because y is an integer. It can only represent whole numbers. "Two and a half" is not a valid Java int any more than it is a valid real world integer. So what happens? Java will truncate (ie. drop) any remainder that results from a division between integers. Hence, the result that y will be bound to is two.

What if we want to know the remainder? Java provides us with an operator that can answer this question for us. It's called the remainder or sometimes the modulus (or just mod for short) operator. Here's an example:

int x = 5;
int y = x / 2;
int theRemainder = x % 2;
Depending on the scenario, it may be appropriate to use a different kind of number that can represent fractions, such as the double.
double x = 5;
double y = x / 2;  // Q: What's the value of y?  A: 2.5
What happens if we write the following:
int x = 5;
double y = x / 2;  // Q: What's the value of y?  
Try it and see. Is the answer what you expected? Why or why not?

Types: Kinds of things

Let's look at a few expressions again. Notice that you can tell me what "kind" of thing each of these expressions evaluates to.

"hello"
aSquare
aSquare.width()
aSquare.length() * 23
In Java, when we give a thing a name, we have to be sure that we also say what kind of thing we're naming. That's why we're always saying something like this during naming:
String greeting = "hello";
The word String is there to state what the kind of thing it is that we're naming.

It doesn't make much sense to say something like: "Her age is green." In that sentence there's a mismatch between "green" and "age". What is it? When we think of age, we think it should be a quantity, a number. But "green" is a color. They're not the same "kind" of thing, so it seems like non-sense. From now on, we'll use the term type to mean "kind of thing." Java is very picky about this kind of non-sense (we'll call them type mismatches) and will catch us on it every time. For instance, Java will gripe about the following:

String greeting = 7;
int someNumber = "hello";
Although it may seem annoying at first, this is actually a good thing. For one thing, imagine what would happen if Java let you add Strings and numbers. What would the meaning of that be? Since it is never the case that a programmer intends to mismatch types, the Java language rightly forbids it in practice.

Errors: Syntactic and Semantic

Let's enrich our taxonomy of errors by looking at some excerpts harvested from that most fertile field of mistaken speech, the words of President George W. Bush.
  1. Is our children learning?
  2. We ought to make the pie higher.
  3. He can't take the high horse and then claim the low road.
Each of them fail to convey meaning, but for different reasons. The first Bushism clearly contains a "grammar" mistake. In Java we call this a syntactic error. Here are some examples:
int x 7;
int velocity = distance / ;
String foo = "hello" 56;
The second Bushism contains a semantic error: we think of pies getting bigger and smaller, but we don't typically think of pies getting higher any more than we think of plants screaming, or pigs flying. Semantic errors in Java are usually type mismatches. Here are a few:
String myName = 7;
aSquare.move("hello");  // assume the move method wants an integer!
int area = length * "width";  
The third Bushism is more subtle, and we may call it a pragmatic error. It reflects an unconventional usage of the English language. An equivalent in Java would be poor coding style. Incomprehensible variable names or poor formatting might make your program difficult or impossible to read, even though it's legal by the rules of the Java language.

Sending information with messages

Recall our basic pattern for sending a message:

<object-name>.<message-name>(<some information>);
When we send messages to objects, we often pass along some other objects that are required for it to answer in an interesting manner. For instance, if we want to move a square, the square wants to know how far to move. If we add something to a collection, the collection needs to know what to add. The objects we pass along with the message are called arguments or parameters. Note that messages are often really picky about what kind and number of arguments are acceptable. For example, if we ask a rectangle to move, passing along two numbers seems reasonable. For instance:
aRectangle.move(10, 20);
What happens when we pass along another rectangle or a String?
aRectangle.move("hello", 20);   
aRectangle.move(35);
Neither of the above statements make sense to us, and they don't make sense in Java either. The first makes no sense because the move message expects two integers, but we have provided a string and an integer. This is an example of a semantic error. The second makes no sense because we have only provided one parameter, in a situation where two were expected. This is also an example of a semantic error.

While we can often intuit what kind of arguments are acceptable, to really figure out what kinds of arguments are acceptable, we need to look at the interface (or sometimes signature)of the method. An interface to a method is a description of the behavior of the method. It defines the the name of the method itself, the number and types of arguments required by the method, and the type of object returned by the method, if any. Often, the interface will also consist of some commentary which describes the behavior or semantics of the method. Here is an example, for the move and area methods for Rectangles:

// Change the position of the shape by the given deltas.
//  parameters:
//    deltaX: the X distance to move
//    deltaY: the Y distance to move
void move(int deltaX, int deltaY);

// Answer the area of the shape.
int area();
The keyword void means that the move method does not return or answer with any value. The interface shows us the pattern that we must follow if we are to call the method correctly. In particular, for the move method it states that we must provide two arguments, both integers. Furthermore, it defines the meaning of those two parameters. The interface to the area method, tells us that it takes no parameters but returns a value, an integer, which is the area of the rectangle.

Before the message is sent, the expressions that represent the arguments are evaluated. Look at the following example:

aRectangle.move(10, aRectangle.width() / 2);
Both arguments are evaluated before the message is sent. Of course, the first expression isn't very interesting, and it just evaluates to the number 10. The second evaluates to half the width of the rectangle before being sent. We can now formalize our message sending pattern:
<object-name>.<message-name>(<expressions>);

where
  <expressions> is zero or more expressions depending on the
  interface of the method. 

Doing a series of things

We often need to do things that require more than one step: baking a cake, washing our hair, changing the oil in the car. Java allows us to express this notion by stringing together statements. Think of each statement as a command to the machine. Each statement is executed, and when it's finished executing, the machine executes the next one. Let's string together some statements that get something interesting done.

 
int width = 20;
Rectangle square = new Rectangle(width, width);
square.move(35, 10);
Notice that we separate statements by using semi-colons. The semi-colon is similar to the full-stop "." in written English. It is used to separate sentences. Java isn't picky about how we write our statements, but its considered bad style to put more than one statement on a single line. Why? Look at the above example rewritten:
int z=20;Rectangle square=new Rectangle(z,z);square.move(35, 10);
Notice that we have not only placed all three statements on one line, but we also not chosen very good names. We've managed to make it very difficult to understand what this fragment is supposed to do.

Input and Output

Nearly every interesting computer system allows the user to interact with it in some manner. When we use an ATM machine, we press buttons on a keypad to request a withdrawal and enter an amount. The ATM machine then may inform us that we have insufficient funds in our account, by displaying a message onto a screen. We call the consumption of information by a program input and the production and display of information output

In today's computer systems, input typically comes from the keyboard and/or a pointing device called a mouse, and output goes to the computer screen. However, there are other unseen sources of input and destinations for output, such as files that hold data on disk drives, network devices that allow our computers to communicate with each other, and printers.

We'll hide many of the details of doing input for now, and imagine that we have a simple interface for performing input. Here is the interface for reading an integer. Reading other simple values occurs through a similar interface.

// Prompt the user and read and return an integer
// If they do not provide an integer, they are re-prompted.
// parameters:
//  prompt:  a String to display
int readInt(String prompt);
Here's a sample interaction (in the interpreter), using this interface.
prompt> Input input = new Input();
prompt> int width = input.readInt("What is the width of the box?");
What is the width of the box?
8
prompt> int height = input.readInt("What is the height?");
What is the height?
hello
Not a valid integer, please try again.
4
prompt> int area = width * height;

Performing simple, textual output in Java is pretty simple, although the syntax may seem a little strange for now. The system provides us with a well-known object, called System.out that has the following simple interface.

// Print a textual representation of the given object,
// followed by a newline (carriage return)
// parameters:
//  o: any object to display
void println(Object o);

// Print a textual representation of the given object,
// without a trailing newline
// parameters:
//  o: any object
void print(Object o);
Here's another sample interaction (in the interpreter), using this interface.
prompt> Rectangle r = new Rectangle(10, 20, 30, 40);
prompt> System.out.println(r)
[Rectangle: x=10, y=20, width=30, height=40]

Patterns we've refined

  1. Naming
  2. Sending messages
  3. Creating new objects

Ben Dugan & UW-CSE, Copyright (c) 2001.