CSC 517: Elegance and Inheritance, Part I Titus Barik (tbarik@ncsu.edu) Spring 2014.

Post on 04-Jan-2016

216 views 1 download

Transcript of CSC 517: Elegance and Inheritance, Part I Titus Barik (tbarik@ncsu.edu) Spring 2014.

CSC 517: Elegance and Inheritance, Part I

Titus Barik (tbarik@ncsu.edu)Spring 2014

Theory vs. Practice

• “I want to move to theory. Everything works in theory.” (John Cash)

• “Well, it may be all right in practice, but it will never work in theory.” (Warren Buffett)

Multiple Inheritance

• Diamond problem: Which method is called first?

• How can we handle this problem?

• Class D extends B, C

B C

A

D

Multiple Inheritance

• Exercise: Scala resolves method names using right-first depth-first search. Reduce all but last when redundancy occurs.

• Answer: – [D, C, A, B, A] which reduces to– [D, C, B, A]

• What is printed with the given trait?

C3 Linearization (Perl, Python)

1. Consistent extended precedence graph.

2. Local precedence order.3. Monotonicity

L[C(B1,B2,…,BN)] = [C] + merge(L[B1],…,L[BN], B1…BN)

Source: Barnett, et. al. A Monotonic Superclass Linearization for Dylan, 1996.

Merge Pre-requisites

• head(C1C2C3) = C1

• tail(C1C2C3) = C2C3

• C + C1C2C3 = CC1C2C3

(concatenation)

Merge Operation

Example: merge(DO, EO, DE)

•The merge of several sequences is a sequence that contains each of the elements of the input sequences.•An element that appears in more than one of the input sequences appears only once in the output sequence.•If two elements appear in the same input sequence, their order in the output sequence is the same as their order in the input sequence.

Merge Example, 1

• Class B extends D, E

• Class C extends D, F

• Class A extends B, C

E

O

DF

C B

A

Merge Example, 2

L[C(B1,B2,…,BN)] = [C] +

merge(L[B1],…,L[BN], B1…BN)

L[O] = O

L[D] = D + merge(O, O) = DO

L[E] = E + merge(O, O) = EO

L[F] = F + merge(O, O) = FO

L[B] = B + merge(DO, EO, DE)

= B + DEO = BDEO

E

O

DF

C B

AMerge results

Merge Example, 3L[C(B1,B2,…,BN)] = [C] + merge(L[B1],…,L[BN], B1…BN)

L[B] = B + merge(DO, EO, DE) = B + DEO = BDEO

L[C] = C + merge(DO, FO, DF) = C + DFO = CDFO

L[A] = A + merge(BDEO, CDFO, BC) = A + BCDEFO = ABCDEFO

E

O

DF

C B

A

Polymorphism

• Unbounded polymorphism. Is there an example of a language that has this?

• Java uses subtype polymorphism.• Categorizations: bounded and

dynamic (inheritance), unbounded and static (templates).

Dynamic Method Invocation

• Dynamic method invocation means that the JVM, when asked to invoke a method on an object, looks at the actual class (versus declared) of the object to find the method to execute.

• Dynamic binding or late binding.• Can’t override this in Java.

Overloading vs. Overriding

• Two methods with the same name are overloaded if they are in the same class*, but have different parameter lists.

• When a method is overridden, one of its subclasses declares a method of the same name, with the same signature.

A Fruity Example

• Fruit inherits from class Object.• Object: boolean equals(Object obj).• Fruit: boolean equals(Fruit fruit).• Is this overriding or overloading?

A Fruity Example

Object o = new Object();Fruit f = new Fruit();Object of = new Fruit();

f.equals(o);(calls object)f.equals(f); (calls fruit)f.equals(of);(calls object)

What about now?

o.equals(o);

o.equals(f);

o.equals(of);

of.equals(o);

of.equals(f); // tricky tricky

of.equals(of);

Last One

• One more change:– Add boolean equals(Object obj)to

Fruit.

• Now what? Panic?Fruit Object Fruit (Object)

f.equals(o) o.equals(o) of.equals(o)

f.equals(f) o.equals(f) of.equals(f)

f.equals(of) o.equals(of) of.equals(of)

Invocation Summary

• The compiler decides which overloaded method to call by looking at – the declared types of the arguments

• And at runtime:– binding to the most specialized object

(actual type) that can receive the message through dynamic method invocation.

• In Java, dynamic binding always occurs. You can’t bypass it, even with casting.

Ice Cream and Cake and Cake

• What is the object-oriented way of getting rich?

• Inheritance.

Interfaces

• Java (and C#) don’t have multiple inheritance, but how can we simulate it?

• “Program to an interface, not an implementation.” (GoF)

• Which is preferred:– ArrayList list = new ArrayList();– List list = new ArrayList();

Generics

• Even better:– ArrayList list = new ArrayList<Shape>();

• How do generics help us?– Shape s = new Shape();– list.add(s);– Shape q = List.get(0)

• Generics allow us to statically communicate type information to the compiler; use them everywhere.

Inheritance is tricky.

• We have done examples with inheritance, but when should it be used?

• Is Y an X? What does it mean for Y to be an X? (is-a relationship).

• Temptations:– Code reuse.– Subclassing for specializing.– Public interface.– Polymorphism (collections).

• In theory, this is great. But is it sufficient? Is it even a good reason?

Inheritance is overused.

• When all you have is a hammer, everything you see is a nail.

• What about the code reuse example?• Inheritance breaks encapsulation.

Why?• Favor composition over class

inheritance.

Is a Square a Rectangle?

Is a Square a Rectangle?

Class Rectangle {

private int width, height;

public

Rectangle(int w, int h);

public int getWidth();

public setWidth(int width);

...

public setSize(int w, int h);

}

http://www.objectmentor.com/resources/articles/lsp.pdf

Uh-oh Spaghettios

• Constructor: Square(int s);• setSize(int w, int h)

– Let’s remove it, but derived classes requiring changes to base classes already indicates a bad design.

• setHeight(5) => changes width.– Are we now okay?

• r.getWidth() * r.getHeight()

Validity is not instrinsic and cannot be viewed in isolation.

A square is a rectangle, but a square object is not a rectangle object.

Inheritance Formalization

• Liskov substitution principle, easy in theory, difficult in practice to get right.

• Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T.

• You’re probably thinking: “I hope this isn ’t on the exam.”

• But you would be wrong.

Direct From the Java API

• Remember code reuse? Inheritance is all or nothing.• “Because Properties inherits from Hashtable, the

put and putAll methods can be applied to a Properties object. Their use is strongly discouraged as they allow the caller to insert entries whose keys or values are not Strings. The setProperty method should be used instead. If the store or save method is called on a “compromised” Properties object that contains a non-String key or value, the call will fail.”

• Didn’t you get the memo?• Yeah. I got the memo. And I understand the policy.

And the problem is just that I forgot the one time. And I've already taken care of it so it's not even really a problem anymore.

Real-World Violations of LSP

• In practice*:– Java violates LSP (unmodifiableList).– Ruby violates LSP (dup method).– C# probably violates LSP.

Ruby Example

irb> 5.respond_to? :dup

=> true

irb> 5.dup

TypeError: can't dup Fixnum

from (irb):1:in `dup'

from (irb):1

•And I would have gotten away with it too, if it weren't for you meddling kids…

Real-World Violations of LSP?

• Workarounds:– Java fine print: “Returns an unmodifiable view of the specified

list. This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or

via its iterator, result in an UnsupportedOperationException. “– Ruby dup method (found in Object). It’s

dynamic, get over it. We don’t have a contract.

– C# workaround is to seal everything, but this breaks the open-closed principle.