Programming Languages: Design, Specification, and Implementation G Rob Strom October 19, 2006
Administrative Alternative mailing address for me: Everyone should subscribe to the class mailing list: Reading: Ada sections 6,10 (classes and inheritance) Alternative C++ book: Lippman & Lajoie “C++ Primer” (Addison Wesley); ch 13, 14 (classes, initializers and finalizers) Java ( 8 (classes) Course Evaluations: During the break, please spend 5 minutes filling out the evaluation form. At the end of that time, collect forms and deliver them to Room 405.
Programming Languages Core Exam Syntactic issues: regular expressions, context-free grammars (CFG), BNF. Imperative languages: program organization, control structures. 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.
Classes of Types, continued Functions/procedures, including closures Type signature includes parameter/result types Pointers/References Type defines type of target In C++, a reference is a bound-once alias In C/C++, a pointer p supports p+i, meaning go to the i-th instance of the object of the type p points to. Object Abstractions (OOLs) Type determines sets of operations (methods) Tasks (Ada) Special (files, etc.)
Issues with Pointers Stacks are deallocated on exit Heaps are not. In some languages (Pascal, C++), you can explicitly free objects. This can lead to dangling references. If you can make pointers to the stack, you can still get dangling references unless you have a rule, such as: Algol 68: Pointers may not point to an object whose lifetime is shorter than that of the pointer. Ada 95: Pointers may not point to an object whose lifetime is shorter than that the of the pointer’s type. Otherwise, to be safe, you must retain objects until they’re guaranteed unusable. If you can copy pointers, then any heap object or any stack object to which a pointer was ever made could be aliased. Ada has a control: Non-references can’t be made into references unless the “aliased” attribute is specified Aliasing makes simple invariant analysis more complicated Does a procedure change X because it changes Y, an alias of X? Does a procedure change X because it holds an alias of X? Does a concurrent task hold an alias to X and hence potentially always change X?
Avoiding dangling references Tombstones: Extra level of indirection Nulled out when object deallocated Advantage: object can be dynamically moved Disadvantages: speed, can’t collect tombstone Key/lock Each pointer has address + key Each pointed to object has matching lock
Automatic Reclamation techniques Reference counting Problem: circular garbage Mark and sweep garbage collection Initially, every allocated block is “suspected garbage” Each reachable block is labelled “non-garbage” Finally, every suspected garbage block is collected Variations: stop-and-copy, generational Both require that we know: where all the pointers are and when they’re initialized the extents of allocated memory Hybrid techniques Rely on the fact that References to some blocks are isolated within some region, and Some regions are not aliased
Object-Oriented Concepts Encapsulation (Information Hiding) User of an “object” need only know the interface to the object: i.e. the operations supported on it, not the implementation The implementation can be specified separately Polymorphism Different instances of an object could have different implementations, so long as they all obeyed the same interface Inheritance Implementations can extend other implementations, specifying only what’s new or changed Object-based
Ada: Packages and Private types Package P is type abs is [limited] private; -- this is what users know procedure method1(a: in out abs); procedure method2(b: in out abs, c: INTEGER) private type abs is record – this is what implementer knows i1: t1; i2: t2; end record; end P; Package body P is … -- implementation of methods
Data Abstraction in Ada Information hiding by packages No special role of the object All functions in the package are “friends”, in that they can access the private data of any types defined in the package Need not be allocated by reference (good thing!) Note, that the private part of the package must be available at compile time where it’s used Hides the implementation, but does not by itself provide polymorphism. That is, all objects of type abs have not only the same interface, but also the same implementation
Inheritance in Ada Interface inheritance: A subclass has all of the methods of its parent class, and possibly more Implementation inheritance: A subclass has all of the data components of the parent, and possibly more A subclass may have different implementations of some of the methods of the parent class
Inheritance in Ada Private types that can be subclassed (inherited from) are called “tagged”. They are extensible records type person is tagged … type president is new person with … Derived types can either inherit operations or can over-ride (redefine) them BUT (unlike C++, Java) normally the decision about which operation to invoke is made statically, UNLESS you explicitly ask Ada to do a run-time-based dispatch.
Run-time Dispatch in Ada A variable using dynamic dispatch is of type FOO’CLASS or access FOO’CLASS. This means it will use the run-time type (implemented in the tag) to determine which type to use when dispatching a call. This is only usable for methods (so-called “primitive” operations) for types. No primitive operations can have operands of mixed types.