Title: Programming Languages: Design, Specification, and Implementation
1Programming LanguagesDesign, Specification, and
Implementation
- G22.2210-001
- Rob Strom
- November 2, 2006
2Administrative
- Alternative mailing address for me
robstrom_at_us.ibm.com - Everyone should subscribe to the class mailing
list http//www.cs.nyu.edu/mailman/listinfo/g22_2
110_001_fa06 - Reading
- Pierce, ch 9, simple typing 11 extended typing,
22 type inference, especially 22.4 unification. - DONT DO THIS AT THE LAST MINUTE!!! Its VERY
formal. - Useful online tutorial A Gentle Introduction to
ML - http//www.dcs.napier.ac.uk/course-notes/sml/manua
l.html - Bring up your grade Resubmit programming
projects - Simple Homework (due next class)
- Convert doubly linked list implementation into a
GENERIC one that will take multiple types - Prof. Schonberg will give next weeks lecture (ML
and Type Inferencing) - Homework assignment for ML will be posted on the
website - Polymorphism Project (due 2 weeks after now) BUT
START NOW!!!! - Come to office hours for help!
3Polymorphic Programming Project (2 weeks)
- This project builds a system exploiting
polymorphism. Choose one of the 3 languages C,
Ada, or Java to do it. - This system models a world composed of the
following kinds of objects - rooms they have doors to neighboring rooms, and
access to factories - factories (they create objects)
- solids (coins, keys, bags, pots), some of which
are containers (bags, pots, jars) - liquids (water, juice) must be in a container,
can only be transferred with a funnel - doors (they transfer solid objects from one room
to a neighbor) - funnels (they transfer liquids from one container
to another) - Objects have attributes (weight, mass), and
different kinds enforce different restrictions. - You manipulate things by repeatedly choosing a
room, and giving it a script that can do any of
these things in that room - Ask factories in the room for things by name
e.g., you can ask for 10 keys different
factories might return different weight keys, or
might return them in a bag inside a package, etc.
- You can ask containers whats inside them.
- You can remove solid things from inside
containers you have in the room with you. You can
insert solid things from the room into
containers. A container will complain if its
capacity is exceeded, or if you are trying to mix
solids and liquids in the same container. - You can transfer x amount of liquid from one
container to another, by invoking a method on a
funnel It will complain if there is too little
liquid in the source container or if the
receiving container doesnt accept that kind of
liquid. Usually containers will not accept
liquid if they are also holding solids. - You can ship a container (and by implication,
everything in it) from a room to a neighbor by
invoking a method on one of the rooms doors. - Use polymorphic programming to
- Configure a network of at least 5 rooms with
doors between them, and different kinds of
factories in each - Design different kinds of solid objects,
containers, and liquids, with different
properties (at least 3 of each). Example pot1
can hold solid up to 5 pounds or liquid up to 10
ounces, but not both solid and liquid. - Write a variety of scripts to obtain things from
factories, extract their contents from
containers, repackage them and ship them to
neighboring rooms, and then go to the neighboring
rooms and unpackage them again.
4Programming Languages Core Exam
- Syntactic issues regular expressions,
context-free grammars (CFG), BNF. - Imperative languages program organization,
control structures, exceptions - Types in imperative languages strong typing,
type equivalence, unions and discriminated types
in C and Ada. - Block structure, visibility and scoping issues,
parameter passing. - Systems programming and weak typing exposing
machine characteristics, type coercion, pointers
arrays in C. - Run-time organization of block-structured
languages static scoping, activation records,
dynamic and static chains, displays. - Programming in the large abstract data types,
modules, packages and namespaces in Ada, Java,
and C. - Functional programming list structures, higher
order functions, lambda expressions, garbage
collection, metainterpreters in Lisp and Scheme.
Type inference and ML. - Object-Oriented programming classes,
inheritance, polymorphism, dynamic dispatching.
Constructors, destructors and multiple
inheritance in C, interfaces in Java. - Generic programming parametrized units and
classes in C, Ada and Java. - Concurrent programming threads and tasks,
communication, race conditions and deadlocks,
protected methods and types in Ada and Java.
5Java Interfaces
- A reference can have interface type rather than
class type. - Classes not only inherit their behavior and
interface from their superclasses, but also they
may explicitly declare that they obey one or more
additional interfaces, e.g. - / This interface defines a method any "SMILE
Timer Handler" must support - public interface ISMILETimerHandler
- public void processTimeout(long / TimerID /
timerID)... - Lots of different classes can implement
ISMILETimerHandler, even if they have no
inheritance relationship among them. For
instance, - public class SMILECollectionService extends
SomeSuperClass implements ISMILETimerHandler, ...
... - public class OutstandingSync extends
SomeOtherSuperClass implements ISMILETimerHandler,
... ... - At any time, an object of type SMILECollectionServ
ice, or OutstandingSync, or any other class that
implements ISMILETimerHandler, can be stored in a
reference variable of (interface) type
ISMILETimerHandler, e.g. - ISMILETimerHandler foo new SMILECollectionServic
e(...) - Reference foo can be stored, copied, passed to an
object, and later, methods on reference foo can
be invoked, e.g. foo.processTimeout(nnn) - The caller of foo has no idea what class of
object is going to be called. The call is
completely polymorphic. All that is known at
compile time is that whatever class will
implement the call, it will be a class that
implements the interface.The actual dispatch will
happen at run-time, based on the class of the
object referenced by foo. - Security exposure If you have an interface, and
you can guess the class name, you can cast the
interface to the class and have access to other
operations!!! ?
6But Ada doesnt have interfaces!How can you get
the effect?
type X is private procedure a() procedure
b() procedure c(...) procedure d()
type Y is private procedure c() procedure
d() procedure e() procedure f()
- Given 2 unrelated classes, X and Y
- Generate a class for interface CDInt. It is the
root of a class hierarchy for different actual
classes
type CDInt is abstract tagged private
procedure C(arg CDIntClass) procedure D(arg
CDIntClass)
type CDIntForX is new CDInt with private
private type CDIntForX is new CDInt with
record theX access X procedure C(arg
CDIntClass) is begin C(theX.all) end
- Generate classes for an object which delegates C
or D calls to X or Y. These classes inherit from
CDInt
- At runtime, get an instance of CDIntForX or
CDIntForY, by calling a method on an X or Y.
Assign it to a polymorphic variable intRef.
anX X intRef CDIntClass
getCDInt(anX) C(intRef)
7How this looks at runtime
Caller C(intRef)
A CDIntForX object anX access X
An actual instance of type X
8Exceptions
- Builtin, e.g.
- Running out of memory
- Division by zero
- User-defined, e.g.
- NoSuchEntry
- BufferFull
- Raising an exception causes a block or procedure
to abnormally terminate, and to signal the
particular exception (possibly with a message) - A containing block or caller in the dynamic chain
will catch the exception and either take
alternative action or reraise it - Advantages
- If a function is supposed to return something, or
a procedure is supposed to initialize or modify
something, and it doesnt do it, it should not be
able to return to a context where it is assumed
it has done its job. - Simply returning a return code is not enough,
because programmers will forget to check it. - Differences Ada-C exceptions not on
interfaces, Java puts them on interfaces, except
RuntimeExceptions Ada exceptions are not
objects. Java try-finally block to allow contexts
to do context-specific finalization
9Exceptions example
- public class Caller
- void run()
- Callee foo new Callee()
- try
- PrintStream s foo.open()
- try
- double a Math.random()
- double b Math.random()
- double c Math.random()
- double root foo.getRoot(a, b, c)
- s.print(The answer is root)
- System.out.println("The answer is " root)
- finally
- s.close()
-
-
- catch (Callee.NoRealRoot e)
- System.out.println("Had to give up because "
- e . getMessage())
- public class Callee
- public static class NoRealRoot extends Exception
- NoRealRoot(String reason) super(reason)
-
-
- double getRoot (double a, double b, double c)
throws NoRealRoot - double discriminant bb - 4ac
- if (discriminant lt 0)
- throw new NoRealRoot ("Negative
Discriminant") - return (-b Math.sqrt (discriminant))/2a
-
10Generics/Templates motivation
- public class Test
- void run()
- List foo new ArrayList() // List of
WHAT???? Bad documentation! ? - Widget w WidgetFactory.getWidget()
- foo.add(w) // intended to be a list of
Widget but no compile-time check here ? -
- for (Iterator it foo.iterator()
it.hasNext ) - Widget aWidget (Widget) it.next() // cast
and run-time check here ? - aWidget.doSomethingToIt()
-
-
-
- // The problem is that I want to reuse the
implementation of List, - // not build separate implementations for List
of Widget, List of PrintStream, etc. - // But I dont want to lie and pretend that my
List is a List of Object if it isnt
11Alternatives
- Macros/preprocessors
- This would allow List to be written once, but
- Would require each List type to be a separate
instantiation of the macro - You could get type errors from the generated code
- Extend the type system with true polymorphic
classes (hard, but see ML, C) - Generics/Templates
- No change in the run-time type system, but
- Compile-time type checking of proper use
12Simplest Case
- public interface List ltEgt // This DEFINES two
new generic interfaces - void add(E x)
- Iteratorlt E gt iterator()
-
- public interface Iterator lt E gt
- E next()
- boolean hasNext()
-
- public class ArrayList lt E gt implements Listlt E gt
// This defines a generic class that uses - // the generic interface
-
- ListltWidgetgt foo new ArrayListltWidgetgt() //
properly documented ? instance of generic class - Widget w WidgetFactory.getWidget()
- foo.add(w) // properly type-checked ?
-
- for (IteratorltWidgetgt it foo.iterator()
it.hasNext ) - Widget aWidget it.next() // no cast ?
- aWidget.doSomethingToIt()
-
13Gotchas
- When reading the code, you can
- Imagine that there is a (potential) class ListltEgt
for every possible value of E. (Ada and C will
actually do this) - Use subtyping to infer relationships, e.g.
ArrayListltWidgetgt is a subtype of ListltWidgetgt - But, when executing the code,
- There are no actual classes like
ArrayListltWidgetgt (there would be in C) - So you can not, for example cast things to
ArrayListltWidgetgt and get run-time checks - Only classes corresponding to erasures of
parametrized types are really there at runtime. - The erasure is the type without the parameters,
e.g. ArrayList.
14Other features
- All instances of the Java generic can share the
same code - Side effect static class variables/methods are
shared, so the image of each instance of a
template defining a new class is shattered - Any reflection, e.g. obj.getClass() sees the same
class. - Each Java generic has an interface (not called
that here I will call it a contract) that
specifies what kind of parameters it can have
when it is instantiated - Unlike C, where each instance can have
specialization, but where each instantiation
can fail for reasons that can only be determined
by looking inside the generic - Unlike Ada, where generics can be parameterized
with objects and functions as well as with types
15The Contract Bounds
- Suppose I need my generic class to invoke a run()
method on its argument of type E. That is - public class Foo lt E gt
- public doRun(E x)
- x.run() // Error! We dont know that E has a
run() method -
extends Runnable gt
// Now it is known to be safe
- Uses of the generic must obey the contract
- FooltRunnablegt y // OK
- FooltBargt w // OK provided that Bar implements
or extends Runnable - FooltObjectgt z // not OK Object doesnt
implement Runnable -
16Why wildcard types
- Suppose ColoredPoint is a subclass of Point. Can
I pass an object of ListltColoredPointgt to a
formal parameter of type ListltPointgt? - No! Because I might add objects of type Point
into a ListltPointgt, but not into a
ListltColoredPointgt - ListltColoredPointgt is not a subtype of
ListltPointgt - But suppose the method is not going to add
objects into the list, just get objects from the
list using an iterator? - Then the formal parameter should be of type
Listlt? extends Pointgt. This type stands for all
classes Listltigt where i extends Point.
Polymorphism without inheritance! - An attempt to call add(x) where x is a Point will
fail, because Listlt ? extends Pointgt doesnt
guarantee an add method that takes a Point. - But you may call an iterate() method whose next()
returns something of type Listlt? extends Pointgt,
which is assignable to a Point. - The most inclusive wildcard type for List is
Listlt?gt. At least you can do operations like
size() which are applicable to any list!
17Use of methods with Wildcard Types
- Interface Collection lt E gt
- public containsAll(Collection lt?gt c) // just
needs iterate, equals - public addAll(Collectionlt? extends E gt //
needs to make sure that // everything
thats added is an E or a subclass -
18What are generic methods and why do we need them?
- Just as generic classes/interfaces are multiple
parameterized instances of a class or interface
(that share a definition) - Generic methods (which could be static methods,
non-static methods, or constructors) are multiple
parameterized instances of methods within a class
or interface (that share a definition) - Example
- class Collections public static ltA extends
ComparableltAgtgt A max(Collectionlt A gt xs)
Iteratorlt A gt xi xs.iterator() // exploits xs
being a CollectionltAgt - A w xi.next() // exploits the fact
that next() on IteratorltAgt returns an A while
(xi.hasNext()) A x xi.next()
if (w.compareTo(x) lt 0) w x // exploits that
w extends ComparableltAgt - return w
- It says that for every class A that supports the
operations of ComparableltAgt, there exists a
method max taking one parameter of type
CollectionltAgt, and returns a value of type A. - So if class Foo implements ComparableltFoogt, you
can validly declare an object of type
CollectionltFoogt, and invoke Collection.max on it. - But if class Bar does not implement
ComparableltBargt, you may not validly declare an
object of type CollectionltBargt and invoke
Collection.max on it.
19So classes with generic methods really have an
infinite number of methods?
- Yes. But all the methods defined with one
generic method definition share the same
implementation! - Really means as viewed by the compiler. At
run-time, if you use reflection, theyll still
look like one method - This is overloading, not polymorphism!
- When the method is analyzed at compile-time, the
compiler will find an instance of each type
parameter and check that the constraints of the
contract are observed.
20What cant you do with Java generics
- Parameterized types play the role of types, not
classes, therefore, inside a class FooltTgt - Cant do new T()
- Cant do T.staticMethod()
- All type information is erased at runtime,
therefore - Inside the static context of FooltTgt, cant
declare variables of type T, or use T in any way
-- because the static context of FooltTgt is the
same for all T. - The static context means static initializers,
static methods, static (class) variables
anything that is shared by every instance of the
class. - Cant use reflection to build appropriate calls
to constructors or methods of type FooltTgt, since
all reflection tells me is that its a Foo. - Cant cast to type FooltTgt.
21Other gotchas
- Because Java didnt put generics in from the
start, - They need to deal with legacy code dealing with
unparameterized collection classes coexisting
with new code. - This has led to introducing an UNCHECKED
CONVERSION. ? - But, the pain of the above is limited to
generating ClassCastExceptions where no visible
class casts exist. (Still type-safe.)
22Generics in Ada
- Explicit instantiation with new
- Parameters may include objects and functions as
well as types - Smaller range of contracts
- generic
- type LIMPRIV is limited private -- Limited
private type - type PRIV is private -- Private type
- type DISCRETE_TYPE is (ltgt) -- Discrete type
- type INT_TYPE is range ltgt -- Integer type
- type MOD_TYPE is mod ltgt -- Modular type
- type FLOAT_TYPE is digits ltgt -- Floating point
type - type FIXED_TYPE is delta ltgt -- Fixed point type
type - DECIMAL_TYPE is delta ltgt digits ltgt -- Decimal
type - procedure AllGener
- procedure AllGener is begin end AllGener
23Templates in C
- Simple case is similar
- template ltclass Tgt
- class Stack
- public
- Stack(int 10)
- Stack() delete stackPtr
- int push(const T)
- int pop(T)
- int isEmpty()const return top -1
- int isFull() const return top size - 1
- private
- int size // number of elements on Stack.
- int top
- T stackPtr
- ...
- typedef Stackltfloatgt FloatStack
-
24But there are differences in C templates
- Each instantiation is a different class instance
- Each class can be specialized e.g.
StackltStringgt can use different logic - Each class generated from a template has its own
static - The generic language is Turing complete
- But not so easy to see the contract!
25A Generic that does Factorial?
- template ltint Ngt // notice that parameter is a
number, not a type - struct Factorial
- enum value N FactorialltN - 1gtvalue
- // here were re-invoking the template
recursively - template ltgt
- struct Factoriallt0gt enum value 1
- // Factoriallt0gt
- // matches both Factoriallt0gt in templateltgt
- // and Factoriallt0gt in template ltint Ngt. The
- // second definition overrides the first one.
- // Thats how the recursion terminates.
- // Factoriallt4gtvalue 24
- // Factoriallt0gtvalue 1
- void foo()
- int x Factoriallt4gtvalue // 24
- int y Factoriallt0gtvalue // 1
-