Programming Languages: Design, Specification, and Implementation G22.2210-001 Rob Strom November 2, 2006 Administrative Alternative mailing address for me: [email protected] Everyone should subscribe to the class mailing list: http://www.cs.nyu.edu/mailman/listinfo/g22_2110_001_fa06 Reading: • • Pierce,
Download ReportTranscript Programming Languages: Design, Specification, and Implementation G22.2210-001 Rob Strom November 2, 2006 Administrative Alternative mailing address for me: [email protected] Everyone should subscribe to the class mailing list: http://www.cs.nyu.edu/mailman/listinfo/g22_2110_001_fa06 Reading: • • Pierce,
Programming Languages: Design, Specification, and Implementation
G22.2210-001 Rob Strom November 2, 2006
Administrative
Alternative mailing address for me: [email protected]
Everyone should subscribe to the class mailing list: http://www.cs.nyu.edu/mailman/listinfo/g22_2110_001_fa06 Reading: • • Pierce, ch 9, simple typing; 11: extended typing, 22: type inference, especially 22.4 unification.
• DON’T DO THIS AT THE LAST MINUTE!!! It’s VERY formal.
Useful online tutorial: “A Gentle Introduction to ML” • http://www.dcs.napier.ac.uk/course-notes/sml/manual.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 week’s 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!
Polymorphic 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 what’s 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 doesn’t 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 room’s 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.
Programming 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.
Java 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 SMILECollectionService, 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 SMILECollectionService(...); • 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!!!
But Ada doesn’t have interfaces!
How can you get the effect?
Given 2 unrelated classes, X and Y type X is private; procedure a(…); procedure b(…); procedure c(...); procedure d(…); type Y is private; procedure c(…); procedure d(…); procedure e(…); procedure f(…); 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: CDInt’Class); procedure D(arg: CDInt’Class); 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.
type CDIntForX is new CDInt with private; private type CDIntForX is new CDInt with record theX : access X; procedure C(arg: CDInt’Class) is begin C(theX.all); end … anX: X; … intRef: CDInt’Class = getCDInt(anX); … C(intRef);
How this looks at runtime
Caller: C(intRef) A CDIntForX object anX: access X An actual instance of type X:
Exceptions:
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 doesn’t 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
Exceptions: 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(); 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 = b*b - 4*a*c; if (discriminant < 0) throw new NoRealRoot ("Negative Discriminant"); } } … } catch (Callee.NoRealRoot e) { System.out.println("Had to give up because " + e . getMessage()); } return (-b + Math.sqrt (discriminant))/2*a; }
Generics/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 don’t want to lie and pretend that my List is a List of Object if it isn’t
Alternatives
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
Simplest Case
public interface List < E >{ … // This DEFINES two new generic interfaces void add( E x); } Iterator< E > iterator(); public interface Iterator < E > { E next(); boolean hasNext(); } public class ArrayList < E > implements List< E > {…} // This defines a generic class that uses // the generic interface … List
Gotchas
When
reading
the code, you can • Imagine that there is a (potential) class List
executing
the code, • There are no actual classes like ArrayList
erasures
of parametrized types are really there at runtime.
•
The
erasure
is the type without the parameters, e.g. ArrayList.
Other 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
The Contract: Bounds
Suppose I need my generic class to invoke a run() method on its argument of type E. That is:
public class Foo < E > {… > { … public doRun( E x) { … // Now it is known to be safe E has a run() method }
Uses of the generic must obey the contract
Foo
Why wildcard types
Suppose ColoredPoint is a subclass of Point. Can I pass an object of List
• No! Because I might add objects of type Point into a List
• Then the formal parameter should be of type
List extends Point>
. This type stands for all classes List where i extends Point. Polymorphism without inheritance! • An attempt to call add(x) where x is a Point will fail, because List< ? extends Point> doesn’t guarantee an add method that takes a Point. • But you may call an iterate() method whose next() returns something of type List extends Point>, which is assignable to a Point.
• The most inclusive wildcard type for List is List>. At least you can do operations like size() which are applicable to any list!
Use of methods with Wildcard Types
Interface Collection < E > {… public containsAll(Collection > c); // just needs iterate, equals public addAll(Collection extends E >; // needs to make sure that // everything that’s added is an E or a subclass }
What 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
< A extends Comparable > A
max(Collection<
A
> xs) { Iterator<
A
> xi = xs.iterator(); // exploits xs being a Collection
A
w = xi.next(); // exploits the fact that next() on Iterator returns an A while (xi.hasNext()) {
A
x = xi.next(); if (w.compareTo(x) < 0) w = x; { // exploits that w extends Comparable } } } return w; It says that for every class A that supports the operations of Comparable, there exists a method “max” taking one parameter of type Collection, and returns a value of type A. So if class Foo implements Comparable
But if class Bar does not implement Comparable
So 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, they’ll 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.
What can’t you do with Java generics
Parameterized types play the role of types, not classes, therefore, inside a class Foo
• The
static context
means static initializers, static methods, static (“class”) variables – anything that is shared by every instance of the class.
• Can’t use reflection to build appropriate calls to constructors or methods of type Foo
• Can’t cast to type Foo
Other gotchas
Because Java didn’t 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.)
Generics 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 (<>); -- Discrete type type INT_TYPE is range <>; -- Integer type type MOD_TYPE is mod <>; -- Modular type type FLOAT_TYPE is digits <>; -- Floating point type type FIXED_TYPE is delta <>; -- Fixed point type type DECIMAL_TYPE is delta <> digits <>; -- Decimal type procedure AllGener; procedure AllGener is begin … ; end AllGener;
Templates in C++
Simple case is similar template
typedef Stack
But there are differences in C++ templates
Each instantiation is a different class instance Each class can be specialized – e.g. Stack 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!
A Generic that does Factorial?
template
// notice that parameter is a number, not a type
struct Factorial { enum { value = N * Factorial
// here we’re re-invoking the template recursively
template <> struct Factorial<0> { enum { value = 1 }; };
// Factorial<0> // matches both Factorial<0> in template<> // and Factorial<0> in template
// That’s how the recursion terminates.
// Factorial<4>::value == 24 // Factorial<0>::value == 1 void foo() { int x = Factorial<4>::value; // == 24 int y = Factorial<0>::value; // == 1 }