1 / 47

Contracts for Java (work in progress)

Contracts for Java (work in progress). Matthias Felleisen Rice University Houston, Texas. Components and Contracts. Components, Java, and Contracts Problems with Contracts The Meaning of Contracts Compiling Contracts. The Component Utopia. Programming in a Component World (1).

nhu
Download Presentation

Contracts for Java (work in progress)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Contracts for Java (work in progress) Matthias Felleisen Rice University Houston, Texas

  2. Components and Contracts • Components, Java, and Contracts • Problems with Contracts • The Meaning of Contracts • Compiling Contracts

  3. The Component Utopia

  4. Programming in a Component World (1) The market delivers interchangeable components with external connectors, ready to be hooked up.

  5. Programming in a Component World (2) Programmers wire together components.

  6. Programming in a Component World (3) Sometimes they add some adapter code.

  7. Programming in a Component World (4) They build new components from old ones and a few adapters for distribution.

  8. What’s Needed for a Component World? • need flexible means of programming and wiring components together • need tools for finding components • need quality assurance and “sanctions” against “black sheep”

  9. Specifying and Wiring Components • Classes are bad: • Mixins: connectors are external • Modules are bad: • Functors: connectors are external • Units: connectors are external, graph-based • Industry’s wiring standards • Objects • COM, DCOM, and/or CORBA

  10. Finding Components • Industry: “in documentation we trust” and “good luck” • Academia: use types and module signatures to find the missing link • DiCosmo (1996 …) • Felleisen (1983)

  11. “Warranties” for Components • Industry: “We didn’t do anything.” • Academia: Types Uber Alles • Contracts: From Eiffel to iJava

  12. Contracts for “Commercial” Components 8. NO WARRANTIES. Microsoft expressly disclaims any warranty for the SOFTWARE PRODUCT. THE SOFTWARE PRODUCT AND ANY RELATED DOCUMENTATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OR MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NONINFRINGEMENT. THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE PRODUCT REMAINS WITH YOU.

  13. “Warranties” for Contracts • syntactic level: types • semantic level 1: functionality • semantic level 2: concurrency • quality of service level: unexplored

  14. Contracts: From Eiffel to iContract

  15. Eiffel: Programming by Contract • Components are classes • Contracts are pre- and post-conditions (assertions) on methods • Contract enforcement attempts to pinpoint the culprit for error signals iContract: Eiffel for Java

  16. A Simple Example class Q implements Queue { Queue enq(Object X) { ... // post: !this.empty() … Queue deq() { … // pre: !this.empty() … boolean empty() { … } … } // Good Client: Queue q = new Q(); q.enq(X).deq() … // Bad Client: Queue q = new Q; q.deq().enq(X) … Eiffel blames this call

  17. Problems with Call-backs some_a.m2() A B some_b.m(some_a) “Java is higher-order”

  18. A Complex Example (1) class Q implements Queue { Queue enq(Object X) { ... // post: !this.empty() // effect: o.onEnq(this) Queue deq() { … // pre: !this.empty() // effect: o.onDeq(this) void register(Observer o) { ... // effect: o.init() // please: a “good” Observer … class GoodO implements Observer { void init() { … } Queue onEnq(Queue q){ ... // post: !q.empty() Queue onDeq(Queue q){ ... // pre: q.empty() … }

  19. A Complex Example (2) class Q implements Queue { Queue enq(Object X) { ... // post: !this.empty() // effect: o.onEnq(this) Queue deq() { … // pre: !this.empty() // effect: o.onDeq(this) void register(Observer o) { ... // effect: o.init() // please: a “good” Observer … class BadO implements Observer { void init() { … display … } Queue onEnq(Queue q) { q.deq() … } Queue onDeq(Queue q) { q.enq(X) … } … } No Warranty on state of q after call !

  20. A Complex Example (3) puts bad observer together with queue Client BadObserver Who’s to blame? Queue … but BadObserver violates the “informal” contract iContract blames Q

  21. What We Learned • Contracts should be a part of the class interface • Contracts should have a semantics so that we can determine whether a run-time system blames the appropriate component

  22. Contracts for Java Interfaces

  23. Contract Java • extend Java interfaces • keep Java semantics • inter-operate with existing Java (easily)

  24. The Language of Contracts: Pre/Post Conditions interface DoubleRoot { double getValue(); double sqrt(); @pre { this.getValue () >= 0.0 } @post { abs(sqrt * sqrt - this.getValue()) < 0.01 } contracts are boolean Java expressions thisrefers to the current object sqrtrefers to the result of the method call

  25. Incompleteness of Assertion Language interface Stack { void push(Object o); @post “o is at top of stack” Object pop(); @pre { !this.empty() } boolean empty(); } interface Stack { void push(Object o); @post: { this.top() == o } Object pop(); @pre { !this.empty() } boolean empty(); Object top(); @pre { !this.empty() } }

  26. Completeness: • … neither possible nor necessary • some properties aren’t computable • for some, the interfaces are too poor • state important invariants (safety) [see Rosenblum1995]

  27. What are the Design Problems? • classes implement multiple interfaces • substitutability • weakening & strengthening conditions • implied interface inheritance

  28. Multiple Interfaces: Meet one Pre class Cimplements I, J {} interface I { void out(int in); @pre { in < 0 } } interfaceJ { void out(int in); @pre { in > 0 } } class Client{ C c = new C(); ……... … ((I)c).m(xxx); … ……… … ((J)c).m(yyy); … }

  29. Multiple Interfaces: Meet one Post class Cimplements I, J {} interface I { int out(); @post { out < 0 } } interfaceJ { int out(); @post { out > 0 } } class Client{ C c = new C(); ……... … ((I)c).m(); … ……… … ((J)c).m(); … } deal with objects on a per interface basis -- principle of least astonishment!

  30. Substitutability (1) interface SimpleCounter { int getValue(); void dec(); void inc(); } interface PositiveCounter { int getValue(); void dec(); @pre { this.getValue() > 0 } void inc(); } class Counter implements SimpleCounter, PositiveCounter

  31. Substitutability (2) class Factory { SimpleCounter make() { return new Counter(); } } class Client { void m(SimpleCounter sc) { sc.dec(); } } class Main { … Client c = new Client(); Factory f = new Factory(); c.m((PositiveCounter) c.make() ); … } undetected violation

  32. Substitutability (3) • Who is guilty? • How do we detect it? class Proxy_Counter extends Counter { PositiveCounter c; Proxy_Counter(PositiveCounter x) { c = x; } void dec() { if (theValue < 0) Violation.error(“Main violated PositiveCounter”); super.dec(); } }

  33. Substitutability (4) • proxy classes violate object equality (==) of (explicit and implicit) casts • fixing this turns object equality into an expensive method • a true fix requires class loader modifications in addition (legacy libraries)

  34. Weakening & Strengthening “Post-s” factory pattern interface I { I make(); } class C implements I { … } interface J extends I { I make(); @post { make instanceof J } } class D extends C implements J { … } • it’s desirable • it’s okay • weakening could be done, too

  35. Weakening & Strengthening “Pre-s” extensible visitor pattern interface I { Object visit(Visitor_I t); } interface J extends I { Object visit(Visitor_I t); @pre { t instanceofVisitor_J } } • it’s desirable • it causes trouble: • require all implementations of J to satisfy pre • use proxies as before • weakening should be done; also causes problems

  36. Implied Interface Inheritance (1) class C implements I { … } class D extends C implements J , I { … } class C implements I { … } class D extends C implements J { … }

  37. Implied Interface Inheritance (2) interface Array { … void update(int ix, Object o) @pre { x < this.getSize() } } interface Resize_Array { … void update(int x, Object o) } class AC implements Array class Resize_AC extends AC implements Resize_Array Java forces a precondition on Resize_AC’s update if viewed as an Array --- better: eliminate implied interface inheritance from Java

  38. Compiling Contracts

  39. The Idea • elaborate contracts away • check interface hierarchy • contracts in interfaces become methods in implementations • method calls are re-directed

  40. Source with Contracts interface Queue { boolean empty(); Queue enq(Object X); @post { !this.empty() } Queue deq(); @pre { !this.empty() } void register(Observer o); } class Q implements Queue { boolean empty(); Queue enq(Object X) { … } Queue deq() { … } void register(Observer o) { … } }

  41. Elaborated Target (1) interface Queue { boolean empty(); Queue enq(Object X); @post { !this.empty() } Queue deq(); @pre { !this.empty() } void register(Observer o); } class Q implements Queue { boolean empty(); Queue enq_Queue(Object X) { Object o = this.enq(X); if (this.empty()) error(“Queue violated”); return o; } Queue enq(Object X) { … } … <to be continued>

  42. Elaborated Target (2) interface Queue { boolean empty(); Queue enq(Object X); @post { !this.empty() } Queue deq(); @pre { !this.empty() } void register(Observer o); } … Queue deq_Queue(String source) { if (this.empty()) error(source); this.deq(); } … }

  43. Elaborated Target (3) class O implements Observer { void onEnq(Queue q) { q.deq_Queue (“O violates Queue”); } … } class O implements Observer { void onEnq(Queue q) { q.deq(); } … }

  44. Elaboration with Multiple Interfaces interface I { S m(T x); @pre … @post … } interface J { S m(T x); @pre… @post … } class C implements I, J { … } class C implements I, J { S m_I(T x, String source) { … } S m_J(T x, String source) { … } S m(T x) { … } … }

  45. Combining Multiple “Post-s” interface I { S m(T x); @post post_I } interface J extends I { S m(T x); @post post_J } class C implements J { … } class C implements J { S m_J(T x, String source) { … test post_I and post J … } S m(T x) { … } … }

  46. Summary and Conclusion • Adding contracts to Java is a compromise. • It brings out weaknesses in Java design. • Future work is to design a variant of Java that is more accommodating to contracts.

  47. The End Joint work with Robby Findler Thanks to Matthew Flatt and Clemens Szyperski for discussions.

More Related