Computer Science 538
Lecture Summary and Notes
February 4, 2000
Lecture by Prof. C. Fischer
Summary by B. Cox
In computer programming languages, "scope" is the fraction of a
program in which a given identifier is valid. It is not common
for a variable to be used before its declaration.
In most languages, the definition takes effect when you see it.
For example,
FLOAT I;
PROC P {
PRINT(I);
INT I;
}
prints a float for the identifier "I".
Generally, you would not want a later declaration to affect an
earlier identifier. This can cause confusion, and allowing such a
thing to be easily done in a language goes against "The Law of
Least Astonishment" (the principle that a program should
do what an outside reader would reasonably expect them to do).
A "forward reference" is when you refer to something that is not
yet seen.
One example of a forward reference is from Java. In Java classes,
you can talk about a method before it is defined, as in the
following rough code structure:
CLASS C {
INT M() {...SUBR();}
INT SUBR()
Here the method SUBR() is called before the program states the
definition of SUBR().
Sometimes a form of forward referencing is necessary. If two
procedures each call one another, then they can't both be defined
first. The languages C/C++ have a special feature for getting
around this.
***********************
"Binding" is the process of determining which value is assigned
to a given variable.
"Lifetime" is how long a given variable lasts within a program.
Closing a variable's scope usually terminates its lifetime.
Sometimes, it is possible to have a lifetime smaller than a
variable's scope.
For example, in Java,
COMPLEX C;
does *not* allocate space for C. You have to write
COMPLEX C = NEW (C);
Java has automatic garbage collection; it deallocates objects for
you, and you have no control over the deallocation. C++, on the
other hand, allows you to dynamically deallocate objects. This is
a common source of errors. For example, in C++,
PROC P
FREE(C);
C.VAL;
the variable C is *still in scope* at the end, but its lifetime
is over! Running this code can produce a segmentation fault.
Sometimes, one may want to extend the lifetime of a variable
beyond its scope. Say you want a procedure to keep track of how
often it is called. Your first attempt is
VOID P() {
INT i = 0;
PRINT(i++);
}
This will NOT keep track of how often "P" is called, because "i"
is renewed with each call. But if you're careful to rewrite this
procedure as
VOID P() {
STATIC INT i = 0;
PRINT(i++);
}
"STATIC" is a keyword that tells C++ to extend the lifetime of
"i" beyond its scope. This procedure will now keep track of how
often it is called. However, you don't want to overuse the STATIC
keyword, because if everything is made STATIC, it is no longer
possible to do garbage collection.
***********************
A "block" is a piece of a program that contains local
declarations and executable code. C/C++ outline blocks
with curly brace symbols. A block is not dynamic/can't be
altered during the program's run time. An example of a block is,
{INT I;
I = I + 2;
PRINT I;
}
An example of a "struct" in C/C++ is
STRUCT S{FLOAT RE, IM;
...
}
A "block" is not dynamic, and a "struct" or "record" can't do
executions. A "class" has the best of both worlds. For example,
in Java,
CLASS COMPLEX {
FLOAT RE, IM;
COMPLEX (FLOAT V1, FLOAT V2)
{RE = VI; IM = V2;}
VOID PRINTIT()
{PRINT("(", RE, ", ", IM, "^)");
}
Constructors only happen after "new" in Java, i.e.
COMPLEX C = NEW COMPLEX(1.0, 2.0);
This can be tricky to learn, as beginning Java programmers
try to figure out why they create a variable and it doesn't work
("What? There's supposed to be a 'new' there?") But it serves a
purpose.
A statement like
C.COMPLEX(2.0, 3.0);
looks like a method, but doesn't have a type. Java outlaws this
statement, because constructors should be called automatically,
not by the user.
***********************
A programmer's dilemma in Java:
CLASS C {...}
C VI, V2;
V1 = V2;
Usually, you want to be able to do this. However, you may
encounter a situation like the following:
CLASS POINT {INT DIMS, FLOAT COORDS[];
POINT(){DIMS = 2; COORDS = NEW FLOAT[2]}
POINT(IND d){DIMS = d; COORDS = NEW FLOAT[d]}
}
POINT PLANE = NEW POINT(2);
POINT SOLID = NEW POINT(3);
PLANE = SOLID;
You don't want to allow this. You want your model of a
two-dimensional plane and your model of a three-dimensional
solid to be non-interchangeable. What do you do?
"Subclassing" takes an existing class and extends it.
"Inheritance" refers to the new class inheriting some or all
features of its parent class. Inheritance allows you to program
less and say more.
So, you use inheritance and subclassing to your advantage, in
something like the following ("SUPER" means "call the constructor
of the superclass"):
CLASS POINT2 EXTENDS POINT{
POINT2{SUPER(2);}
}
CLASS POINT3 EXTENDS POINT{
POINT3{SUPER(3)}
}
POINT2 PLANE = NEW POINT2();
POINT3 SOLID = NEW POINT3();
Now, a declaration like PLANE = SOLID is *not* allowed!
Java also has "reflection," which allows you to ask about an
object ("What kind of Pokemon are you?" :)
Reflection lets you program for objects *before* they exist.
However, reflection can also cause problems with security.
***********************
This is an example of a typical linked list class in Java:
CLASS LINKEDLIST{
OBJECT VALUE;
LINKEDLIST NEXT;
OBJECT HEAD() {RETURN VALUE}
LINKEDLIST TAIL() {RETURN NEXT}
LINKEDLIST(OBJECT O) {VALUE = 0; NEXT = NULL;}
}
LINKEDLIST L = NEW LINKEDLIST(new Integer(123);)
Note that Java has wrapper classes for primitive types: integer,
double, etc. Names of the wrapper classes begin with a capital
letter. For example, the wrapper class for a primitive of type
integer is "Integer." In order to store an integer in a Java
linked list, you first have to put it in the wrapper class.