CSE341, Fall 2011, Lecture 26 Summary

Similar documents
CSE341: Programming Languages Lecture 25 Subtyping for OOP; Comparing/Combining Generics and Subtyping. Dan Grossman Winter 2013

Today. CSE341: Programming Languages. Late Binding in Ruby Multiple Inheritance, Interfaces, Mixins. Ruby instance variables and methods

Late Binding; OOP as a Racket Pattern

CSE 341, Autumn 2015, Ruby Introduction Summary

CS152: Programming Languages. Lecture 23 Advanced Concepts in Object-Oriented Programming. Dan Grossman Spring 2011

CS-XXX: Graduate Programming Languages. Lecture 23 Types for OOP; Static Overloading and Multimethods. Dan Grossman 2012

Last major topic: Subtyping. CSE341: Programming Languages Lecture 24 Subtyping. A tiny language. Records (half like ML, half like Java)

CS152: Programming Languages. Lecture 24 Bounded Polymorphism; Classless OOP. Dan Grossman Spring 2011

CSE341: Programming Languages Lecture 23 Multiple Inheritance, Mixins, Interfaces, Abstract Methods. Dan Grossman Autumn 2018

CSE341: Programming Languages Lecture 11 Type Inference. Dan Grossman Spring 2016

CSE341: Programming Languages Lecture 19 Introduction to Ruby and OOP. Dan Grossman Winter 2013

Ruby logistics. CSE341: Programming Languages Lecture 19 Introduction to Ruby and OOP. Ruby: Not our focus. Ruby: Our focus. A note on the homework

Object-Oriented Design Lecture 14 CSU 370 Fall 2007 (Pucella) Friday, Nov 2, 2007

CS 251 Intermediate Programming Inheritance

Exercise 3 Subtyping and Behavioral Subtyping October 13, 2017

Inheritance and Substitution (Budd chapter 8, 10)

Conformance. Object-Oriented Programming Spring 2015

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

Data Structures (list, dictionary, tuples, sets, strings)

CSE341: Programming Languages Lecture 22 OOP vs. Functional Decomposition; Adding Operators & Variants; Double-Dispatch. Dan Grossman Autumn 2018

Inheritance and object compatibility

6.170 Recitation #5: Subtypes and Inheritance

PROGRAMMING LANGUAGE 2

Interfaces, Mixins, & Multiple Inheritance

CS-202 Introduction to Object Oriented Programming

CS558 Programming Languages Winter 2013 Lecture 8

Overview of OOP. Dr. Zhang COSC 1436 Summer, /18/2017

Computer Science 225 Advanced Programming Siena College Spring Topic Notes: Inheritance

To Think About. MyClass.mogrify(new int[] { 1, 2, 4, 6 }));

Subtyping: broad definitions. Not Subtyping: type variable instantiation. Mutable Records (half like ML, half like Java/Scala)

Subtyping (Dynamic Polymorphism)

CSE351 Winter 2016, Final Examination March 16, 2016

Java Object Oriented Design. CSC207 Fall 2014

Rules and syntax for inheritance. The boring stuff

CS153: Compilers Lecture 11: Compiling Objects

Lecture 21: The Many Hats of Scala: OOP 10:00 AM, Mar 14, 2018

Argument Passing All primitive data types (int etc.) are passed by value and all reference types (arrays, strings, objects) are used through refs.

CSE 331 Software Design and Implementation. Lecture 14 Generics 2

Lecture Notes on Programming Languages

A Short Summary of Javali

CSE341, Spring 2013, Final Examination June 13, 2013

QUIZ. What is wrong with this code that uses default arguments?

Day 4. COMP1006/1406 Summer M. Jason Hinek Carleton University

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

CSE 331 Software Design and Implementation. Lecture 14 Generics 2

Type Hierarchy. Lecture 6: OOP, autumn 2003

Lambda Correctness and Usability Issues

Inheritance, Polymorphism, and Interfaces

Type Hierarchy. Comp-303 : Programming Techniques Lecture 9. Alexandre Denault Computer Science McGill University Winter 2004

Comp 249 Programming Methodology

Subtypes and Subclasses

301AA - Advanced Programming [AP-2017]

Programming Languages. Streams Wrapup, Memoization, Type Systems, and Some Monty Python

Lecture 13: Object orientation. Object oriented programming. Introduction. Object oriented programming. OO and ADT:s. Introduction

Java Fundamentals (II)

Chapter 5 Object-Oriented Programming

CSE 413 Languages & Implementation. Hal Perkins Winter 2019 Structs, Implementing Languages (credits: Dan Grossman, CSE 341)

Concepts of Programming Languages

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

Expected properties of equality

STUDENT LESSON A20 Inheritance, Polymorphism, and Abstract Classes

Administrivia. CMSC433, Fall 2001 Programming Language Technology and Paradigms. Administrivia (cont.) Project 1. Copy constructor.

Object Oriented Programming. Java-Lecture 11 Polymorphism

CMSC131. Inheritance. Object. When we talked about Object, I mentioned that all Java classes are "built" on top of that.

CSE341, Fall 2011, Lecture 12 Summary

Outline. Java Models for variables Types and type checking, type safety Interpretation vs. compilation. Reasoning about code. CSCI 2600 Spring

CS-XXX: Graduate Programming Languages. Lecture 22 Class-Based Object-Oriented Programming. Dan Grossman 2012

CS558 Programming Languages

C++ Yanyan SHEN. slide 1

CSE 401/M501 Compilers

Inheritance and Interfaces

CSE 401 Final Exam. March 14, 2017 Happy π Day! (3/14) This exam is closed book, closed notes, closed electronics, closed neighbors, open mind,...

Lesson 10A OOP Fundamentals. By John B. Owen All rights reserved 2011, revised 2014

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

Module 10 Inheritance, Virtual Functions, and Polymorphism

G Programming Languages Spring 2010 Lecture 6. Robert Grimm, New York University

Type Checking in COOL (II) Lecture 10

Making Inheritance Work: C++ Issues

Making Inheritance Work: C++ Issues

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

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

Lecture Topics. Administrivia

OO Technology: Properties and Limitations for Component-Based Design

ob-ject: to feel distaste for something Webster's Dictionary

CSE 331 Software Design & Implementation

Don t Believe the Hype. CS152: Programming Languages. Lecture 21 Object-Oriented Programming. Class-based OOP. So what is OOP?

CSCI-142 Exam 1 Review September 25, 2016 Presented by the RIT Computer Science Community

Everything is an object. Almost, but all objects are of type Object!

CSE 505, Fall 2007, Final Examination 10 December Please do not turn the page until everyone is ready.

CS 520 Theory and Practice of Software Engineering Fall 2018

Super-Classes and sub-classes

16 Multiple Inheritance and Extending ADTs

Object Oriented Issues in VDM++

Intro. Scheme Basics. scm> 5 5. scm>

Instantiation of Template class

3 ADT Implementation in Java

What is a type? Types in OO languages. What is a type? Types as sets. Example. Clients of screensaver

HAS-A Relationship. Association is a relationship where all objects have their own lifecycle and there is no owner.

9/10/2018 Programming Data Structures Inheritance

6.001 Notes: Section 8.1

Transcription:

CSE341, Fall 2011, Lecture 26 Summary Standard Disclaimer: This lecture summary is not necessarily a complete substitute for attending class, reading the associated code, etc. It is designed to be a useful resource for students who attended class and are later reviewing the material. This lecture applies the general concepts of record and function subtyping from the last lecture to objectoriented languages, mostly Java. We will see that: Record and function subtyping are excellent guides to what should be allowed in statically typed object-oriented languages to prevent field missing and method missing errors. But Java has two key differences worth exploring: It uses class and interface names for types, which is convenient and/but prevents some subtyping that would be sound. It does not support contravariant arguments on methods. Instead it supports static overloading based on the types of method arguments. self/this is special with respect to subtyping: It is covariant in subclasses even though we sometimes think of it as an extra argument to methods. Basic Subtyping for Objects and Java s Restrictions Thereof An object is basically a record holding fields (which we assume here are mutable) and methods. We assume the slots for methods are immutable: If an object s method m is implemented with some code, then there is no way to mutate m to refer to different code. (An instance of a subclass could have different code for m, but that s different than mutating a record field.) With this perspective, sound subtyping for objects follows from sound subtyping for records and functions: A subtype can have extra fields. Because fields are mutable, a subtype cannot have a different type for a field. A subtype can have extra methods. Because methods are immutable, a subtype can have a subtype for a method, which means the method in the subtype can have contravariant argument types and a covariant result result type. That said, object types in Java and C# do not look like record types and function types. For example, we cannot write down a type that looks something like: {fields : x:real, y:real,... methods: disttoorigin : () -> real,... Instead, we reuse class names as types where if there is a class Foo, then the type Foo includes in it all fields and methods implied by the class definition (including superclasses). And, as discussed previously, we also have interfaces, which are more like record types except they do not include fields and we use the name of the interface as a type. Subtyping in Java and C# includes only the subtyping explicitly stated via the subclass relationship and the interfaces that classes explicitly indicate they implement (including interfaces implemented by superclasses). All said, this approach is more restrictive than subtyping requires, but since it does not allow anything it should not, it soundly prevents field missing and method missing errors. In particular: 1

A subclass can add fields but not remove them A subclass can add methods but not remove them A subclass can override a method with a covariant return type A class can implement more methods than an interface requires or implement a required method with a covariant return type Shadowing Fields Because fields are mutable, we know a subtype cannot have a different type for a field than a supertype. So it is surprising that Java actually allows a class to declare a field with the same name as a field already declared in a superclass. For example, this code is allowed in Java: class Color { String colorname; class FancyColor extends Color { double shade; class Point {... class ColorPoint extends Point { Color color;... class MyColorPoint extends ColorPoint { FancyColor color;... It would not be sound to allow the MyColorPoint class to change the color field to hold a FancyColor and have code assume this. After all, methods inherited from ColorPoint could assign color to hold instances of Color leading to errors if we then tried to read the shade field. The conundrum is actually easily solved: In Java, the declaration FancyColor color adds a different field to instances of MyColorPoint that happens to have the same name as another field. Since it is a new, different field, it can have any type whatsoever, not necessarily related to the type of the other field named color. Field look-ups do not use dynamic dispatch, so any uses of color in methods of ColorPoint will still use the color field of type Color. In MyColorPoint, the new field shadows the old one, so color will refer to the new field. To access the old field, code can use super.color. Static Overloading A similar but more common and convenient weirdness relates to Java s support for having multiple methods with the same name. Even though it would be sound, there is simply no way in Java to override a method with contravariant arguments. Instead, Java works like this: If a class declares a method with name m, return type t0 and argument types t1, t2,..., tn (in that order), then: If the superclass already has a method name m with argument types t1, t2,..., tn (in that order), then this is overriding. The type-checker requires t0 to be the same as the return type in the superclass method or a subtype (covariant subtyping on result types). Else this is a new method added to the subclass, not overriding, even if the superclass (or the subclass) has other methods named m. 2

Having multiple methods with the same name can be convenient so that you do not have to think up different names for similar behavior. For example, a Rational class could have methods like: void add(rational r) {... void add(int i) {... void add(double d) {... But you must take care in Java to make sure you are overriding or not overriding when you intend to. It can be confusing to change or reorder argument types accidentally and, as a result, have different methods with the same name. More importantly, we need to define which method gets called when there are multiple methods with the right name. That is, we must revise our definition of the most fundamental issue in object-oriented programming: What is the semantics of e0.m(e1,...,en)? As before, we start as follows: Evaluate e0,..., en to objects v0,..., vn. Use the (run-time) class of v0 to look up m (dynamic dispatch). But now there may be multiple choices m. Java picks the best choice using the static types of e1,..., en, not the classes v0,..., vn. This semantics is called static overloading since we overload the name m to mean multiple things and disambiguate using the static types of the arguments. It is not dynamic dispatch on the arguments, which would be a different semantics called multimethods. There are programming languages with multimethods, but Java and C# do not have them. The exact definition of best choice is remarkably complicated and we will not explain all the rules, but we will give the rough idea and some examples. Simple cases like the add methods for Rational are easy: Type-checking the argument should produce an int, double, or Rational and the best choice should be obvious. But even here we allow a subtype of Rational (using subtyping to pick the method that takes a Rational) or other numeric types (using a conversion to pick either the int version or the double version according to rules spelled out in the language definition). Also note that we always pick a method with the correct number of arguments. And if there is no choice that would type-check, the call, as usual, does not type-check. Here is a more complicated example where we have 5 methods named m and the comments next to the methods and example method calls indicate which method will get used by each call: class Color extends Object { String s; class FancyColor extends Color { double shade; class MyClass { void m(object x) {... // A void m(color x) {... // B void m(fancycolor x) {... // C void m(color x, FancyColor y) {... // D void m(fancycolor x, Color y) {... // E MyClass obj = new MyClass(...); Color c1 = new Color(...); FancyColor c2 = new FancyColor(...); Color c3 = new FancyColor(...); // subtyping! obj.m(c1); // B obj.m(c2); // C 3

obj.m(c3); // B static overloading! obj.m(c1,c2); // D obj.m(c1,c3); // type error: no method matches obj.m(c2,c2); // type error: no best match (tie) We now explain each of the six calls in more detail: obj.m(c1) calls m with one argument of type Color. Either method A or B would type-check, but since B requires less subtyping, it is picked. obj.m(c2) is similar: it calls m with one argument of type FancyColor. Even though A, B, and C all type-check, C requires the least subtyping. obj.m(c3) is handled exactly like obj.m(c1) because c1 and c3 both have type Color. In Java, it is irrelevant that the result of evaluating c3 is an instance of the FancyColor class. Under static overloading, we still pick method B. obj.m(c1,c3) calls m with two arguments of type Color. This does not type-check because none of the methods can take such arguments: the two-argument methods both require at least one argument to be a FancyColor. Again the fact that evaluating c3 would produce an instance of FancyColor class is irrelevant. obj.m(c2,c2) does not type-check for a fundamentally different reason: Methods D and E would both type-check and since they tie in the amount of subtyping, the type-checker rejects the call rather than break the tie. We can break the tie ourselves by rewriting the call as either obj.m((color)c2,c2), which would call D, or as obj.m(c2,(color)c2), which would call E. Or we could add another method m to MyClass that takes two FancyColor arguments. Names vs. Structure Remember that the type systems in Java and C# use class and interface names as types and allow subtyping only as indicated by explicit subclassing and implementation of interfaces. So, for example, the type ThreeActPlay is not a subtype of StringPair even though it would be fine from the perspective of record subtyping: class StringPair { String first; String second; void setfirst(string x) {... class ThreeActPlay { String first; String second; String third; void setfirst(string x) {... To have ThreeActPlay <: StringPair we would have to make ThreeActPlay an explicit subclass. Whether we want such subtyping is disputable. On the one hand, it would let us reuse some code for StringPair objects without any risk of a method missing error. On the other hand, ThreeActPlay and StringPair are rather separate concepts and it can be a virtue to have the type-checker given an error if we (accidentally?) use an expression of one type where we expect the other. 4

Classes vs. Types Classes and types are different things! Java and C# purposely confuse them as a matter of convenience, but you should keep the concepts separate. A class defines an object s behavior. Subclassing inherits behavior, modifying behavior via extension and override. A type describes what fields an object has and what messages it can respond to. Subtyping is a question of substitutability and what we want to flag as a type error. It is often grating to the ears of a programming-languages expert to hear things like, overriding the method in the supertype or, using subtyping to pass an argument of the superclass. That said, this confusion is understandable in languages where every class declaration introduces a class and a type with the same name. If, like in Ruby, subclasses did not have to be subtypes, then we could allow overriding to change the types of methods. But this is a dangerous practice: If the overridden method is used by inherited methods of the superclass, then those methods might no longer type-check in the subclass. Conversely, subtypes do not have to subclasses given features like interfaces, but we still require class declarations to indicate what interfaces are supertypes. There is no fundamental reason for this. For example, if the Launchable interface had just one method requirement void launch();, then we could implicitly let any class with such a method have its type be a subtype of Launchable. This could allow more code, but could lead to errors, e.g., if we do not want to allow a Missile to be passed to a method that takes a Launchable. As discussed in a previous lecture, abstract methods, like interfaces, are related to the type part of a class declaration not the behavior part. An abstract method indicates that all values of the type will have such a method, but it provides no behavior for subclasses to inherit. Covariant self/this As a final subtle detail and advanced point, Java s this is treated specially from a type-checking perspective. When type-checking a class C, we know this will have type C or a subtype, so it is sound to assume it has type C. In a subtype, e.g., in a method overriding a method in C, we can assume this has the subtype. None of this causes any problems, and it is essential for OOP. For example, in class B below, the method m can type-check only if this has type B, not just A. class A { int m(){ return 0; class B extends A { int x; int m(){ return x; But if you recall our manual encoding of objects in an earlier lecture, the encoding passed this as an extra explicit argument to a method. That would suggest contravariant subtyping, meaning this in a subclass could not have a subtype, which it needs to have in the example above. It turns out this is special in the sense that while it is like an extra argument, it is an argument that is covariant. How can this be? Because it is not a normal argument where callers can choose anything of the correct type. Methods are always called with a this argument that is a subtype of the type the method expects. This is the main reason why coding up dynamic dispatch manually works much less well in statically typed languages, even if they have subtyping: You need special support in your type system for this. 5