39
Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor: Yossi Gil

Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Embed Size (px)

DESCRIPTION

Three Kinds of Evolution I-Evolution: Moving down the inheritance tree. M-Evolution: Evolving by applying mixins. S-Evolution: Evolving by applying shakeins. Overview Motivation I-Evolution M-Evolution S-Evolution

Citation preview

Page 1: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Object Evolution A chapter from the research work on

Applying Aspect-Oriented Software Development to Middleware Frameworks

Tal Cohen

Research supervisor: Yossi Gil

Page 2: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Object Evolution• Dynamic reclassification: allowing an object to change

its type at runtime.– e.g., prince → frog.– Supported by Smalltalk, several others.– Many real-world uses

• e.g., State design pattern.

• Type safety problems…Prince p = new Prince();if (…) p → Frog();p.drawSword(); // potential runtime type error

• Our solution: limit to monotonic changes only.– "Object evolution" -- moving down the inheritance tree.– Prince → king is okay!

begin::Overview

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 3: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Three Kinds of Evolution

• I-Evolution: Moving down the inheritance tree.

• M-Evolution: Evolving by applying mixins.

• S-Evolution: Evolving by applying shakeins.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 4: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Contributions

• The case for object evolution.– Why you want your language to support this feature.

• Concrete language extension.– The idea is simple, the details are not trivial.

• Three kinds of evolution.– A language can support any one, two, or all.

• Analysis of potential failures.– What can go wrong, and how to cope with it.

• Implementation strategies.– The nitty-gritty details.

end::

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 5: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Motivation

Page 6: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

The State Design Pattern

begin::Motivation

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 7: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

State Example: TCPConnection

• TCPConnection responds differently to messages (open, close, etc.) depending on its state.

• Possible states: Listen, Established, Close.

• A switch statement in each method…!?

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 8: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

TCPConnection using State

• Two objects in memory• Repeated delegation code• API must be identical

– No state-specific public methods.

TCPConnectionopen()close()acknowledge()

TCPStateopen()close()acknowledge()

state

TCPEstablishedopen()close()acknowledge()

TCPListenopen()close()acknowledge()

TCPClosedopen()close()acknowledge()

state.open();

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 9: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Knowledge Refinement

• State pattern not applicable: subclass has many additional methods.– Should the "changeable" class contain the union of all

methods of all possible states!?• Creating a new object implies:

– Copying existing state (fields),– Chasing references.

MethodInvocation

ObjectRefx

MethodNameequals

ParamsList(y)

x.equals(y)Parsing the source line:

InterfaceMethodInvocation

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 10: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Lazy Data Structures

• A specific case of knowledge refinement.

• Example: XML/HTML parsing.– "Varying interface" problem particularly

acute.• Should the "Node" superclass include the

features of every possible node type?• 80 different node types in XHTML…

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 11: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Data Covarianceclass LinkedList { static class Node { Node next; Object data; … constructor not shown … }

Node head, tail;

void append(Object obj) { Node newNode = new Node(obj); … add newNode at end of list … }

class BidiLinkedList extends LinkedList { static class BidiNode extends Node { Node prev; … new constructor not shown … }

void append(Object obj) { BidiNode newNode = new BidiNode(obj); … add newNode at end of list … }

•Because each class needs a different node type, we can't use refinement.

•The result: code duplication.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 12: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Dynamic Shakeins

• Shakeins are a superior alternative to AspectJ-style aspects.

• Newer AOP languages support dynamic aspects.– Aspects can be applied/removed at runtime.

• Applying/removing a shakein at runtime implies changing the object's class!

• This was the original motivation for this work.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 13: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Dynamic Shakeins

• For example: given an object of type Account, we wish to enable logging.– From Account to Logging<Account>.– … and back, as needed.

• Another example: protect a List object by applying the ReadOnly shakein to it.– Turning it into ReadOnly<List> without

changing the list content.

end::

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 14: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

I-Evolution

Page 15: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

I-Evolution

• Move an object down the inheritance tree.

• Syntax: v → T(…)– v is an object reference.– T is a type.

• Must be a subtype of v's static type.– … indicates optional parameters.– → can be typed as ->.

begin::I-Evolution

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 16: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

I-Evolution Example 1

• Note that connection objects cannot be "recycled"

–No way to reverse state.–Solution: later…

class TCPConnection { // Listen state public void open() { … establish connection … this → TCPConnectionEstablished(); } …}

class TCPConnectionEstablished extends TCPConnection { public void close() { … close connection … this → TCPConnectionClosed(); } …} class TCPConnectionClosed

extends TCPConnectionEstablished { public void close() { throw new IllegalStateException(); } …}

• No need for method delegation.

• Only one object in memory.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 17: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

I-Evolution Example 2class LinkedList { static class Node { Node next; Object data; … constructor not shown … }

Node head, tail;

void append(Object obj) { Node newNode = new Node(obj); … add newNode at end of list … }

class BidiLinkedList extends LinkedList { static class BidiNode extends Node { Node prev; … new constructor not shown … }

void append(Object obj) { BidiNode oldTail = (BidiNode) tail; super.append(obj); tail → BidiNode(); tail.prev = oldTail; }

•BidiLinkedList.append is now a refinement of the inherited version.

•No code duplication!

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 18: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Evolvers

• The change from class T to subclass T' might require code execution.

• Required for preserving class invariants.

• For example: when evolving from LinkedList to BidiLinkedList, we must go over the list and turn each Node into a BidiNode.– And instate the prev pointer while doing so.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 19: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Evolver Example• The evolver

represents the "delta" between the superclass constructor and this class's constructor.

• However, it must take into account the possibility that the object is in a non-virgin state.

class BidiLinkedList extends LinkedList { static class BidiNode extends Node { Node prev; … }

public →BidiLinkedList() { // Evolver if (head == null) return; head → BidiNode(); BidiNode current = head; while (current.next != null) { current.next → BidiNode(); current.next.prev = current; current = current.next; } …

• If no evolver is specified, default evolvers can often be deduced.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 20: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

How Can I-Evolution Fail?

• I-Evolution never introduces runtime type errors.– i.e., when an object accepts a message, it

knows how to handle it.• Yet the evolution operation itself can fail.

• Failure #1: v → T(…), v is null.– Not an "empty operation" because we might

expect the evolver code to do something.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 21: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

How Can I-Evolution Fail?

• Failure #2: v → T(…), and the evolver code →T throws an exception.– Just as new can fail due to exceptions.

• Failure #3: v → T(…), but v's dynamic type is not a superclass of T.– Given:

– This might fail:

A

B C

void foo(A a) { a → B(); // But what if a instanceof C!?}

Note: This is just like the downcast operation (B)a can fail!

end::

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 22: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

M-Evolution

Page 23: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Mixin Example

• This mixin can be applied to any class that implements the List interface:

begin::M-E

volution

mixin ReadOnly { inherited public void add(Object o); inherited public void remove(int index);

public final void add(Object o) { throw new IllegalStateException(); }

public final void remove(int index) { throw new IllegalStateException(); }}

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 24: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Is "ReadOnly" Useful?

• We can now create objects of type, e.g., ReadOnly<Vector>.

• However, even the constructor of this class will fail to add items to it!

• The mixin looks useless, unless we can turn existing list objects into read-only.

• … Evolution!

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 25: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Evolving to ReadOnly

• ReadOnly<Vector> is a new class, which extends Vector.

• So we can use regular I-Evolution with it.• But a reference to List can actually be of

type Vector, ArrayList, LinkedList, or any other implementation class!

if (lst instanceof Vector) lst → ReadOnly<Vector>();else if (lst instanceof ArrayList) lst → ReadOnly<ArrayList>();else … unbounded number of possibilities …

I-Evolution doesn't cut it in this case.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 26: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

M-Evolution

• Syntax: v → M<v>(…)– v is an object reference.– M is a mixin.– v is evolved into the class created by

applying M to v's dynamic type!

lst → ReadOnly<lst>();… works for any implementation of List! …

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 27: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Idempotent Mixins

• M-Evolution can result in infinitely long inheritance threads, generated at runtime.– ReadOnly<ReadOnly<ReadOnly<Vector>>>

• To prevent this, if mixin M is marked @Idempotent (or detected to be idempotent), then applying M to M<T> yields M<T>.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 28: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

How Can M-Evolution Fail?

• Existing failures: Evolving null, exception-throwing evolvers.

• Avoided failures: never fails due to incorrect dynamic type!

• New failure type: inability to apply mixin.– Final class / final members.– Accidental overriding.

end::

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 29: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

S-Evolution

Page 30: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

What is a Shakein?

• A Shakein makes a re-implementation of a class.

• It does not change the type.– We get a new implementation of an existing

type.– Never introduces new non-private members.

• A parameterized, generic-like structure.

begin::S-E

volutionO

verviewM

otivationI-E

volutionM

-Evolution

S-E

volution

Page 31: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Shakein Example

shakein Logging { before execution of public methods { Log.log("Began " + methodName); }

after successful execution of same { Log.log(methodName + " ended successfully"); }

after failed execution of same { Log.log(methodName + " caused exception: " + e); }}

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 32: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

S-Evolution

• Syntax: v → S<v>(…)– v is an object reference.– S is a shakein.– v is evolved into the class created by

applying S to v's dynamic type!

obj → Logging<obj>();… works for just about any object! …

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 33: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Replacing One Shakein by Another

• S-Evolution does not change the object's type.– Only it's (implementation) class.

• It is therefore possible to undo S-Evolution without any risk for runtime type errors.

• Or, replace one shakein with another.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 34: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

State Groups

• A set of shakeins can be declared as belonging to the same state group.

• If S1, S2 S, then:– State transition: Applying S1 to S2<T> yields S1<T>.

• And vice versa.

– All states are idempotent: Applying S1 to S1<T> yields S1<T>.

• Likewise for S2.

• i.e., an object can only have one shakein (state) from a given state group.

• Note: idempotent mixins can be viewed as one-state groups.

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 35: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

State Group Exampleclass TCPConnection { // Default = listen state public void open() { … establish connection … this → Established<this>(); } …}

@StateGroup("Connection")shakein Established { public void close() { … close connection … this → Closed<this>(); } …}

@StateGroup("Connection")shakein Closed { public void reset() { this -> Listen<this>(); } …}

• Connection objects can now be recycled.

@StateGroup("Connection")shakein Listen { // Empty: restore default state}

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 36: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Dynamic Aspects with Shakeins@StateGroup("Log")shakein Logging { before execution of public methods { Log.log("Began " + methodName); }

after successful execution of same { Log.log(methodName + " ended successfully"); }

after failed execution of same { Log.log(methodName + " caused exception: " + e); }}

@StateGroup("Log")shakein NotLogging {

// Empty: restore default}

obj → Logging<obj>();…

obj → NotLogging<obj>();

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

• Unlike some other dynamic aspect solutions:

– No boolean test at every method call. – No list of aspects to iterate over.– Zero performance overhead when no

shakeins are applied.• However, applying/removing a dynamic

aspect (i.e., evolution) can be costly.– Depending on implementation strategy.– We expect this operation to be less

common than method invocation.

Page 37: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

How Can S-Evolution Fail?

• Existing failures: Evolving null, exception-throwing evolvers.

• Applying to final class / final members.• Avoided failures: never fails due to

incorrect dynamic type!• Never fails due to accidental

overriding!– Since no new members are introduced.

end::

Overview

Motivation

I-Evolution

M-E

volutionS

-Evolution

Page 38: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Summary

Page 39: Object Evolution A chapter from the research work on Applying Aspect-Oriented Software Development to Middleware Frameworks Tal Cohen Research supervisor:

Summary

• The quest for dynamic shakeins was successful.

• … with several extra benefits.• Language designers can choose any

subset of {I,M,S}-Evolution.• Some issues not discussed here:

– The fine details of evolvers.– Multi-state objects.– Implementation strategies.