Subclassing for ADTs Implementation

Similar documents
16 Multiple Inheritance and Extending ADTs

Object-Oriented Design Lecture 11 CS 3500 Spring 2010 (Pucella) Tuesday, Feb 16, 2010

17 Multiple Inheritance and ADT Extensions

3 ADT Implementation in Java

Object-Oriented Design Lecture 13 CSU 370 Fall 2008 (Pucella) Friday, Oct 31, 2008

Object-Oriented Design Lecture 3 CSU 370 Fall 2007 (Pucella) Friday, Sep 14, 2007

Code Reuse: Inheritance

Object-Oriented Design Lecture 23 CS 3500 Fall 2009 (Pucella) Tuesday, Dec 8, 2009

CS3500: Object-Oriented Design Fall 2013

20 Subclassing and Mutation

Lecture 5: Implementing Lists, Version 1

8 Hiding Implementation Details

Equality for Abstract Data Types

The Java Type System (continued)

CS 151. Linked Lists, Recursively Implemented. Wednesday, October 3, 12

7 Code Reuse: Subtyping

Index. Index. More information. block statements 66 y 107 Boolean 107 break 55, 68 built-in types 107

Data abstractions: ADTs Invariants, Abstraction function. Lecture 4: OOP, autumn 2003

Declarations and Access Control SCJP tips

Binghamton University. CS-140 Fall Problem Solving. Creating a class from scratch

Algebraic Specifications

CMSC 132: Object-Oriented Programming II

Lecture 7: Implementing Lists, Version 2

Chapter 5 Object-Oriented Programming

Contents. I. Classes, Superclasses, and Subclasses. Topic 04 - Inheritance

Object-Oriented Design Lecture 21 CSU 370 Fall 2008 (Pucella) Tuesday, Dec 9, 2007

JAVA MOCK TEST JAVA MOCK TEST II

Classes, interfaces, & documentation. Review of basic building blocks

Classes Classes 2 / 36

1 Shyam sir JAVA Notes

More on Objects in JAVA TM

Why Design by Contract! CS 619 Introduction to OO Design and Development. Design by Contract. Fall 2012

CS 61B Discussion 5: Inheritance II Fall 2014

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

A Model of Mutation in Java

CS/ENGRD 2110 SPRING Lecture 7: Interfaces and Abstract Classes

Programming in C++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

JAVA BASICS II. Example: FIFO

CS1004: Intro to CS in Java, Spring 2005

Weiss Chapter 1 terminology (parenthesized numbers are page numbers)

Designing Robust Classes

Object-Oriented Design Lecture 16 CS 3500 Fall 2010 (Pucella) Friday, Nov 12, 2010

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

Chapter 6 Introduction to Defining Classes

Inheritance. Inheritance Reserved word protected Reserved word super Overriding methods Class Hierarchies Reading for this lecture: L&L

Goal. Generic Programming and Inner classes. Minor rewrite of linear search. Obvious linear search code. Intuitive idea of generic linear search

6.005 Elements of Software Construction Fall 2008

Advanced JML Erik Poll Radboud University Nijmegen

Introduction to Programming Using Java (98-388)

11 Parameterized Classes

Inheritance. Lecture 11 COP 3252 Summer May 25, 2017

13 Subtyping Multiple Types

Language Features. 1. The primitive types int, double, and boolean are part of the AP

Zhifu Pei CSCI5448 Spring 2011 Prof. Kenneth M. Anderson

CSC Java Programming, Fall Java Data Types and Control Constructs

CS-140 Fall 2017 Test 2 Version A Nov. 29, 2017

CMPSCI 187: Programming With Data Structures. Lecture 12: Implementing Stacks With Linked Lists 5 October 2011

c) And last but not least, there are javadoc comments. See Weiss.

CS 6456 OBJCET ORIENTED PROGRAMMING IV SEMESTER/EEE

Polymorphism. return a.doublevalue() + b.doublevalue();

Programming II (CS300)

12 Implementing Subtyping

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

For this section, we will implement a class with only non-static features, that represents a rectangle

CMSC 132: Object-Oriented Programming II

Lecture 7: Data Abstractions

3.Constructors and Destructors. Develop cpp program to implement constructor and destructor.

Synchronization SPL/2010 SPL/20 1

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

Outline. Computer Science 331. Information Hiding. What This Lecture is About. Data Structures, Abstract Data Types, and Their Implementations

Chapter 4 Defining Classes I

Midterm Exam (REGULAR SECTION)

Implementing a List in Java. CSC 143 Java. List Interface (review) Just an Illusion? Using an Array to Implement a List CSC

Prelim 1. CS 2110, September 29, 2016, 7:30 PM Total Question Name Loop invariants

CS Internet programming Unit- I Part - A 1 Define Java. 2. What is a Class? 3. What is an Object? 4. What is an Instance?

CS-140 Fall 2017 Test 1 Version Practice Practice for Nov. 20, Name:

Implementing a List in Java. CSE 143 Java. Just an Illusion? List Interface (review) Using an Array to Implement a List.

AP COMPUTER SCIENCE JAVA CONCEPTS IV: RESERVED WORDS

Class, Variable, Constructor, Object, Method Questions

Announcements. CS18000: Problem Solving And Object-Oriented Programming

CS 360 Programming Languages Day 14 Closure Idioms

Software Construction

Inheritance. Transitivity

15 Multiple Inheritance and Traits

Array Based Lists. Collections

C a; C b; C e; int c;

boolean, char, class, const, double, else, final, float, for, if, import, int, long, new, public, return, static, throws, void, while

Subclass Gist Example: Chess Super Keyword Shadowing Overriding Why? L10 - Polymorphism and Abstract Classes The Four Principles of Object Oriented

The list abstract data type defined a number of operations that all list-like objects ought to implement:

Cloning Enums. Cloning and Enums BIU OOP

Object-Oriented Design Lecture 5 CSU 370 Fall 2008 (Pucella) Friday, Sep 26, 2008

CS18000: Programming I

Inheritance (Part 5) Odds and ends

Index COPYRIGHTED MATERIAL

Recursive Data and Recursive Functions

Implementing a List in Java. CSE 143 Java. List Interface (review) Just an Illusion? Using an Array to Implement a List.

public static boolean isoutside(int min, int max, int value)

CS/ENGRD 2110 SPRING 2018

Object-Oriented Programming

Agenda. Objects and classes Encapsulation and information hiding Documentation Packages

Transcription:

Object-Oriented Design Lecture 8 CS 3500 Fall 2009 (Pucella) Tuesday, Oct 6, 2009 Subclassing for ADTs Implementation An interesting use of subclassing is to implement some forms of ADTs more cleanly, especially ADTs that have different representations for their values. Let me use a simple ADT that you are familiar with, integer lists, with the following signature and specification: public static List empty (); public static List cons (int, List); public boolean isempty (); public int first (); public List rest (); public String tostring (); empty().isempty() = true cons(i,s).isempty() = false cons(i,s).first() = i cons(i,s).rest() = s empty().tostring() = "<empty>" cons(i,s).tostring() = i + " " + s.tostring() Consider the following direct implementation of the List ADT as a linked list: public class List { private Integer firstelement; private List restelements; private List (Integer i, List s) { firstelement = i; restelements = s; public static List empty () { return new List(null,null); 1

public static List cons (int i, List s) { return new List(new Integer (i),s); // class Integer lets you use null as a value public boolean isempty () { return (this.firstelement == null); public int first () { if (this.isempty()) throw new IllegalArgumentException("first() on empty list"); return this.firstelement; public List rest () { if (this.isempty()) throw new IllegalArgumentException("rest() on empty list"); return this.restelements; public String tostring () { if (this.isempty()) return "<empty>"; return this.first() + " " + this.rest(); This code and its underlying representation is ugly, and I mean that as a technical term. Part of the problem is that there is an implicit invariant: whenever the firstelement field is not null, then the restelements field better not be null either. (Can you see what can go wrong if we do not respect this invariant?) We must make sure that the implementation always preserves that invariant. There are ways around that, making the invariant more robust, but they re a bit unsatisfying. Another problem with the implementation is that there are all kinds of checks in the code that test whether the list is empty or not. It would be much better to instead have two kinds of lists, an empty list and a cons list, and have them implement their respective methods knowing full well what their representation is. This is what we re going to explore now. We will use subclasses to keep track of the kind of list we have, and the subclasses will implement their methods in full confidence that the list they are manipulating is of the right kind, without needing to check the representation. 2

But that means that the List class, by itself, does not represent anything. The representation is in the subclasses. It does not make sense to create an object of type List anymore. We will only create an object of class EmptyList or ConsList, as they will be named. To enforce this, we are going to make the List class abstract. An abstract class is a class that cannot be instantiated. 1 Therefore, it does not have a Java constructor. The only use of an abstract class is to serve as a superclass for other classes. An abstract class need not implement all its methods. It can have abstract methods that simply promise that subclasses will implement those methods. (Java will enforce this, by making that all concrete subclasses of the abstract class do provide an implementation for the methods.) Here is a recipe for implementing an immutable ADT that is specified by an algebraic specification using subclasses. Let T be the name of the ADT. Assumptions on the structure of the ADT interface: Assume that the signature is given in OO-style: except for the basic creators, each operation of the ADT takes an implicit argument which is an object of type T. Except for the basic creators, each operation is specified by one or more equations. If an operation is specified by more than one equation, then the left hand sides of the equations differ according to which basic creator was used to create an argument of type T. The equations have certain other technical properties that allow them to be used as rewriting rules. We are to implement the ADT in Java. The creators of the ADT are to be implemented as static methods of a class named T. Other operations of the ADT are to be implemented as methods of a class named T. Steps of the recipe: Determine which operations of the ADT are basic creators and which are other operations. Define an abstract class named T. For each basic creator c, define a concrete subclass of T whose instance variables correspond to the arguments that are passed to c. For each such subclass, define a Java constructor that takes the same arguments as c and stores them into the instance variables. 1 In contrast, a class that can be instantiated is sometimes called a concrete class. 3

(So far we have defined the representation of T. Now we have to define the operations.) For each creator of the ADT, define a static method within the abstract class that creates and returns a new instance of the subclass that corresponds to c. For each operation f that is not a basic creator, define an abstract method f. For each operation f that is not a basic creator, and for each concrete subclass C of T, define f as a dynamic method within C that takes the arguments that were declared for the abstract method f and returns the value specified by the algebraic specification for the case in which Java s special variable this will be an instance of C. If the algebraic specification does not specify this case, then the code for f should throw a RuntimeException such as an IllegalArgumentException. Following this recipe for the List ADT above gives the following. Can you match the steps with what gets produced? public abstract class List { public static List empty () { return new EmptyList (); public static List cons (int i, List s) { return new ConsList (i,s); public abstract boolean isempty (); public abstract int first (); public abstract List rest (); public abstract String tostring (); class EmptyList extends List { public EmptyList () { public boolean isempty () { return true; public int first () { throw new IllegalArgumentException ("first() on empty list"); 4

public List rest () { throw new IllegalArgumentException ("rest() on empty list"); public String tostring () { return "<empty>"; class ConsList extends List { private int firstelement; private List restelements; public ConsList (int i, List s) { firstelement = i; restelements = s; public boolean isempty () { return false; public int first () { return this.firstelement; public List rest () { return this.restelements; public String tostring () { return this.first() + " " + this.rest(); Nested Classes Last time, we saw a recipe for deriving an implementation from an ADT specification. There are two problems with that approach, however, one minor, one major: (1) Namespace pollution (2) Extensibility 5

Let s take care of the minor one now. We ll return to the extensibility problem later in the course. Consider the List class as derived from the recipe. It consists of a public abstract class List, and two subclasses, EmptyList and ConsList. Now, because of the way Java works, either all of those classes must be made public, or, in the case where you decide to put all the classes in the same file, only List is made public, and the two subclasses are unannotated. This makes the two subclasses package-public: they are visible to other classes in the same package, but unavailable to classes outside the package. In other word, they are public for classes within the same package, but private for classes outside the package. In practice, the only class we really want to be able to create instances of EmptyList and ConsList is the List class. All list object creation should go through the List class static methods. In parts, this is because we rarely want to have objects specifically of class EmptyList or ConsList about, but rather only want to have List objects. The static creators in the List class ensure this is the case. So how do we prevent EmptyList and ConsList from being available even from within the package. The answer, which may or may not be obvious, is to simply package up the two subclasses directly within the List class, and make them private so that they cannot be accessed from outside the class. Here is the code: public abstract class List { public static List empty () { return new EmptyList (); public static List cons (int i, List s) { return new ConsList (i,s); public abstract boolean isempty (); public abstract int first (); public abstract List rest (); public abstract String tostring (); private static class EmptyList extends List { public EmptyList () { public boolean isempty () { return true; public int first () { 6

throw new IllegalArgumentException("first() on empty list"); public List rest () { throw new IllegalArgumentException("rest() on empty list"); public String tostring () { return "<empty>"; private static class ConsList extends List { private int firstelement; private List restelements; public ConsList (int i, List s) { firstelement = i; restelements = s; public boolean isempty () { return false; public int first () { return this.firstelement; public List rest () { return this.restelements; public String tostring () { return this.first() + " " + this.rest(); These are examples of nested classes. In fact, these are static nested classes. A static nested class is just like a class defined in its own file, except that it is defined within another class. (If a nested class T is defined as public within a class S, then class T can be accessed from outside S as S.T.) Why do we need the static qualifier? The static qualifier, as usual, indicates that the nested class is associated with the class definition itself. In particular, the nested class cannot access instance variables of the class containing it. (Nor can it invoke instance methods of the class containing it.) This essentially says that the nested class is defined only once, when the containing class is itself defined. Note that this is a containment relation. Class S contains class definition T, just like it contains static methods and static fields. (Without the static qualifier, a nested class (say T ) is associated with instances of the class 7

containing the definition (say S). Every instance of S redefines the nested class T. In particular, the nested class can refer to instance variables of S. When they are not static, nested classes are called inner classes. Inner classes are very powerful, and are related to closures, which can be used to do higher-order programming. In other words, inner classes give you lambda. We will not use inner classes much in this course, but it s good to know that they exist.) Nesting classes takes care of the namespace pollution problem. As I said, we will return to the extensibility problem later in a few lectures. 8