Imperative Programming 2: Traits

Similar documents
Programming in Scala Mixin inheritance Summer 2008

Imperative Programming 2: Inheritance 1

CS Programming Languages: Scala

G Programming Languages - Fall 2012

Bibliography. Analyse et Conception Formelle. Lesson 5. Crash Course on Scala. Scala in a nutshell. Outline

Imperative Programming 2: Circuit simulation

Software Engineering: Design & Construction

Programming Languages

Introduction to Scala

Overview. Elements of Programming Languages. Objects. Self-Reference

CS 2340 Objects and Design - Scala

Overview. Elements of Programming Languages. Advanced constructs. Motivating inner class example

Overview. Elements of Programming Languages. Objects. Self-Reference

Announcements. CSCI 334: Principles of Programming Languages. Lecture 16: Intro to Scala. Announcements. Squeak demo. Instructor: Dan Barowy

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

CS205: Scalable Software Systems

Copyright 2018 Tendril, Inc. All rights reserved.

Graphical Interface and Application (I3305) Semester: 1 Academic Year: 2017/2018 Dr Antoun Yaacoub

Exercise 6 Multiple Inheritance, Multiple Dispatch and Linearization November 4, 2016

The SCAlable LAnguage

Scala. The scalabale Language. May 30, Department of Computer Sciences University of Salzburg. Functional Features Object oriented Features

Object-oriented programming

15 Multiple Inheritance and Traits

CS558 Programming Languages

CS205: Scalable Software Systems

Learning Scala Seminar 2

Scala. Fernando Medeiros Tomás Paim

Programming in Scala Second Edition

Scala : an LLVM-targeted Scala compiler

An Introduction to Scala for Spark programming

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

Scala - Some essential concepts -

Inheritance. Transitivity

Object Oriented Programming in Java. Jaanus Pöial, PhD Tallinn, Estonia

Inheritance (Part 5) Odds and ends

Advanced Object-Oriented Languages Scala

PROGRAMMING LANGUAGE 2

Lecture 10. Overriding & Casting About

Notes from a Short Introductory Lecture on Scala (Based on Programming in Scala, 2nd Ed.)

Example: Count of Points

Optimizing Higher-Order Functions in Scala

First Programming Language in CS Education The Arguments for Scala

Stateful Objects. can I withdraw 100 CHF? may vary over the course of the lifetime of the account.

Life in a Post-Functional World

Linked lists and the List class

abstract classes & types

Example: Count of Points

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

Exercise 6 Multiple Inheritance, Multiple Dispatch and Linearization November 3, 2017

HAS-A Relationship. If A uses B, then it is an aggregation, stating that B exists independently from A.

CS 6112 (Fall 2011) Foundations of Concurrency

17 From Delegation to Inheritance

Collections and Combinatorial Search

More About Objects. Zheng-Liang Lu Java Programming 255 / 282

Name Return type Argument list. Then the new method is said to override the old one. So, what is the objective of subclass?

Control Structures. Christopher Simpkins CS 3693, Fall Chris Simpkins (Georgia Tech) CS 3693 Scala / 1

Recap from last time. Programming Languages. CSE 130 : Fall Lecture 3: Data Types. Put it together: a filter function

Lecture 24: Implementing Heaps 10:00 AM, Mar 21, 2018

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

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

Subtyping (Dynamic Polymorphism)

OOP in Java Review. CS356 Object-Oriented Design and Programming October 1, 2014

Exercise 6 Multiple Inheritance, Multiple Dispatch and Linearization November 3, 2017

Programs as Data. The Scala language

Homework 8. What To Turn In. Reading. Self Check. Problems. Handout 19 CSCI 334: Spring, 2017

Software Engineering Design & Construction

Instance Members and Static Members

n n Official Scala website n Scala API n

Exercise 8 Parametric polymorphism November 18, 2016

Java Inheritance. Written by John Bell for CS 342, Spring Based on chapter 6 of Learning Java by Niemeyer & Leuck, and other sources.

Inheritance (Extends) Overriding methods IS-A Vs. HAS-A Polymorphism. superclass. is-a. subclass

CS558 Programming Languages

Encoding Scala Programs for the Boogie Verifier. Valentin Wüstholz

Final Exam. Programming Assignment 3. University of British Columbia CPSC 111, Intro to Computation Alan J. Hu. Readings

Superclasses / subclasses Inheritance in Java Overriding methods Abstract classes and methods Final classes and methods

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

Inheritance & Polymorphism

Lecture 2: Java & Javadoc

n n Try tutorial on front page to get started! n spring13/ n Stack Overflow!

22. Subtyping, Inheritance and Polymorphism

Object-Oriented Concepts

Class Hierarchy and Interfaces. David Greenstein Monta Vista High School

C++ Important Questions with Answers

Inheritance. Notes Chapter 6 and AJ Chapters 7 and 8

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

First IS-A Relationship: Inheritance

SCALA ARRAYS. Following picture represents array mylist. Here, mylist holds ten double values and the indices are from 0 to 9.

The story so far. Elements of Programming Languages. While-programs. Mutable vs. immutable

The class Object. Lecture CS1122 Summer 2008

Inheritance and Interfaces

Lab 2: Object-Oriented Design 12:00 PM, Jan 31, 2018

Abstract Classes. Abstract Classes a and Interfaces. Class Shape Hierarchy. Problem AND Requirements. Abstract Classes.

Concepts of Object-Oriented Programming Peter Müller

Late Binding; OOP as a Racket Pattern

Arrays Classes & Methods, Inheritance

Week 8: Functions and States

Object Oriented Programming. Java-Lecture 11 Polymorphism

Scala, Your Next Programming Language

The fringe of a binary tree are the values in left-to-right order. For example, the fringe of the following tree:

More about inheritance

Transcription:

Imperative Programming 2: Traits Hongseok Yang University of Oxford

Experience with traits so far In IP1, you have used traits as interfaces, in order to specify available methods and fields. trait IntQueue { def get(): Int def put(x: Int): Unit import scala.collection.mutable.arraybuffer class ArrayQueue extends IntQueue { private val buf = new ArrayBuffer[Int] def get() = buf.remove(0) def put(x: Int) { buf += x But traits are more powerful. This power is frequently used in practice.

Experience with traits so far In IP1, you have used traits as interfaces, in order to specify available methods and fields. trait IntQueue { def get(): Int def put(x: Int): Unit class ListQueue extends IntQueue { private var l: List[Int] = List() def get() =... def put(x: Int) {... import scala.collection.mutable.arraybuffer class ArrayQueue extends IntQueue { private val buf = new ArrayBuffer[Int] def get() = buf.remove(0) def put(x: Int) { buf += x But traits are more powerful. This power is frequently used in practice.

Experience with traits so far In IP1, you have used traits as interfaces, in order to specify available methods and fields. trait IntQueue { def get(): Int def put(x: Int): Unit class ListQueue extends IntQueue { private var l: List[Int] = List() def get() =... def put(x: Int) {... import scala.collection.mutable.arraybuffer class ArrayQueue extends IntQueue { private val buf = new ArrayBuffer[Int] def get() = buf.remove(0) def put(x: Int) { buf += x But traits are more powerful. This power is frequently used in practice.

Today s lecture We will study powerful features of traits, and discuss about idioms of using them.

Features of traits 1. We can define methods and fields in a trait. 2. Multiple traits can be inherited simultaneously. 3. They support so called stackable modification, a powerful mechanism for composing traits.

1. We can define methods and fields in a trait. [Q] Add putl(xs:list[int]){... Easy implementation of rich interfaces.

1. We can define methods and fields in a trait. [Q] Add putl(xs:list[int]){... Easy implementation of rich interfaces. trait IntQueue { def get(): Int def put(x: Int): Unit import scala.collection.mutable.arraybuffer class ArrayQueue extends IntQueue { private val buf = new ArrayBuffer[int] def get() = buf.remove(0) def put(x: Int) { buf += x class ListQueue extends IntQueue { private var l: List[Int] = List() def get() = { val res = l.head; l = l.tail; res def put(x: Int) { l = l :+ x

1. We can define methods and fields in a trait. [Q] Add putl(xs:list[int]){... Easy implementation of rich interfaces. trait IntQueue { def get(): Int def put(x: Int): Unit def putl(xs: List[Int]) { for(x<-xs) put(x) import scala.collection.mutable.arraybuffer class ArrayQueue extends IntQueue { private val buf = new ArrayBuffer[int] def get() = buf.remove(0) def put(x: Int) { buf += x class ListQueue extends IntQueue { private var l: List[Int] = List() def get() = { val res = l.head; l = l.tail; res def put(x: Int) { l = l :+ x

1. We can define methods and fields in a trait. [Q] Add putl(xs:list[int]){... [Q] What s the problem of this alternative? trait IntQueue trait IntQueue { { def get(): def Int get(): Int def put(x: def Int): put(x: Unit Int): Unit def putl(xs: def putl(xs: List[Int]) List[Int]): { for(x<-xs) Unit put(x) import scala.collection.mutable.arraybuffer import scala.collection.mutable.arraybuffer class ArrayQueue extends IntQueue { class ArrayQueue private extends val buf IntQueue = new ArrayBuffer[int] { private val def buf get() = new = buf.remove(0) ArrayBuffer[int] def get() def = buf.remove(0) put(x: Int) { buf += x def put(x: def Int) putl(xs: { buf List[Int]) += x { but ++= xs class ListQueue extends IntQueue { class ListIntQueue private var extends l: List[Int] IntQueue = { List() private var def l: get() List[Int] = { val = res List() = l.head; l = l.tail; res def get() def = { put(x: val res Int) = l.head; { l += x l = l.tail; res def put(x: def Int) putl(xs: { l += List[Int]) x { l ++= xs

1. We can define methods and fields in a trait. [Q] Add putl(xs:list[int]){... [Q] What s the problem of this alternative? By defining methods in a trait, we can easily support rich interfaces without duplicating code. By defining N functions, trait IntQueue { def get(): Int def put(x: Int): Unit def putl(xs: List[Int]) { for(x<-xs) put(x) def putupto(upper: Int) { for(x<- 1 to upper) put(x) def remove(n: Int) { for(i<-1 to n) get()... class ArrayQueue extends IntQueue... class ListQueue extends IntQueue... we can add 2xN methods

1. We can define methods and fields in a trait. 2. Multiple traits can be inherited simultaneously. Syntax:... extends T0 with T1... with Tn

1. We can define methods and fields in a trait. 2. Multiple traits can be inherited simultaneously. Syntax:... extends T0 with T1... with Tn trait IntQueue { def get(): Int def put(x: Int): Unit def putl(xs: List[Int]) { for(x<-xs) put(x) trait Ordered[A] { def compare(that: A): Int def <(that: A): Boolean = (this compare that) < 0 def >(that: A): Boolean = (this compare that) > 0 def <=(that: A): Boolean = (this compare that) <= 0 import scala.collection.mutable.arraybuffer class ArrayQueue extends IntQueue with Ordered[ArrayQueue]{ private val buf = new ArrayBuffer[int] def get() = buf.remove(0) def put(x: Int) { buf += x def compare(that: ArrayQueue) = buf.length - that.buf.length

1. We can define methods and fields in a trait. 2. Multiple traits can be inherited simultaneously. Syntax:... extends T0 with T1... with Tn The same syntax for trait definition. Terminology: We mix in Ti s. Methods in T, T1,... and Tn are combined in an intricate way. In particular, super.meth(..) in a trait has a special semantics that affects this combination. This is exploited in the stackable modification pattern.

Any is a superclass of everything. It defines basic methods, like ==,!=, equals, hashcode, etc. AnyVal is a superclass of all values. AnyRef is a superclass of all user-defined classes.

Any is a superclass of everything. It defines basic methods, like ==,!=, equals, hashcode, etc. AnyVal is a superclass of all values. AnyRef is a superclass of all user-defined classes.

Any is a superclass of everything. It defines basic methods, like ==,!=, equals, hashcode, etc. AnyVal is a superclass of all values. AnyRef is a superclass of all user-defined classes.

Default trait inheritance If the extend clause is missing, a trait inherits from the Scala class AnyRef. trait IntQueue { def get(): Int def put(x: Int): Unit def putl(xs: List[Int]) { for(x<-xs) put(x) Any AnyRef IntQueue

Linearization class C extends T0 with T1... with Tn trait T extends T0 with T1... with Tn Linearization determines a linear order of all inherited classes and traits by C and T. Recursive algorithm : Handle T0,... then Tn, finally C/T. Recursive step : Extend the current linearization by adding classes and traits that are inherited by Ti (including Ti) but not linearized so far. trait Animal trait Furry extends Animal trait HasLegs extends Animal trait FourLegged extends HasLegs class Cat extends Animal with Furry with FourLegged

Linearization class C extends T0 with T1... with Tn trait T extends T0 with T1... with Tn Linearization determines a linear order of all inherited classes and traits by C and T. It decides methods to be called. Recursive step : Extend the current linearization by trait Animal { def f(){ println( A ) adding classes and traits that are inherited by Ti trait Furry extends Animal { override def f(){ println( F ) trait HasLegs extends Animal { override def f(){ println( H ) (including Ti) but not linearized so far. trait FourLegged extends HasLegs class Cat extends Animal with Furry with FourLegged (new Cat).f()

super.m in a trait super.m in a trait T is bound not when the trait T is defined, but when it is mixed in. super.m is resolved according to linearization. It refers to the most recent m defined in a class or trait before T in the linearization. Use the keyword abstract override when m is not override defined in f(){ a superclass super.f(); println( F ) or supertrait of T. trait Animal { def f(){ println( A ) trait Furry extends Animal { trait HasLegs extends Animal { override def f(){ super.f(); println( H ) trait FourLegged extends HasLegs class Cat extends Animal with Furry with FourLegged (new Cat).f()

super.m in a trait Use the keyword abstract override when m is not defined in a superclass or supertrait of T. trait Animal { def f() trait NormalAnimal extends Animal { def f() { println( NA ) trait Furry extends Animal { abstract override def f(){ super.f(); println( F ) trait HasLegs extends Animal { abstract override def f(){ super.f(); println( H ) trait FourLegged extends HasLegs class Cat extends NormalAnimal with Furry with FourLegged (new Cat).f()

super.m in a trait Stackable modification: Implement a new functionality by mixing in traits with super calls in a particular order. Use the keyword abstract override when m is not defined in a superclass or supertrait of T. trait Animal { def f() trait NormalAnimal extends Animal { def f() { println( NA ) trait Furry extends Animal { abstract override def f(){ super.f(); println( F ) trait HasLegs extends Animal { abstract override def f(){ super.f(); println( H ) trait FourLegged extends HasLegs class Cat extends NormalAnimal with Furry with FourLegged class Cat2 extends NormalAnimal with FourLegged with Furry (new Cat).f(); (new Cat2).f()

Exercise: Fill in the boxes trait IntQueue { def get(): Int def put(x: Int): Unit import scala.collection.mutable.arraybuffer class ArrayQueue extends IntQueue { private val buf = new ArrayBuffer[int] def get() = buf.remove(0) def put(x: Int) { buf += x trait Filtering extends IntQueue { abstract override def put(x:int) { if (x > 0) super.put(x) trait Doubling extends IntQueue { abstract override put(x: Int) { super.put(2*x) trait Increasing extends IntQueue { abstract override put(x: Int) { super.put(1+x) class IncFilteringArrayQueue extends ArrayQueue with Filtering with Increasing class IncFilterDoubleArrayQueue extends ArrayQueue with Doubling with Filtering with Increasing

Exercise: Fill in the boxes trait IntQueue { def get(): Int def put(x: Int): Unit import scala.collection.mutable.arraybuffer class ArrayQueue extends IntQueue { private val buf = new ArrayBuffer[int] def get() = buf.remove(0) def put(x: Int) { buf += x trait Filtering extends IntQueue { abstract override def put(x:int) { if (x > 0) super.put(x) trait Doubling extends IntQueue { abstract override def put(x:int) { super.put(2*x) trait Increasing extends IntQueue { abstract override def put(x:int) { super.put(1+x) class IncFilteringArrayQueue extends ArrayQueue with Filtering with Increasing class IncFilterDoubleArrayQueue extends ArrayQueue with Doubling with Filtering with Increasing

Trait vs class When do you want to use traits? When do you want to use classes or abstract classes?

Summary Traits can include method and field definitions. Multiple traits can be inherited simultaneously. Linearization determines their inheritance hierarchy. Traits support stackable modification via super call. Read Chap 12.