
First Summer 2004

Lecture Notes Five: Syntax. The structure of main
.
What is a number?

That much we know.

Let's say: an integer or a floating point number.

We know all about integers and floating point numbers,
I'd say.

What is an operator?

You want a long answer or a short one?

Short.

+ ,  , * , / are operators.

What is an expression?

A number, is a (very simple) expression. A symbolic name is
also a (very simple, or atomic) expression.

What is an expression followed by an
operator followed by another expression?

That would also be an expression, wouldn't it?

Yes, indeed. What do we have so far?

We have this table:

Term defined  Composition 
expression  number 
 variable 
 (expression operator expression)


Do we need the parentheses?

Not really, but we want to emphasize the structure.

Correct. Now, is ((3 + 4) * a) an expression?

It is. Do you want to show why with a diagram?

I sure do.

Very well, there you go:

That's interesting that we can define a concept
(such as expression) in terms of itself.

This is called a recursive definition. An
important part of a recursive definition is specifying
a set of fixed points,

... without which defining
something in terms of itself could go on for ever.

Exactly. Thank goodness for numbers and
variable names without which our definition
would be irreversibly circular.

What is an assignment statement?

Its structure is as follows: variable name, followed
by an equal sign, followed by an expression,
and then by a semicolon.

a = 3 + 5;
a = b;
r = new Rectangle(2, 2, 10, 10);
What are we trying to get at?

The structure of all Java programs.

What is a declaration?

It is a type, followed by a variable name and a
semicolon...

int m;
Rectangle r;
double x, y, z;

I see you can declare several variables at the same time.

Yes, that's relatively obvious by now, I hope.


... and it can also be
a type, followed by an assignment statement
(as defined above).

You should be building a few examples following these definitions,
or take some statements and analyze them the way we analyzed the simple
expression a few lines above.

int m = 25;
int n = 34, p;
Rectangle r = new Rectangle (5, 10, 8, 16);
OK, I see what you're getting at, let's move on.

Are we really going to be extremely precise and cover all possible cases?

Not really. For that we'd have to sacrifice some of the intuitive structure
of all these.

But we'll go far enough for you to get a good grasp of the general
structure.

Are you ready for something really deep?

Go ahead.

What is a function call?

A function name followed by open parenthesis, followed by zero or
more arguments separated by commas, followed by closed parenthesis.

System.out.println();
System.out.println("Wow!");
Math.sqrt(2);
r.translate(3, 3);
What is an argument?

I suppose any expression would work as one.

System.out.println("tom" + "ate".substring(0, 2) + "a dog".charAt(3));
I've seen length() and substring() being
invoked on String s, but what's charAt() ?

Exactly what you're thinking that it might be.

Based on its name?

Yes. And we'll talk more about char s tomorrow.

OK, let's summarize what we have so far:


Term defined  Composition 
expression  number 
 variable 
 (expression operator expression)

funCall  funName ( ) 
 funName ( arguments ) 
arguments  expression 
 expression, arguments


Any questions about function names?

Not really, I suppose they're basically
of the "absolute path" kind, like
System.out.println

Good assumption.

Are function calls expressions themselves?

I'm glad you asked. The answer is "yes" if the function returns a value.

Then we are now dealing with an even bigger infinity of expressions.

Note though that not all functions return values.

Yes, println from System.out does not
return a value, but sqrt from class Math
returns the square root of the argument, so it can be used in an
expression.

Let's update our table. We'll put a star ^{(*)} next to
remind ourselves that it's a logic error to use a function
call in an expression if the function does not return a value.


Term defined  Composition 
expression  number 
 variable 
 (expression operator expression) 
 funCall ^{*} 
funCall  funName ( ) 
 funName ( arguments ) 
arguments  expression 
 expression, arguments



The update is minimal, but I think I need to
look at more examples before I become too dizzy.

You've already seen examples of expressions, as defined by the table above.

This table is a table of syntactic categories described in terms of other syntactic categories,

... an enterprise aimed at describing the (grammatical structure of our simple) language.

Here are some more examples of expressions.

Take them apart, fit them in the table, don't just accept them and then move on.



Don't worry. Let's take a look:

Math.sqrt(a + Math.sqrt(b))
This is easy:


Math.sqrt(Math.sqrt(Math.sqrt(Math.sqrt(a))))
Just as easy:


Math.pow(a, (1.0 / 16.0))
Same as above:


Math.sqrt(Math.pow(Math.sqrt(Math.pow(Math.sqrt(2)), 2)), 2)
A bit messy, perhaps, but easy:


(6 + (5 + (4 + (3 + (2 + 1)))))
A statement is a
 declaration or
 an assignment statement,



Or a function call, as in:

System.out.println("Hello, world!");
public class Template
{ public static void main(String[] args)
{
<methodBody>
}
}
It's the template we're using, and methodBody
is composed of one or more statements.

That is, declarations and statements
in any order, with the following final table describing the
entire structure of the language (so far).

Term defined  Composition 
statement  declaration 
 assignment 
 funCall 
declaration  type variable ; 
 type variable = assignment ; 
assignment  variable = expression ; 
expression  number 
 variable 
 (expression operator expression) 
 funCall ^{*} 
funCall  funName ( ) 
 funName ( arguments ) 
arguments  expression 
 expression, arguments


This table covers the syntax of the Java programs that we
are going to be writing for a while.

Note that not all syntactically correct programs are logically correct.

For example declaring a variable a twice is
a semantic error, although having two declarations
in a program is not a syntactic error...

... but if the variable is one and the same the semantic part
of the compiler will signal that.

Suppose you compile and run the program below.

What's its output?

class One {
public static void main(String[] args) {
int m = 2;
System.out.println(m);
int m = 3;
System.out.println(m);
}
}
The program won't compile.

One cannot declare a variable twice.

All right, let's move on. Have you heard of the
latest late policy on assignments and such?

There's no new policy, everything is still the same:
you need to turn everything on time. Try your best to
meet the deadlines.

Just trying to get your attention.

Sure. Let's move on.

Fine. What is an int ?

It's an integer number between 2^{31} (which is about 2 billion)
and (2^{31}  1). If you need to refer to these boundaries in your program,
use the constants Integer.MIN_VALUE and Integer.MAX_VALUE

... which are defined in a class called Integer like Math.PI is
defined in the Math class.

Convention says: name your constants using all caps
for the name of the constant.

How do you define constants?

Mark them final when you declare them.

Here's a program, what does it produce:

Overflow.

public class Test
{ public static void main(String[] args)
{ int n = Integer.MAX_VALUE;
System.out.println(n);
n = n + 1;
System.out.println(n);
}
}
Have you run it?

Yes, it's an eyeopening experience.

Why does it happen?

Representation is finite.

What if we need bigger integers?

Use long .

What's a long ?

It's a type that allows for the representation of bigger integers. The range is
now 2^{63} (which is about 9 billion billions) to (2^{63}  1).

What if we need bigger integers?

Then work with objects of class BigInteger .

How do I do that?

We'll see that in a minute. What is a floatingpoint number?

A double or a float .

float spans the range from 3.4E38 to 3.4E38. double
is much wider: from 1.7E308 to 1.7E308 but both suffer from the same problem:

... precision.

Yes, what's the output of this program?

public class Test
{ public static void main(String[] args)
{ double a = 30000000000000000000000.0;
System.out.println(a  (a  0.5));
}
}
It should be 0.5 by algebra.

Yes, but is that what the program prints?

Try it.

Also, try to initialize the double variable
with a value that doesn't contain the decimal point.

In that case the compiler catches the overflow before it happens.

Overflow happens even for double type.

The following program produces Infinity .

You're kidding me!

public class Test
{ public static void main(String[] args)
{ double a = 1.5E308;
System.out.println(a * 10);
}
}
For most of the programming projects in this book, the limited
range and precision of int and double
are acceptable.

Just bear in mind that overflow or loss of precision occur.

Another kind of loss of precision occurs in what is known as a
roundoff error.

What's that?

In the processor hardware, numbers are represented in the binary number system,
not in decimal.

You get roundoff errors when binary digits are lost, they just may
crop up at different places than you might expect.

Here's an example:

Another eyeopener.

System.out.println(4.35 * 100);
What do we do?

Keep a cool head. For example in this last case first round
then cast to an int ...

... if you want an int , ...

... and especially if you want the right one.

How about

Slightly off...

System.out.println(Math.pow(Math.sqrt(2), 2));
That's different, but related.

Yes, and we'll discuss how floatingpoint numbers should be tested for equality soon.

How do you use big numbers?

If you want to compute with really large numbers, you can use
big number objects.

Big number objects are objects of the BigInteger and BigDecimal classes in the java.math package.

Unlike int or double ,
big numbers have essentially no limits on their size and precision,

... however, computations with big number objects are much slower than those
that involve primitive types. To perform operations you need to use methods


add

subtract

multiply and

divide

... that big number objects have.

Here's
a + b * c
with big numbers.

import java.math.*;
public class Test
{ public static void main(String[] args)
{ BigInteger a = new BigInteger("100000000000000000000000000000000000000");
BigInteger b = new BigInteger("200000000000000000000000000000000000000");
BigInteger c = new BigInteger("300000000000000000000000000000000000000");
BigInteger d = a.add(b.multiply(c));
System.out.println(d);
}
}
This is good exercise in object notation.

You bet. We've seen rectangles, strings, and now
big numbers. We're getting even better.

So what should we have achieved by now?

I think we understand integer and floating point numbers.

We're able to write arithmetic expressions in Java.

We can appreciate the importance of comments and good code layout.

We can define and initialize variables and constants.

We know of the limitations of int and double types,

... and the overflow and roundoff errors that result.

We can read program input with ConsoleReader .

We know how to print program output.

We understand the structure of a method body ,

... which contains statements, such as declarations, assignments,
and function calls.

We've also talked about expressions.

We have used the String class to define and manipulate strings.



By the way can you draw a picture for me for the following situation:

String a = "Hello!";
String b = a.toUpperCase();
I sure can:

Thanks. It is the same with substring , isn't it?


I know it is. String objects are called immutable objects.

That's right: toUpperCase on a String works
like add on a big number...

... or like intersection on a Rectangle .

Last updated: May 12, 2004 by Adrian German for A201