Homework 6. Reading. Problems. Handout 7 CS242: Autumn November

Similar documents
A Type System for Object Initialization In the Java TM Bytecode Language

Object-Oriented Languages and Object-Oriented Design. Ghezzi&Jazayeri: OO Languages 1

COMP 2355 Introduction to Systems Programming

Inheritance, and Polymorphism.

Note 12/1/ Review of Inheritance Practice: Please write down 10 most important facts you know about inheritance...

CS3157: Advanced Programming. Outline

The Java Language Implementation

CE221 Programming in C++ Part 1 Introduction

Introduction to C++ Introduction to C++ Dr Alex Martin 2013 Slide 1

Midterm Review. PIC 10B Spring 2018

Overriding המחלקה למדעי המחשב עזאם מרעי אוניברסיטת בן-גוריון

CS 162, Lecture 25: Exam II Review. 30 May 2018

Java Object Oriented Design. CSC207 Fall 2014

M301: Software Systems & their Development. Unit 4: Inheritance, Composition and Polymorphism

CSE P 501 Compilers. Java Implementation JVMs, JITs &c Hal Perkins Winter /11/ Hal Perkins & UW CSE V-1

CSCI 102L - Data Structures Midterm Exam #1 Fall 2011

Chapter 1: Object-Oriented Programming Using C++

Polymorphism Part 1 1

Object typing and subtypes

Functions and Parameter Passing

CS250 Final Review Questions

Fundamentals of Programming Languages

ECE 3574: Dynamic Polymorphism using Inheritance

Week 7. Statically-typed OO languages: C++ Closer look at subtyping

Agenda. The main body and cout. Fundamental data types. Declarations and definitions. Control structures

2 ADT Programming User-defined abstract data types

Short Notes of CS201

Inheritance, Polymorphism and the Object Memory Model

Fast Introduction to Object Oriented Programming and C++

Introduction to C++ Systems Programming

Interview Questions of C++

CS201 - Introduction to Programming Glossary By

Object-Oriented Programming for Scientific Computing

CS304 Object Oriented Programming Final Term

Object Reference and Memory Allocation. Questions:

Special Member Functions. Compiler-Generated Destructor. Compiler-Generated Default Constructor. Special Member Functions

CS24 Week 3 Lecture 1

CSE 303: Concepts and Tools for Software Development

Compiling Techniques

Exercise 1.1 Hello world

The Notion of a Class and Some Other Key Ideas (contd.) Questions:

Midterm Exam 5 April 20, 2015

Abstract Data Types (ADTs) 1. Legal Values. Client Code for Rational ADT. ADT Design. CS 247: Software Engineering Principles

C++ Programming: Polymorphism

Basic memory model Using functions Writing functions. Basics Prototypes Parameters Return types Functions and memory Names and namespaces

What does it mean by information hiding? What are the advantages of it? {5 Marks}

CS304 Object Oriented Programming

C++ Modern and Lucid C++ for Professional Programmers

Object Oriented Design

C How to Program, 6/e, 7/e

Memory and Pointers written by Cathy Saxton

Introduction to C++ Professor Hugh C. Lauer CS-2303, System Programming Concepts

CSE 374 Programming Concepts & Tools. Hal Perkins Spring 2010

CS 247: Software Engineering Principles. ADT Design

What s Conformance? Conformance. Conformance and Class Invariants Question: Conformance and Overriding

A506 / C201 Computer Programming II Placement Exam Sample Questions. For each of the following, choose the most appropriate answer (2pts each).

C++_ MARKS 40 MIN

Agenda. CSE P 501 Compilers. Java Implementation Overview. JVM Architecture. JVM Runtime Data Areas (1) JVM Data Types. CSE P 501 Su04 T-1

Polymorphism CSCI 201 Principles of Software Development

Announcements. CSCI 334: Principles of Programming Languages. Lecture 18: C/C++ Announcements. Announcements. Instructor: Dan Barowy

Lecture 3: C Programm

CSE 452: Programming Languages. Previous Lecture. From ADTs to OOP. Data Abstraction and Object-Orientation

cs3157: c++ lecture #2 (mon-11-apr-2005) chronology of some programming languages... C++ vs Java identifiers.

Paytm Programming Sample paper: 1) A copy constructor is called. a. when an object is returned by value

CMSC 132: Object-Oriented Programming II

Software Paradigms (Lesson 3) Object-Oriented Paradigm (2)

CS107 Handout 37 Spring 2007 May 25, 2007 Introduction to Inheritance

l Determine if a number is odd or even l Determine if a number/character is in a range - 1 to 10 (inclusive) - between a and z (inclusive)

Operator overloading

Evolution of Programming Languages

CMSC 202 Section 010x Spring Justin Martineau, Tuesday 11:30am

Inheritance. Transitivity

CS164: Programming Assignment 5 Decaf Semantic Analysis and Code Generation

SRM ARTS AND SCIENCE COLLEGE SRM NAGAR, KATTANKULATHUR

CS105 C++ Lecture 7. More on Classes, Inheritance

CSE 374 Programming Concepts & Tools. Hal Perkins Fall 2015 Lecture 19 Introduction to C++

Lecture Overview. [Scott, chapter 7] [Sebesta, chapter 6]

Special Member Functions

C++ Inheritance and Encapsulation

Increases Program Structure which results in greater reliability. Polymorphism

C++ Crash Kurs. Polymorphism. Dr. Dennis Pfisterer Institut für Telematik, Universität zu Lübeck

Subtyping (Dynamic Polymorphism)

C++ Mini-Course. Part 1: Mechanics Part 2: Basics Part 3: References Part 4: Const Part 5: Inheritance Part 6: Libraries Part 7: Conclusion. C Rulez!

Largest Online Community of VU Students

CPSC 427: Object-Oriented Programming

VALLIAMMAI ENGINEERING COLLEGE

SDV4001 Object Oriented Programming with C++ and UI Midterm 2013

double d0, d1, d2, d3; double * dp = new double[4]; double da[4];

Data Abstraction. Hwansoo Han

Chapter 6 Introduction to Defining Classes

CMSC 132: Object-Oriented Programming II

Pointers II. Class 31

AN OVERVIEW OF C++ 1

IV. Stacks. A. Introduction 1. Consider the 4 problems on pp (1) Model the discard pile in a card game. (2) Model a railroad switching yard

POLYMORPHISM 2 PART. Shared Interface. Discussions. Abstract Base Classes. Abstract Base Classes and Pure Virtual Methods EXAMPLE

POLYMORPHISM 2 PART Abstract Classes Static and Dynamic Casting Common Programming Errors

Object-Oriented Programming

Pointers and Arrays CS 201. This slide set covers pointers and arrays in C++. You should read Chapter 8 from your Deitel & Deitel book.

CS 376b Computer Vision

I BSc(IT) [ Batch] Semester II Core: Object Oriented Programming With C plus plus - 212A Multiple Choice Questions.

Transcription:

Homework 6 Due 14 November, 5PM Handout 7 CS242: Autumn 2012 7 November Reading 1. Chapter 10, section 10.2.3 2. Chapter 11, sections 11.3.2, and 11.7 3. Chapter 12, section 12.4 4. Chapter 13, section 13.3, 13.4 and 13.5 5. Optimizing Dynamically-Typed Object-Oriented Languages With Polymorphic Inline Caches (pdf on CourseWare), pages 1 5. Problems 1............................................................... Protocol Conformance We can compare Smalltalk interfaces to classes using protocols, which are lists of operation names (selectors). When a selector allows parameters, as in at: put:, the selector name includes the colons but not the spaces. More specifically, if dict is an updatable collection object, such as a dictionary, then we could send dict a message by writing dict at: cross put: angry. (This makes our dictionary definition of cross the single word angry. ) The protocol for updatable collections will therefore contain the seven-character selector name at:put:. Here are some example protocols. map : {numelems, contains:, at:put:, get:, remove: set : {numelems, contains:, add:, remove: multiset : {numelems, contains:, count:, add:, remove: array : {numelems, at:put:, get: simple collection : {numelems Briefly, a map represents a function from a set of integer keys to a set of values. It can be sent the message isempty to test whether its domain is empty, returning true if empty and false otherwise; contains: tests whether a given key is part of the domain; at:put: adds a key/value mapping to the map; get: fetches the value associated with the given key, and remove: removes the mapping from the given key. A set object represents a set of integers, where the contains:, add: and remove: methods test membership, add an element, and remove an element respectively. Multisets are like sets except they may contain multiple copies of any given element, which we can quantify using the count: method. Arrays are objects where the at:put: method is used to update elements of the array, and the get: method is used to retrieve elements of the array. The simple collection class just collects methods that are common to all the other classes. We say that the protocol for A conforms to the protocol for B if the set of A selector names contains the set of B selector names. (a) Draw a diagram of these classes, ordered by protocol conformance. You should end up with a graph that look s like William Cook s drawing shown in the text, without the dotted arrows showing inheritance. (b) Choose two classes, A and B, from your diagram from part (a) such that B conforms to the protocol for A. Describe briefly, in words, a way of implementing each class so that the implementation of B inherits from the implementation of A. 1

(c) Choose two classes, A and B, from your diagram from part (a) such that neither conforms to the protocol of the other. Describe briefly, in words, a way of implementing each class so that the implementation of A inherits from the implementation of B. (d) Choose two classes, A and B, from your diagram from part (a) such that B conforms to the protocol for A. Describe briefly, in words, a way of implementing each class so that the implementation of A inherits from the implementation of B. 2......................................................................... C++ Conversions C++ allows the programmer to specify how to convert between different classes. This can be very useful when you are passing around objects by value, as the default behavior is not always what is desired. If you are unfamiliar with C++, you may find Bruce Eckel s Thinking in C++, 2nd Ed helpful. It is freely available on the web, via http://www.mindview.net/books/. (a) What is printed by the following code and why? Your answer should be three sentences or less. #include <iostream> using namespace std; class A { virtual void foo() { cout << A::foo\n << endl; class B : public A { virtual void foo() { cout << B::foo\n << endl; void test( A a ); void test( A a ) { a.foo(); int main() { A a; B b; test(a); test(b); (b) C++ provides an interesting mix of features for converting between objects of different types. The two primary language features are copy constructors and operator conversion. Like many parts of C++ they can surpise people. Explain why the following code prints bork bork instead of bork B::foo or bork bark could this problem be solved by using a copy constructor instead? Explain briefly. 2

#include <iostream> using namespace std; class A { char *s; virtual void foo() { cout << s << endl; A() : s( bork ) { class B : public A { virtual void foo() { cout << B::foo << endl; operator A() const { A a; a.s = bark ; return a; void test( A a ); void test( A a ) { a.foo(); int main() { A a; B b; test(a); test(b); (c) C++ is the only mainstream object oriented language that does not hide its objects behind pointers or references. You have just seen how this can cause an intersting set of problems when programmers pass objects by value. What two character edit can you do to the original code to make it work as expected? 3..................................................................... Function Subtyping Assume that Square <: Rectangle and Rectangle <: Polygon. Which of the following subtype relationships hold in principle? (a) (Square Square) <: (Rectangle Rectangle) (b) (Square Rectangle) <: (Rectangle Rectangle) (c) (Square Polygon) <: (Rectangle Rectangle) (d) (Rectangle Square) <: (Rectangle Rectangle) (e) (Rectangle Rectangle) <: (Rectangle Rectangle) (f) (Rectangle Polygon) <: (Rectangle Rectangle) (g) (Polygon Square) <: (Rectangle Rectangle) (h) (Polygon Rectangle) <: (Rectangle Rectangle) (i) (Polygon Polygon) <: (Rectangle Rectangle) (j) (Square (Rectangle Square)) <: (Polygon (Rectangle Square)) (k) (Rectangle (Rectangle Square)) <: (Polygon (Rectangle Square)) (l) (Polygon (Rectangle Square)) <: (Polygon (Rectangle Square)) 3

(m) (Polygon (Square Square)) <: (Polygon (Rectangle Square)) (n) (Polygon (Polygon Rectangle)) <: (Polygon (Rectangle Square)) (o) (Polygon (Polygon Square)) <: (Polygon (Rectangle Square)) (p) (Rectangle (Rectangle Rectangle)) <: (Polygon (Rectangle Square)) 4.............................................................. Private Virtual Functions At first thought, the idea of a private virtual function might seem silly: why would you want to redefine a function that is not visible outside the class? However, there is a programming idiom that makes use of private virtual functions in a reasonable way. This idiom is illustrated in the following code, which uses a public function to call a private virtual function. class Computer { void retailprice(void) { int p = 2 * manufacturecost(); printf( $%d\n, p); // Print p private: virtual int manufacturecost(void) {return 1000; class IBMComputer: public Computer { private: virtual int manufacturecost(void) {return 1500; int main(void) { Computer *cptr = new Computer(); IBMComputer *ibmptr = new IBMComputer(); Computer *cibmptr = new IBMComputer(); cptr->retailprice(); ibmptr->retailprice(); cibmptr->retailprice(); return 0; This question asks about how the function calls to retailprice() are evaluated. (a) Explain which version of manufacturecost() is used in the call cibmptr->retailprice() and why. (b) If the virtual keyword is omitted from the declaration of manufacturecost in the derived class IBMComputer, the code above will still compile without error and execute. Will manufacturecost be implemented as a virtual function in class IBMComputer? Use your knowledge of how C++ is implemented to explain why or why not. (c) It is possible for the private base class function to be declared public in the derived class. Does this conflict with subtyping principles? Explain why or why not in a few words. 5......................................................... Subclassing and Subtyping C++ supports both public and private inheritance. Sometimes these are described by saying that public inheritance establishes an is-a relationship, while private inheritance establishes a has-a 4

relationship. One distinction is that private inheritance makes the public functions of the parent class private in the child class. Here is some example code to illustrate the difference between public and private inheritance: class Engine { virtual void start() { cout << getenginetype() << " started" << endl; virtual string run() { cout << "attempting to run " << getenginetype() << endl; start(); virtual string getenginetype() { return "generic engine"; class SteamEngine:public Engine { //A SteamEngine is an Engine virtual string getenginetype() { return "steam engine"; class Car : private Engine { //A Car has an Engine virtual void startcar() { cout << "starting car" << endl; Engine::run(); (a) Will the code on lines 6-8 produce any compile-time or run-time errors? 1: int main() 2: { 3: Engine e; 4: SteamEngine s; 5: Car c; 6: e.start(); 7: s.start(); 8: c.start(); 9: return 0; 10: 6: 7: 8: (b) When Car :: startcar is executed, it makes a call to Engine :: run which in turn executes 5

Engine :: start. What is the type of the this pointer that is passed implicitly to Engine :: run, and what does this imply about the virtual tables for Engine and Car? (c) List the public interfaces of Engine and Car. What can you conclude about the subtype relationship between a parent and child class using private inheritance? (d) Will the code on lines 7-9 produce any compile-time or run-time errors? 1: void checkup(const Engine& e) {... 2: int main() 3: { 4: Engine e; 5: SteamEngine s; 6: Car c; 7: checkup(e); 8: checkup(s); 9: checkup(c); 10: return 0; 11: 7: 8: 9: 6........................................................... Array Covariance in Java Java array types are covariant with respect to the types of array elements (i.e., if B <: A, then B[ ] <: A[ ]). This can be useful for creating functions that operate on many types of arrays. For example, the following function takes in an array and swaps the first two elements in the array. 1: public swapper (Object[] swappee){ 6

2: if (swappee.length > 1){ 3: Object temp = swappee[0]; 4: swappee[0] = swappee[1]; 5: swappee[1] = temp; 6: 7: This function can be used to swap the first two elements of an array of objects of any type. The function works as it is and does not produce any type errors at compile-time or run-time. (a) Suppose a is declared as Shape[] a, an array of shapes, where Shape is some class. Explain why covariance (if B <: A, then B[ ] <: A[ ]) allows the type checker to accept the call swapper(a) at compile time. (b) Suppose Shape[] a as in part (a). Explain why the call swapper(a) and execution of the body of swapper will not cause a type error or exception at run time. (c) Java uses run-time checks, as needed, to make sure that certain operations respect the Java type discipline at run time. What run-time type checks occur in the compiled code for the swapper function and where? List the line number(s) and the check that occurs on that line. (d) A friend of yours is aghast at the design of Java array subtyping. In his brilliance, he suggests that Java arrays should follow contravariance instead of covariance (i.e., if B <: A, then A[ ] <: B[ ]). He states that this would eliminate the need for run-time type checks. Write three lines of code or less that will compile fine under your friend s new type system, but will cause a run-time type error (assuming no run-time type tests accompany his rule). You may assume you have two classes, A and B, that B is a subtype of A, and that B contains a method, foo, not found in A. We give you two declarations that you can assume before your three lines of code. B b[]; A a[] = new A[10]; (e) Your friend, now discouraged about his first idea, decides that covariance in Java is alright after all. However, he thinks that he can get rid of the need for run-time type tests through sophisticated compile time analysis. Explain in a sentence or two why enforcing covariance solely at compile time, without runtime type-checking, will still lead to run-time type errors. You may write a few lines of code similar to those in part (d) if it helps you make your point clearly. 7.............................................................. Java Bytecode Analysis Java programs are compiled into bytecode, a simple machine language that runs on the Java Virtual Machine. Note that it is possible that bytecode could be written by hand or that compiled bytecode gets corrupted when transmitted over the network. So, when a class is loaded by the JVM, it is first examined by the bytecode verifier. The verifier performs static analysis of the class to ensure that a program will not cause an unchecked runtime type error. One kind of bytecode error that the verifier should catch is use of an uninitialized variable. Here is a code fragment in Java and some corresponding bytecode. We have added comments to the bytecode to help you figure out the effects of the instructions. // Java Source Code Point p = new Point(3); p.print(); // Compiled Bytecode 1: new #1 <Class Point> // allocate space for Point 7

2: dup // duplicate top entry on stack 3: iconst 3 // push integer 3 onto stack 4: invokespecial #4 <Method Point(int)> // invoke constructor, which pops // its argument (3) and one of // the pointers to p off stack 5: invokevirtual #5 <Method void Print()> // invoke print method, popping // the other pointer to p. The first line of the Java source allocates space for a new Point object and calls the Point constructor to initialize this object. The second line invokes a method on this object and therefore can be allowed only if the object has been initialized. It is easy to verify from this Java source that p is initialized before it is used. Checking that objects are initialized before use in the bytecode is more difficult. The Java implementation creates objects in several steps: First, space is allocated for the object. Second, arguments to the constructor are evaluated and pushed onto the stack. Finally, the constructor is invoked. In the bytecode for this example, the memory for p is allocated in line 1, but the constructor isn t invoked until line 4. If several objects are passed as arguments to the constructor, there could be an even longer code fragment between allocation and initialization of an object, possibly allocating multiple new objects, duplicating pointers, and taking conditional branches. To account for pointer duplication, some form of aliasing analysis is needed in the bytecode verifier. This problem will consider a simplified form of initialize-before-use bytecode verification that keeps track of pointer aliasing by keeping track of the line number at which an object was first created. When a pointer to an uninitialized object is copied, the alias analysis algorithm copies the line number where the object was created, so that both pointers can be recognized as aliases for a single object. Of course, if an instruction creating a new object is inside a loop, then there may be many different uninitialized objects created at the same line number. However, the bytecode verifier does not need to work for this case, since Java compilers do not generate code like this. We won t consider any cases with conditional branches in this problem. Let s examine the contents of stack and any associated line numbers for alias detection after execution of each of the bytecode instructions from above. Note that we draw the stack growing downwards in this diagram: After line: Stack line # where created initialized 1 Point p 1 no 2 Point p 1 no alias for p 1 no 3 Point p 1 no alias for p 1 no int 3 3 yes 4 Point p 1 yes By using line numbers as object identifiers associated with each pointer on the stack, we keep track of the fact that both pointers on the stack point to the same place after line 2. So when the constructor invoked on line 4 initializes the alias for p, we recognize that p is initialized as well. Thus the Print() method is applied to a properly initialized Point object, and this example code fragment passes our simple initialize-before-use verifier. (a) Consider the following bytecode: 1: new #1 <Class Point> 2: new #1 <Class Point> 3: dup 4: iconst 3 5: invokespecial #4 <Method Point(int)> 6: invokevirtual #5 <Method void Print()> 8

When line 5 is reached, there will be more than one uninitialized Point objects on the stack. Use the static verification method described above to figure out which one gets initialized, and whether the subsequent invocation of the Print() method occurs on an initialized Point. You should draw the state of the stack after each instruction, using the original line number associated with any pointer to detect aliases. (b) So far we have only considered bytecode operations that use the operand stack. For this problem we introduce two more bytecode instructions, load and store, which allow values to be moved between the operand stack and local variables. store x removes a variable from the top of the stack and stores it into local variable x. load x loads the value from local variable x and places it on the top of the stack. In the following table, we have begun applying the initialize-before-use verification procedure described above to the code fragment in the left column. Note that we are maintaining information about aliasing and initialization state for local variable x as well as the contents of the operand stack. The contents of the stack correspond to that obtained just after the code in the left column is executed. Code local variable x stack line # init? content line # init? 1: new #1 <Class Point> n/a no Point 1 no 2: new #1 <Class Point> n/a no Point 1 no Point 2 no 3: store x 2 no Point 1 no 4: load x 5: load x 6: iconst 5 7: invokespecial #4 <Method Point(int)> 8: invokevirtual #5 <Method void Print()> 9: invokevirtual #5 <Method void Print()> Continue applying the procedure to fill in the missing information on lines 4-9. Based on the state information you have after instruction 7, is the Print() method on line 8 applied to a properly initialized object? What about the Print() method on line 9? 9