assertions prasun dewan comp 114. assertions declare some property of the program potentially useful...
Post on 19-Dec-2015
212 Views
Preview:
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