1 / 25

Programming Languages: Design, Specification, and Implementation

Programming Languages: Design, Specification, and Implementation. G22.2210-001 Rob Strom November 2, 2006. Administrative. Alternative mailing address for me: robstrom@us.ibm.com Everyone should subscribe to the class mailing list: http://www.cs.nyu.edu/mailman/listinfo/g22_2110_001_fa06

Download Presentation

Programming Languages: Design, Specification, and Implementation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Programming Languages:Design, Specification, and Implementation G22.2210-001 Rob Strom November 2, 2006

  2. Administrative • Alternative mailing address for me: robstrom@us.ibm.com • 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!

  3. 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.

  4. 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.

  5. 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!!! 

  6. But Ada doesn’t 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: CDInt’Class); • procedure D(arg: CDInt’Class); • 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 … • 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: CDInt’Class = getCDInt(anX); • … • C(intRef);

  7. How this looks at runtime • Caller: • C(intRef) • A CDIntForX object • anX: access X • An actual instance of type X:

  8. 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

  9. 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 = b*b - 4*a*c; if (discriminant < 0) throw new NoRealRoot ("Negative Discriminant"); return (-b + Math.sqrt (discriminant))/2*a; } Exceptions: example

  10. 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 Generics/Templates: motivation

  11. 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

  12. 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<Widget> foo = new ArrayList<Widget>(); // properly documented  instance of generic class Widget w = WidgetFactory.getWidget(“…”); foo.add(w); // properly type-checked  … for (Iterator<Widget> it = foo.iterator(); it.hasNext ; ) { Widget aWidget = it.next(); // no cast  aWidget.doSomethingToIt(); } Simplest Case

  13. Gotchas • When reading the code, you can • Imagine that there is a (potential) class List<E> for every possible value of E. (Ada and C++ will actually do this) • Use subtyping to infer relationships, e.g. ArrayList<Widget> is a subtype of List<Widget> • But, when executing the code, • There are no actual classes like ArrayList<Widget> (there would be in C#) • So you can not, for example cast things to ArrayList<Widget> 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.

  14. 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

  15. 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) { … x.run(); // Error! We don’t know that E has a run() method } extends Runnable > { … // Now it is known to be safe • Uses of the generic must obey the contract Foo<Runnable> y; // OK Foo<Bar> w; // OK provided that Bar implements or extends Runnable Foo<Object> z; // not OK; Object doesn’t implement Runnable

  16. Why wildcard types • Suppose ColoredPoint is a subclass of Point. Can I pass an object of List<ColoredPoint> to a formal parameter of type List<Point>? • No! Because I might add objects of type Point into a List<Point>, but not into a List<ColoredPoint> • List<ColoredPoint> is not a subtype of List<Point> • 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 List<? extends Point>. This type stands for all classes List<i> 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!

  17. 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 }

  18. 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>> A max(Collection< A > xs) {     Iterator< A > xi = xs.iterator(); // exploits xs being a Collection<A> A w = xi.next(); // exploits the fact that next() on Iterator<A> returns an A    while (xi.hasNext()) { A x = xi.next();       if (w.compareTo(x) < 0) w = x; { // exploits that w extends Comparable<A>     }     return w;   } }  It says that for every class A that supports the operations of Comparable<A>, there exists a method “max” taking one parameter of type Collection<A>, and returns a value of type A. So if class Foo implements Comparable<Foo>, you can validly declare an object of type Collection<Foo>, and invoke Collection.max on it. But if class Bar does not implement Comparable<Bar>, you may not validly declare an object of type Collection<Bar> and invoke Collection.max on it.

  19. 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.

  20. What can’t you do with Java generics • Parameterized types play the role of types, not classes, therefore, inside a class Foo<T>: • Can’t do new T(…) • Can’t do T.staticMethod(…) • All type information is erased at runtime, therefore • Inside the static context of Foo<T>, can’t declare variables of type T, or use T in any way -- because the static context of Foo<T> 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. • Can’t use reflection to build appropriate calls to constructors or methods of type Foo<T>, since all reflection tells me is that it’s a Foo. • Can’t cast to type Foo<T>.

  21. 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.)

  22. 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;

  23. Templates in C++ • Simple case is similar template <class T> 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 Stack<float> FloatStack ;

  24. But there are differences in C++ templates • Each instantiation is a different class instance • Each class can be specialized – e.g. Stack<String> 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!

  25. A Generic that does Factorial? template <int N> // notice that parameter is a number, not a type struct Factorial { enum { value = N * Factorial<N - 1>::value }; }; // 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 <int N>. The // second definition overrides the first one. // 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 }

More Related