assertions prasun dewan comp 114. assertions declare some property of the program potentially useful...

Post on 19-Dec-2015

212 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Assertions

Prasun Dewan

Comp 114

Assertions

• Declare some property of the program

• Potentially useful for– specification– testing– formal correctness – documentation

Compile time vs. runtime properties

• Some assertions language supported– Compile time

• String s = nextElement()

– Runtime• ((String) nextElement())

– Asserting type properties of object.– Assertions describe runtime properties

Application-independent vs. dependent• Language can provide us with fixed number

of application-independent assertions.• Cannot handle

– First character of String is a letter.– Letter concept not burnt into language.

• Class Character defines it

– Innumerable assertions about letters possible• Second elements of string is letter.• Third element of string is letter.

• Need mechanism to express arbitrary assertions

Assertions vs. Exceptions

• Wrong assertion results in exception.

• Wrong class cast leads to class cast exception.

Reasons for exceptions

• User error– Programmer cannot prevent it

• Internal error– Programmer can prevent

• Assertions catch internal errors.

Reasons for assertions

• Why catch internal errors via assertions?

• Alternative: Make test runs and look at output.

Finite test runs

• Some errors not exhibited in test runs.– Inconsistent string not printed because of user

option.

Late detection

• Output produced much after the cause– Storing an inconsistent string causes

erroneous output when the string is matched not when it is stored.

Complex output

• May not know what the output is, but know the relationship between input and output– (123.345 * 789.123 ) / 123.345 == 789.123– Number is divisible by a prime factor

No manifestation in output

• Some errors have to do with efficiency.– Storing duplicate items in a set.

• Not exhibited in output

Example Assertion

{ y = 10/x; z = 5}

assert (y == 10/x) & (z == 5)

Our own mathematical syntax to be mapped to

Java later

Definition• Example

{ y = 10/x; z = 5}

assert (y == 10/x) & (z == 5)

• Statement regarding– State of program (variable values)

– Program counter (currently executing statement)

• PC implicit by putting assertion next to a statement– Specifies Boolean expression involving selected program

variables

– Assertion fails if boolean expression false

– Not all program variables named• X unnamed above

• Does not care about unnamed variables

Role of Assertions• Debugging

– Exception thrown if assertion fails

• Documentation// detailed prime factor computation code

….

assert (number % prime) == 0

• Specification – Assertion defined desired result of the code to be

implemented

• Formal correctness– Can prove if assertion met by code.

– Need assertions regarding language constructs

Recording Variables

{X = X + 1}assert ???

• Cannot say:{X = X + 1}assert X == X + 1;

• Introduce recording variable{oldX = X; X = X + 1}assert X = oldX + 1

• Special variables needed to make assertions sometimes

Preconditions and Postconditions

assert (x !=0)

{ y = 10/x; z = 5}

assert (y == 10/x) & (z == 5)

• Precondition– What is expected before

statement(block) execution

• Postcondition– What is guaranteed

after statement(block) if precondition met

• Together define a contract

Alternative syntax

pre (x !=0)

post (y == 10/x) & (z == 5)

{ y = 10/x; z = 5}

• Both conditions placed before statement block.

Incorrect precondition?

x = 0;pre (x !=0)post (y == 10/x) & (z == 5){ y = 10/x; z = 5}

• Precondition may not be satisfied by previous incorrect statement.

• Yet it is a correct precondition

Alternative precondition

pre (x > 0)

post (y == 10/x) & (z == 5)

{ y = 10/x; z = 5}

• Some assertions imply others– x > 0 x !=0

• Implied assertion is considered weaker.

• Can always replace precondition with a stronger one.

• Prefer weakest precondition– Requires fewest assumptions.– Statement can be used in more

contexts– Better documentation

Alternative postcondition

pre (x != 0)

post (z == 5)

{ y = 10/x; z = 5}

• Some assertions imply others– y == 10/x & (z == 5) => z == 5

• Can always replace postcondition with a weaker one

• Prefer strongest postcondition– More detailed documentation

– Can be used in more contexts• Can be followed by statements with

stronger preconditions.

Comp 114

• pre arrays, loops, procedures

• {Take Comp 114}• post objects,

inheritance, trees, recursion, assertions, composite, iterator, visitor pattern

• pre arrays, loops, procedures, objects, inheritance

• {Take Comp 114}• post recursion

Too strong

Too weak

Course Analogy

• Preconditions– Declared course prerequisite

• Post conditions– Advertised objectives

• Stronger precondition– Does not allow some students to enroll

• Weaker post conditions– Does not allow enrollment in future courses

Strongest Postcondition?

pre (x !=0)

post (y == 10/x) & (z == 5)

{ y = 10/x; z = 5}

• Says nothing about x.

Strongest Postcondition

pre (x !=0)

post (y == 10/x) & (z == 5) & (x != 0)

{ y = 10/x; z = 5}

• Strongest post condition given the precondition

• The stronger the pre condition, stronger the post condition.

Alternative weakest/strongest pair

pre (x > 0)

post (y == 10/x) & (z == 5) & (x > 0) & (y > 0)

{ y = 10/x; z = 5}

Stronger precondition

Stronger postcondition

Multiple valid pairs

• Weakest precondition relative to post condition.• Strongest post condition relative to pre condition.• A statement not associated with a unique pair that

is best.• Strengthening the precondition strengthens the

post condition• What is the “right pair?”

Two approaches

• Start with a precondition– Find the strongest postcondition we can prove.

• Start with a post condition– Find the weakest precondtion for it.

Theoretical specification point of view

• Specify the result needed as a post condition.

• Identify the weakest precondition needed to obtain the result.

• Write a program that satisfies the pair.

Reality specification point of view

• Based on what you can assume you change your expectations.

• Iterative process.

Debugging/specification/ documentation point of view

• Precondition of a statement should be weakest one necessary for “correct” operation of program.– Correct means no exception.

• A statement that is not equivalent should not have the same pre and post condition

Debugging/specification/ documentation point of view

pre (x >0)

post (y == 10/x) & (z == 5) & (x > 0)

{ y = 10/x; z = 5}

pre (x >0)

post (y == 10/x) & (z == 5) & (x > 0)

{ y = 10/x; z = 5; x = abs(x) + 1}

Statements are not equivalent

Debugging/ specification/ documentation point of view

pre (x !=0)

post (y == 10/x) & (z == 5) & (x != 0)

{ y = 10/x; z = 5}

Best pre and post conditions

Proving programs correct point of view

• Precondition can be stronger than one that is the best one for the statement from debugging/specification/documentation point of view

• Allows us to derive pre and post conditions of containing statement/program

Program correctness proof

pre

post (x == 1)

{x = 1}

pre (x == 1)

post (y == 10/x) & (z == 5) & (x == 1)

{ y = 10/x; z = 5}

Program correctness proof

pre

post (y == 10/x) & (z == 5) & (x == 1)

{x = 1; y = 10/x; x= 5}

Changeable assertions

• What we assert about a statement (to prove program correct) may depend on what is executed before it.

• Need facilities to change assertions easily.

• Proxies explained later address this.

Weakest possible condition

• Implied by anything

• true

• p true

• If p is true then true is true.

• But true is always true.

• So p can be any boolean expression.

Strongest possible condition

• Implies anything• false• false p• If false is true then p is true• But false is never true.• So any p is implied.• “I will give you a million dollars when hell

freezes over”

Important equivalence

• P Q !P | Q

• P true !P | true true

• false Q !false | Q true

Asserting false

switch c {

case ‘a’: …

case ‘b’: …

default: assert false

}

Unreachable statement

Invariant

pre (x !=0)

post (y == 10/x) & (z == 5) & (x != 0)

{ y = 10/x; z = 5}

• True before and after statement

Separately declared

inv (x !=0)

post (y == 10/x) & (z == 5)

{ y = 10/x; z = 5}

• List invariant separately

Invariants for debugging purposes• Should never be false

– False strongest invariant of all statements.– But not best for a reachable statement as it does

not convey useful information– Never assert it for reachable statements if

assertion not done for program proofs.

• Should never involve recording variables– recording variables describe how program

variables change– invariants describe how these variables do not

change

Loop Invariant

sum = 0;j = 0;while (j < n) { j++; sum = sum + j;}

• Holds true before and after each loop iteration, that is, before and after each execution of loop body.

Loop Invariant

inv (sum = 0 j k) & (j <= n ) & (j >= 0)

sum = 0;j = 0;while (j < n) { j++; sum = sum + j;}

• Holds true before and after each loop iteration, that is, before and after each execution of loop body.

Method assertions

invariant x != 0post (y == 10/x) & (z == 5) & (x != 0)void m () { y = 10/x; z = 5;}

• Preconditions, postconditions, invariants associated with method body

Class assertions

public class C {int x =0;int y = 1;public void incrementXAndY () { incrementX(); incrementY();}public int getX() { return x;}public int getY() { return y;}incrementX() { x++;}incrementY() { y++;}}

• Preconditions, postconditions, invariants shared by all public methods of class

Class assertionsinv y == x + 1public class C {int x =0;int y = 1;public void incrementXAndY () { incrementX(); incrementY();}public int getX() { return x;}public int getY() { return y;}incrementX() { x++;}incrementY() { y++;}}

• Preconditions, postconditions, invariants shared by all public methods of class

Expressing Assertions• Natural language

– All array elements are not odd.– All array elements are either odd or positive.– Easy to read but ambiguous.

• Programming language– Library or language constructs– Executable, unambiguous but language-dependent and

awkward• Useful for debugging• Specification cannot be done before language decided.

• Mathematical language– Uambiguous, time tested, convenient but not executable

Propositional Calculus• Logic operators

• not, and, or• We will use Java syntax.

• Quantifiers– Universal ( )– Existential ( )

• Propositional variables• Program• Others: Recording, Quantifier

• Propositions– Boolean expressions involving operators, variables, and

quantifiers

• Simple/quantified propositions– Do not use/use quantifiers

Propositional Algebra

• Calculus based on algebra

• Algebra defines– Arithmetic operations– Relations operations– We will use Java syntax

Example Propositions• Simple propositions

– True– False– X > 6– (X > 6 ) & (Y < 2)

• Quantified j: 0 <= j < b.size() : b.elementAt(j) != null

• All elements of B are not null j: 0 <= j < b.size(): b.elementAt(j) != null

• At least one element of B is not null.

Quantified Propositions• Sub-proposition

– Simple or quantified proposition in terms of quantifier

• Domain– A collection of values used in

sub-proposition evaluation– b.elementAt(0), …

b.elementAt(B.size() – 1

• Domain description– Describes domain using

quantified variable

• Quantified j: 0 <= j < b.size():

b.elementAt(j) != null j: 0 <= j < b.size():

b.elementAt(j) != null

• General form:– Qx:D(x):P(x) – Q is either or

quantifier– X is quantified variable– D(x) is domain description– P(x) is sub-proposition

Expressing Assertions in Java

• Write your own code.

• Libraries

• Language support– Does not support quantifiers– Works for 1.4– You have 1.3

Assertion Failed Exception

• Thrown when assertion fails• Unchecked because internal error• Can subclass it for specific

assertions• Will use message in examples

package assertions;public class AnAssertionFailedException extends RuntimeException { public AnAssertionFailedException () {}; public AnAssertionFailedException (String initValue) { super (initValue); }}

Assert methods

• Used for simple assertions

package assertions;import java.util.Enumeration;public class AnAsserter { public static void assert (boolean proposition, String message) throws AnAssertionFailedException { if (!proposition) throw new AnAssertionFailedException (message); }

public static void assert (boolean proposition) throws AnAssertionFailedException {

assert (proposition, “”);}

}

Using assert

• Must write our boolean expression that is passed to assert– public static int sum (int from, int to) { … }

• Must code pre/post conditions and invariants as assert calls

//inv (sum = 0 j k) & (j <= n ) & (j >= 0)

sum = 0;j = 0;while (j < n) { j++; sum = sum + j;}

Using assert

• Must write our boolean expression that is passed to assert– public static int sum (int from, int to) { … }

• Must code pre/post conditions and invariants as assert calls

sum = 0;

j = 0;

//inv (sum = 0 j k) & (j <= n ) & (j >= 0)

while (j < n) {

AnAsserter.assert (j <= n && j >= 0 && sum == sum(0, j))

j++;

sum = sum + j;

AnAsserter.assert (j <= n && j > =0 && sum == sum(0, j))

}

Class and Method Invariants

• Class invariant– Encode them as invariants of

all public methods.

• Method invariant– Put assert at start and end of

public methods

//inv y = x + 1public class C {int x =0;int y = 1;public void incrementXAndY () { incrementX(); incrementY();}public int getX() { return x;}public int getY() { return y;}incrementX() { x++;}incrementY() { y++;}}

Class and Method Invariants

• Class invariant– Encode them as

invariants of all public methods.

• Method invariant– Put assert at start and

end of method

//inv y = x + 1public class C {

int x =0;int y = 1;void assertClassInvariant{

AnAsserter.assert (y == x + 1);}public void incrementXAndY () { assertClassInvariant(); incrementX(); incrementY(); assertClassInvariant();}public int getX() { assertClassInvariant(); ??? return x;}

…}

Cannot put something after return and return may have side effects

(return x++)

Class and Method Invariants//inv y = x + 1public class C {

int x =0;int y = 1;void assertClassInvariant{

AnAsserter.assert (y == x + 1);}void internalIncrementXAndY () { incrementX(); incrementY();}public void incrementXAndY () { assertClassInvariant(); internalIncrementXAndY(); assertClassInvariant();}int internalGetX() { return x;}public int getX() { assertClassInvariant(); int retVal = internalGetX(); assertClassInvariant(); return retVal;}

…}

Asserting proxy method

• Can define another proxy method that asserts and calls the real method– Keeps asserting code

separate

– Useful for functions

– Useful when multiple exit points

Multiple exit points

• Can define another proxy method that asserts and calls the real method– Keeps asserting code

separate

– Useful for functions

– Useful when multiple exit points

char assignGrade (int score) {if (score >= 50) {

grade = ‘P’;return;

} elsegrade = ‘F’;

}

char assertingToGrade (int score) { assignGrade(score);

assert (grade == ‘F’ || grade == ‘P’);}

Quantified Assertions

• Syntax– Qx:D(x):P(x) j: 0 <= j < b.size(): b.elementAt(j) != null j: 0 <= j < b.size(): b.elementAt(j) != null

• Goal:– Write general boolean functions that take as arguments

encoding of the elements of domain and return true iff proposition is true

– Will write separate functions for universal and existential quantifer

Goal

• Need to fill the …

package assertions;import java.util.Enumeration;public class AQuantifier { public static boolean forAll (…) { … } public static boolean thereExists (…) { … }}

Problem with inaccessible variables

• Syntax– Qx:D(x):P(x) j: 0 <= j < b.size(): b.elementAt(j) != null j: 0 <= j < b.size(): b.elementAt(j) != null

• How to describe D(x) and P(x)?– Cannot pass expression string as variables involved

have no meaning to library– Will pass one argument describing the domain

• Collection of elements– Another argument describing the subproposition to be

evaluated for each domain element.

How to describe domain?

• Syntax– Qx:D(x):P(x) j: 0 <= j < b.size(): b.elementAt(j) != null j: 0 <= j < b.size(): b.elementAt(j) != null

• Domain can be– Array, Vector, StringHistory, …

• Need a common interface to describe elements– java.util.Enumeration

Describing the domain

AnAsserter.assert(AQuantifier.forAll(B.elements(), …, "Some element of B is null");

AnAsserter.assert(AQuantifier.thereExists(b.elements(), …, "All elements of B are null");

Need to fill …

package assertions;import java.util.Enumeration;public class AQuantifier { public static boolean forAll ((Enumeration domain, …) { while (domain.hasMoreElements()) … } public static boolean thereExists ((Enumeration domain, …) {

while (domain.hasMoreElements()) … }}

How to describe Subproposition

• Syntax– Qx:D(x):P(x) j: 0 <= j < b.size(): b.elementAt(j) != null j: 0 <= j < b.size(): b.elementAt(j) != null

• Cannot pass expression string as variables involved have no meaning to library

• But can pass function that evaluates it.– boolean isNotNull(Object element) {

return element != null; }

• Function will be evaluated for each domain element by our libraries

Subproposition as a function

AnAsserter.assert(AQuantifier.forAll(B.elements(), isNotNull), "Some element of B is null");

AnAsserter.assert(AQuantifier.thereExists(b.elements(), isNotNull), "All elements of B are null");

package assertions;import java.util.Enumeration;public class AQuantifier { public static boolean forAll (Enumeration domain, (object boolean) subProposition) { while (domain.hasMoreElements()) if (!subProposition (domain.nextElement()) return false; return true; } public static boolean thereExists ((Enumeration domain, (object boolean) subProposition) {

while (domain.hasMoreElements()) if (!subProposition (domain.nextElement()) return true; return false; }}

How to describe Subproposition• Cannot pass expression string.• But can pass function that

evaluates it.– boolean isNotNull(Object element) {

return element != null;

}

• Java does not support function parameters

• But allows object parameters– Object = data + functions

• All subproposition objects implement same interface

• A subproposition object visits each element

package visitors;import assertions.ElementChecker;public class ANonNullChecker implements ElementChecker { public boolean visit(Object element) {

return (element != null); }}

package assertions;public interface ElementChecker { public boolean visit (Object element);}

Describing the subproposition

AnAsserter.assert(AQuantifier.forAll(b.elements(), new ANonNullChecker()), "Some element of B is null");

AnAsserter.assert(AQuantifier.thereExists(b.elements(), new ANonNullChecker()), "All elements of B are null");

package assertions;import java.util.Enumeration;public class AQuantifier { public static boolean forAll (Enumeration domain, ElementChecker subProposition) { while (domain.hasMoreElements()) if (!subProposition.visit(domain.nextElement())) return false; return true; } public static boolean thereExists (Enumeration domain, ElementChecker subProposition) { while (domain.hasMoreElements()) if (subProposition.visit(domain.nextElement())) return true; return false; }}

Call

Callback

Calls vs. Callbacks

• Calls– calls from reusing class to reused class

• Callbacks– calls from reused class to reusing class.– not to implement a symbiotic relationship– done to service calls

Subproposition accessing vars other than domain elements j: 0 <= j < b.size(): b.elementAt(j) != a.elementAt(0) j: 0 <= j < b.size(): b.elementAt(j) != a.elementAt(0)

package visitors;import assertions.ElementChecker;public class ANonNullChecker implements ElementChecker { public boolean visit(Object element) {

return (element != null); }}

AnAsserter.assert(AQuantifier.forAll(b.elements(), new ANonNullChecker()), "Some element of B is null");

No constructor

Subproposition accessing vars other than domain elements j: 0 <= j < b.size(): b.elementAt(j) != a.elementAt(0) j: 0 <= j < b.size(): b.elementAt(j) != a.elementAt(0)

package visitors;import assertions.ElementChecker;public class AnInequalityChecker implements ElementChecker {

Object testObject;public AnInequalityChecker(Object theTestObject) {

testObject = theTestObject;}public boolean visit(Object element) {

return !element.equals(testObject);}

}

AnAsserter.assert(AQuantifier.forAll(b.elements(), new AnInequalityChecker(a.elementAt(0))), "Some element of b is equal to a.elementAt(0)");

Each external var becomes constructor parameter

Visitor Pattern• Some collection C of elements of type T• Visitor interface

– public interface ElementChecker { public boolean visit (Object element);}– public interface V {public T2 m (T p);}

• One or more traverser methods that use collection and visitor interface to pass one or more collection elements to the method.

– public static boolean forAll (Enumeration domain, ElementChecker subProposition) {…subProposition.visit(domain.nextElement());

– traverser1 (C c, V v) { …v.m(element of C)…}• Implementation of interface whose constructors take as arguments external

variables that need to be accessed by the visitor methodpublic class AnInequalityChecker implements ElementChecker {

Object testObject;public AnInequalityChecker(Object theTestObject) {…}public boolean visit(Object element) {…};

}public class AV1 implements V { public AV1 (T1 p1, … Tn pN) { …} public T2 m (T p) { … }}

• Client passes traverser visitor implementation and collection– AQuantifier.forAll(b.elements(), new AnInequalityChecker(a.elementAt(0)));– traverser1(c, new AV1(a1,.. aN));

Visitor Pattern

Collection Interface C with elements of type T

element1: T element1: T

component

Visitor Interface

Visitor Class 1

implements

Visitor Class 2

uses

Traverser 2

Traverser 1

Example of Visitor Pattern

Enumeration

Object Object

component

ElementChecker

ANonNullChecker

implements

AnInequalityChecker

uses

thereExists()

forAll()

Nested Assertions

j: 0 <= j < b.size(): k: 0 <= k < b.elementAt(j).size(): b.elementAt(j).elementAt(k) != null

package visitors;import assertions.ElementChecker;public class ANonNullChecker implements ElementChecker { public boolean visit(Object element) {

return (element != null); }}

package visitors;import assertions.ElementChecker;public class AForAllChecker implements ElementChecker { public boolean visit(Object element) { Enumeration children = ( (Vector) element).elements(); return AQuantifier.forAll(children, new ANonNullChecker())); }}

AnAsserter.assert(AQuantifier.forAll(b.elements(), new AForAllChecker(), "Some leaf-level element of b is null”);

Visiting Hierarchical Structures

(Trees)

Example of Pattern in Everyday Applications

• Program tree

• A visitor for printing all nodes.

• Another for type checking.

• Yet another for generating code

• Do not want to put all of this code in tree class.

• In any case, printing should not be in tree.

Java 1.4 Assertion Support• AssertionError exception

= AnAssertionFailedException

• assert <boolean expression>= AnAsserter.assert(<boolean expression>, “”);

• assert <boolean expression>: <value>= AnAsserter.assert(<boolean expression>, string representation of

<value>

• Compile option determine if assert is keyword– javac –source 1.4 models/ACounter.java

• Assertions can be dynamically turned on or off for package or Class– java –da:bus.uigen –ea models.ACounter

• No support for quantifiers.

Error vs. Exception• Java assertion failure results in AssertionError

• Subclass of Error rather than RunTimeException

• Reasoning: – Convention dictates that RunTimeException

should be caught– Should “discourage programmers from

attempting to recover from assertion failures.”• Might do custom reporting, mail error report etc.

– Decision was controversial

Modularizing assertion code

• How to not clutter regular with assertion code.

• How to turn off/change library-based assertion code?

Proxy Methods

• Can define another proxy method that asserts and calls the real method– Keeps asserting code

separate

– Useful for functions

– Useful when multiple exit points

char assignGrade (int score) {if (score >= 50) {

grade = ‘P’;return;

} elsegrade = ‘F’;

}

char assertingToGrade (int score) { assignGrade(score);

assert (grade == ‘F’ || grade == ‘P’);}

Proxy classes

• Put assertion code in special classes that are proxies for real classes.

• Factory, factory selectors and factory methods can be used to choose between proxy and regular classes.

Counterpackage models;public class ACounter implements Counter {

int counter = 0;public void add (int amount) {

counter += amount;}public int getValue() {

return counter;}

}

Asserting Proxy Class

package models;import assertions.AnAsserter;public class ACheckedCounter extends ACounter {

public void add (int amount) {int oldCounter = counter;super.add(amount);AnAsserter.assert(counter == oldCounter + amount,

"New counter:" + counter + " != old counter:" + oldCounter + " + amount:" + amount);

}}

Example of Proxy Pattern

ACounter Counterimplements

AChecked Counter

IS-A implements

Proxy Pattern

Real Subject Class

Subject Interface

implements

Proxy Class

IS-A implements

Proxies in everyday apps• Proxy is a stand-in for real subject.• Adds to one or more method implementations• Web proxies

– Cache data– Redirect to nearest server

• Proxy may – Log– Cache (remote proxy)– Provide access control– Assert

Asserting Proxy Class

package models;import assertions.AnAsserter;public class ACheckedCounter extends ACounter {

public void add (int amount) {int oldCounter = counter;super.add(amount);AnAsserter.assert(counter == oldCounter + amount,

"New counter:" + counter + " != old counter:" + oldCounter + " + amount:" + amount);

}}

Alternative way of doing

proxy?

Delegating Proxy

• Proxy HAS-A reference to the Subject and not IS-A Subject.

• Proxy is called delegator and subject is called delegate

Delegating Proxy-based Counterpackage models;import assertions.AnAsserter;public class ADelegatingCheckedCounter implements Counter {

Counter counter; public ADelegatingCheckedCounter (Counter theCounter) {

counter = theCounter;}public void add (int amount) {

int oldVal = counter.getValue();counter.add(amount);int newVal = counter.getValue();AnAsserter.assert(newVal == oldVal + amount,

"New counter:" + newVal + " != old counter:" + oldVal + " + amount:" + amount);

}public int getValue() {

return counter.getValue();}

}

Example of Delegating Proxy

ACounter Counterimplements

AChecked Counter

HAS_A implements

Delegating Proxy

Real Subject Class

Subject Interface

implements

Proxy Class

HAS_A implements

Inheritance vs. Delegation

Real Subject Class Subject Interfaceimplements

Proxy Class

HAS-A implements

Real Subject Class Subject Interfaceimplements

Proxy Class

IS-A

OMT (Object Modeling Technique)

Real Subject Class Subject Interfaceimplements

Proxy Class

HAS-A implements

Real Subject Class Subject Interfaceimplements

Proxy Class

IS-A

Added notation of implements

Real Subject Class Subject Interfaceimplements

Proxy Class

HAS-A implements

Real Subject Class Subject Interfaceimplements

Proxy Class

IS-A

Inheritance vs. Delegation

Reused Class Reused Interface

Reusing Class Reusing Interface

Reused Class Reused Interface

Reusing Class Reusing Interface

Inheritance vs. Delegation: Instances

Reused Class

Reusing Class

Reused Class

Reusing Class

instance

instance

instance

Physical component

Asserting Proxy Class

package models;import assertions.AnAsserter;public class ACheckedCounter extends ACounter {

public void add (int amount) {int oldCounter = counter;super.add(amount);AnAsserter.assert(counter == oldCounter + amount,

"New counter:" + counter + " != old counter:" + oldCounter + " + amount:" + amount);

}}

Delegating Proxy-based Counterpackage models;import assertions.AnAsserter;public class ADelegatingCheckedCounter implements Counter {

Counter counter; public ADelegatingCheckedCounter (Counter theCounter) {

counter = theCounter;}public void add (int amount) {

int oldVal = counter.getValue();counter.add(amount);int newVal = counter.getValue();AnAsserter.assert(newVal == oldVal + amount,

"New counter:" + newVal + " != old counter:" + oldVal + " + amount:" + amount);

}public int getValue() {

return counter.getValue()b;}

}

Inheritance vs. Delegation: Init methods/Constructor

Reused Class

Reusing Class

Reused Class

Reusing Class

declares

Constructor/init (delegate, …)

declares

Constructor/init (…)

Inheritance vs. Delegation: Super calls

Reused Class

Reusing Class

Reused Class

Reusing Class

declares Reused method m

Reused method m

declares

declaresMethod n

super.m()

Method n

delegate.m()

declares

Asserting Proxy Class

package models;import assertions.AnAsserter;public class ACheckedCounter extends ACounter {

public void add (int amount) {int oldCounter = counter;super.add(amount);AnAsserter.assert(counter == oldCounter + amount,

"New counter:" + counter + " != old counter:" + oldCounter + " + amount:" + amount);

}}

Delegating Proxy-based Counterpackage models;import assertions.AnAsserter;public class ADelegatingCheckedCounter implements Counter {

Counter counter; public ADelegatingCheckedCounter (Counter theCounter) {

init(theCounter);}public void add (int amount) {

int oldVal = counter.getValue();counter.add(amount);int newVal = counter.getValue();AnAsserter.assert(newVal == oldVal + amount,

"New counter:" + newVal + " != old counter:" + oldVal + " + amount:" + amount);

}public int getValue() {

return counter.getValue();}

}

Inheritance vs. Delegation: Reused Methods

Reused Class

Reusing Class

Reused Class

Reusing Class

declares Reused method m

Reused method m

declares

m stub

delegate.m()

declares

Delegation is more work!

public abstract class AnAbstractTitleToCourseMapper implements TitleToCourseMapper {public AnAbstractTitleToCourseMapper() {

fillCourses();}abstract RegularCourse getRegularCourse();abstract FreshmanSeminar getFreshmanSeminar();void fillCourses() {

RegularCourse introProg = getRegularCourse ();FreshmanSeminar legoRobots = getFreshmanSeminar();...

}public String getTitle() {

return titleToCourseMapper.getTitle();}...

}

Abstract class

Concrete course userpublic class ATitleToCourseMapper extends AnAbstractTitleToCourseMapper {

RegularCourse getRegularCourse() {return new ARegularCourse();

}FreshmanSeminar getFreshmanSeminar() {

return new AFreshmanSeminar();}

}

Delegate classpublic class ATitleToCourseMapperDelegate implements TitleToCourseMapper {

CourseFactory delegator;public ATitleToCourseMapperDelegate(CourseFactory theDelegator) {

delegator = theDelegator;fillCourses();

}void fillCourses() {

RegularCourse introProg = delegator.getRegularCourse ();FreshmanSeminar legoRobots = delegator. getFreshmanSeminar(); ...

}public String getTitle() {

return titleToCourseMapper.getTitle();}...

}

Concrete course user

public class ATitleToCourseMapperDelegator implements TitleToCourseMapper, CourseFactory {

public RegularCourse getRegularCourse() {return new ARegularCourse();

}public FreshmanSeminar getFreshmanSeminar() {

return new AFreshmanSeminar();}public String getTitle() {

return titleToCourseMapper.getTitle();}...

}

Inheritance vs. Delegation: Callbacks

Reused Class

Reusing Class

Reused Class

Reusing Class

declaresReused

method m

Reused method m

declares

declaresMethod n

this.n()

declaresMethod n

with possibly

more access

delegator.n()

Abstract or OverriddenMethod n

Calls vs. Callbacks

• Calls– calls from reusing class to reused class

• Callbacks– calls from reused class to reusing class.– not to implement a symbiotic relationship– done to service calls

Inheritance vs. Delegation: Constructors/Init methods for callbacks

Reused Class

Reusing Class

Reused Class

Reusing Class

declares

declares Constructor/init (delegator, …)

Constructor/init (…)

Access problems

• Occur with callbacks.

• And if reusing class accesses variables of reused class

Inheriting String Databasepackage collections;public class AStringDatabase extends AStringHistory implements StringDatabase {

public void deleteElement (String element) {shiftUp(indexOf(element));

}public int indexOf (String element) {

int index = 0;while ((index < size) && !element.equals(contents[index]))

index++;return index;

}void shiftUp (int startIndex) {

int index = startIndex ;while (index + 1 < size) {

contents[index] = contents[index + 1];index++;

}size--;

}public boolean member(String element) {

return indexOf (element) < size;}public void clear() {

size = 0;}

}

Delegating String Setpackage collections;import enums.StringEnumeration;public class ADelegatingStringDatabase implements StringDatabase {

AStringHistory stringHistory = new AStringHistory();public void deleteElement (String element) {

shiftUp(indexOf(element));}public int indexOf (String element) {

int index = 0;while ((index < stringHistory.size) && !

element.equals(stringHistory.contents[index])) index++;

return index;}void shiftUp (int startIndex) {

int index = startIndex ;while (index + 1 < stringHistory.size) {

stringHistory.contents[index] = stringHistory.contents[index + 1];index++;

}stringHistory.size--;

}

Class as type and accessing

non public variables in

same package

Instantiating delegate rather than

getting reference from constructor.init

method

Delegating String Set

public boolean member(String element) {return indexOf (element) < stringHistory.size;

}public void clear() {

stringHistory.size = 0;}public int size() {

return stringHistory.size();}public String elementAt (int index) {

return stringHistory.elementAt(index);}public StringEnumeration elements() {

return stringHistory.elements();}public void addElement(String element) {

stringHistory.addElement(element);}

}

Large number of forwarding

stubs

Access issues• Callbacks methods

– must be given public access if interface types the delegator.

– can be given protected or default access– but requires class types, delegator and delegator

class in same package

• May need to give access to reused class variables also– through public methods– or putting delegate and delegator in same

package, giving them protected/default access and using class as type

Cons of Delegation

• Need to instantiate multiple classes.

• Need to compose instances.

• Need to define stub methods

• Access problems

Pros of Delegation

Reused Class Reused Interface

Reusing Class Reusing Interface

Reused Class Reused Interface

Reusing Class Reusing Interface

Substituting Reused Class

Reused Class 2 Reused Interface

Reusing Class 2 Reusing Interface

Reused Class 2 Reused Interface

Reusing Class Reusing Interface

Substituting Reused Class

• Another implementation of reused interface– in inheritance requires another implementation

of reusing class that duplicates methods of original reusing class.

– In delegation simply requires a different object to be passed to constructor

New Inheriting Proxy Class

package models;import assertions.AnAsserter;public class ACheckedCounter2 extends ACounter2 {

public void add (int amount) {int oldCounter = counter;super.add(amount);AnAsserter.assert(counter == oldCounter + amount,

"New counter:" + counter + " != old counter:" + oldCounter + " + amount:" + amount);

}}

Orginal Delegating Proxypackage models;import assertions.AnAsserter;public class ADelegatingCheckedCounter implements Counter {

Counter counter; public ADelegatingCheckedCounter (Counter theCounter) {

counter = theCounter;}public void add (int amount) {

int oldVal = counter.getValue();counter.add(amount);int newVal = counter.getValue();AnAsserter.assert(newVal == oldVal + amount,

"New counter:" + newVal + " != old counter:" + oldVal + " + amount:" + amount);

}public int getValue() {

return counter.getValue();}

}

Reused Class

Reusing Class 1

Reused Class

Reusing Class 2

Reusing Class 2

Reusing Class 1

Multiple Reusing Classes• Inheritance

– each possible combination of reusing classes bound at compile time

– Duplicates code

• Delegation– can be changed

dynamically

AConsoleControllerAndViewAndJOptionViewAConsoleControllerAndView

ACounterJOptionView

Delegation-based MVC

ACheckedCounter

ACounterController ACounterConsole View

Inheritance-based MVCACounter

ACounterWithConsoleAndJOptionViewAndController

ACounterWithConsoleView

ACounterWithConsoleAndJOptionView

No facades or notification needed

Controller with Console View

package views;import models.ACounter;public class ACounterWithConsoleView extends ACounter {

void appendToConsole(int counterValue) {System.out.println("Counter: " + counterValue);

}public void add (int amount) {

super.add(amount);appendToConsole(getValue());

}}

Controller with Console and JOption View

package views;import models.ACounter;import javax.swing.JOptionPane;public class ACounterWithConsoleAndJOptionView extends ACounterWithConsoleView {

void displayMessage(int counterValue) {JOptionPane.showMessageDialog(null, "Counter: " +

counterValue);}public void add (int amount) {

super.add(amount);displayMessage(getValue());

}}

Controller with Console and JOption View and Controller

package controllers; import views.ACounterWithConsoleAndJOptionView;import java.io.IOException;public class ACounterWithConsoleAndJOptionViewAndController extends ACounterWithConsoleAndJOptionView implements CounterWithConsoleViewAndController {

public void processInput() {while (true) {

int nextInput = Console.readInt();if (nextInput == 0) return;add(nextInput);

}}

}

AConsoleControllerAndView

Alternative: Delegation-based Configuration

AnObservableCounter

ACounterController ACounterConsole View

ACounterJOptionView

Alternative: Inheritance-based MVCACounter

ACounterWithConsoleViewAndController

ACounterWithConsoleView

New class

Controller with Console and View and Controller

package controllers; import views.ACounterWithConsoleAndJOptionView;import java.io.IOException;public class ACounterWithConsoleViewAndController extends ACounterWithConsoleView implements CounterWithConsoleViewAndController {

public void processInput() {while (true) {

int nextInput = Console.readInt();if (nextInput == 0) return;add(nextInput);

}}

}

Only difference between it and previous inheriting

controller

Inheritance vs. Delegation: Distribution

Reused Class

Reusing Class

Reused Class

Reusing Class

instance

instance

instance

Data and methods of both

classes at one location

Can be in two different locations

(client/server)

Reused Class 1

Reusing Class

Reused Class 1

Reusing Class

Reused Class 2

Reused Class 1

Reusing multiple classes• In Java reusing

multiple classes through inheritance not an option.

• Can always have multiple instance variables

Pros and Cons of Delegation• Can change reused class

without changing reusing class.

• Multiple reusing classes can share reused class variables simultaneously.

• Variables and methods of reusing and reused class can be on separate computers.

• Works in single inheritance languages

• Need to instantiate multiple classes.

• Need to compose instances.

• Need to define stub methods

• Access problems

Need to weigh pros and cons

When benefits of delegation don’t apply use inheritance

That is why inheritance exists.

Inheritance is a bad idea• If reusing class has “with” in its name:

– ACounterWithConsoleView

• If more than one way to do inheritance– Controller can be subclass of view– Or vice versa

• If some of the inherited methods are not used:– AStringHistory extends Vector

• Adds methods to add and access string elements rather than object elements

• addString(), stringAt()

– does not use removeElement() etc

• If reusing class should not be used wherever shared class is used– even if all methods are reused.

Inheritance is a bad ideapublic ACartesianPoint implements Point { int x, y; public APoint(int theX, int theY) { x = theX; y = theY;} public int getX() { return x } public int getY() { return y } public double getRadius() { return Math.sqrt(x*x + y*y); } .public double getAngle() { return Math.atan(y/x);}}

public ASquare extends ACartesianPoint implements Square { int sideLength; public ASquare (int theX, int theY, int theSideLength) { x = theX; y = theY; sideLength = theSideLength} public int getSideLength() {return sideLength};}

public ASquare implements Square { Point center; int sideLength; public ASquare( Point theCenter, int theSideLength) { center = theCenter;sideLength = theSideLength; } public int getX() {return center.getX();} public int getY() {return center.getY();} public int getRadius() {return center.getRadius();} public int getAngle() {return center.getAngle();} public int getSideLength() {return sideLength;}}

ASquare IS-NOT-A

ACartesianPoint!

Inheritance vs. Delegation in Popular Software: Toolkits

Widget Class

Widget User

Widget Class

Widget User

declares

declares

super call

delegate call

declares

declaresAction Performed

Action Performed

Action Performed

Action Performed

Java 1.0

Later versions

Inheritance vs. Delegation in Popular Software• Main problem with inheritance based widgets

– Widget users could not be subclass of any other class because of multiple inheritance

• Multiple objects can receive events from same widget.

• Widget implementation can be switched• Observer concept supports both approaches

– Inherited Observer class vs. Delegated PropertyChangeSupport

• Threads support both approaches– Inheritable Thread class vs. Implemented Runnable

Interface

The Importance of Being Earnestpublic class ABankAccount implements BankAccount {

int currentBalance = 0;public static final int MIN_BALANCE = 100;public ABankAccount (int initialBalance) {

currentBalance = initialBalance;}public void deposit (int amount) {

currentBalance += amount;}public boolean withdraw (int amount) {

int minNecessaryBalance = MIN_BALANCE + amount;if (minNecessaryBalance <= currentBalance) {

currentBalance -= amount;return true;

}else return false;

}public int getCurrentBalance () {

return currentBalance;}public boolean safeWithdraw (int amount) { AnAsserter.assert(amount > 0, "amount < 0"); boolean retVal = withdraw(amount); AnAsserter.assert(currentBalance >= MIN_BALANCE, "currentBalance < MIN_BALANCE"); return retVal;}

}

Usage

Usage

Usage

Integer.MAX_INT

Usage

Usage

Safe Usage

Integer Overflow

and Security

• Google for “integer overflow security”

top related