1 / 27

Attached types and their application to three open problems of object-oriented programming

Attached types and their application to three open problems of object-oriented programming. Bertrend Meyer ETH Zurich and Eiffel Software. Itay Maman 236803 Seminar lecture, 8 November 2005. Motivation. Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException

whitley
Télécharger la présentation

Attached types and their application to three open problems of object-oriented programming

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. Attached types and their application to three open problems of object-oriented programming Bertrend Meyer ETH Zurich and Eiffel Software Itay Maman 236803 Seminar lecture, 8 November 2005

  2. Motivation Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at my.program.MainWindow$1.actionPerformed(MainWindow.java:33) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) Guarantee that in x.f(a1,a2,..), the receiver, x, will always denote an object • This talk: • Presents Meyer’s notion of non-null types • (Implemented in the Eiffel language) • We will use Java-like syntax

  3. Thoughts on static typing • Let’s consider x.f() • Static typing: Ensures that x will point to an object that “understands” the message f() • But, x could be null • null does not understand f() • => null pointers are “holes” in the static typing system • Elimination of null pointers is a typing issue • (Not a data analysis issue)

  4. null, what is it good for? • Special value • Indicating end-of-file, a missing value, etc. • Delayed initialization of fields • In a word-processor, there is no document object until the user opens a file • Two (or more) mutually dependent objects • Recursive data structures • Recursive data structures • Q: Can we find an alternative to null values?

  5. Null-safety in Eiffel (A new mechanism, recently proposed) • Non-null type: A type T has no null value • This is the default • Null type: ?T is a super type of T which has the null value • Only non-null types allow invocation of methods • The same goes for field access • Automatic conversion: T -> ?T • Checked conversion: ?T -> T

  6. Downcast+assign expression: • Check non null • Check dynamic type • Assign to a local variable A non-null program public class Printer { private PrintWriter out = System.out; public Printer(?PrintWriter pw) { if( (PrintWriter o = ) pw) { out = o; o.flush(); } } public void print(Object obj) { out.println(obj.toString()); } }

  7. An equivalent program public class Printer { private PrintWriter out = System.out; public Printer(PrintWriter pw) { Object temp = pw; if(temp instanceof PrintWriter) { PrintWriter o = (PrintWriter) temp; out = o; o.flush(); } } public void print(Object obj) { out.println(obj.toString()); } }

  8. CAP: Certified Attachment Patterns public class IntList { private ?IntList tail; private int n; public IntList(int n, ?IntList tail) { ... } public static void print(?IntList list) { while(list != null) { System.out.println(list.n); list = tail; } } } • The expression list.n is (statically) null-safe • Look at the loop condition! • This is a CAP of list

  9. CAPs • Definition: CAP(x) • A segment of code, where x is ensured to be non-null by some null test • x – An expression whose type is nullable • CAPs eliminate many downcast+assign expression • => Simple, intuitive code • Currently there are several standard CAPs • A compiler implementation cannot add a new CAP • Note that CAP for fields are more restricted • Scope is limited to first instruction after the null test

  10. Standard CAPs for locals // x is a nullable local variable: ?X x; while(x != null) { x.f(); x.g(); x = h(); } if(x != null) { x.f(); x.g(); x = h(); } if(x == null) { ... } else { x.f(); x.g(); x = h(); } x = new X(); x.f(); x.g();x = h(); b = (x != null) && (x.f() == x.g()); b = (x == null) || (x.f() == x.g()); assert x != null; x.f(); x.g(); x = h(); • If x is a field, only x.f() is legal

  11. Soundness • Assignment • ?T -> T is illegal • null -> T is illegal • Initialization • Formal arguments • Are always assigned upon method invocation • Local variables • Compiler already ensures proper initializaion • Fields…

  12. Soundness: Fields • The problem: Ensuring non-null initialization of fields • Historically, fields are initialized with null • Meyer’s approach: • Three distinct solutions…

  13. Solution 1/3: Self initializing types • Field Y.x is lazily initialized on first access • Only if not previously initialized • Applicable if X has a default constructor class X { public X() { } public void f() { } } class Y { private X x; publicvoid h() { x.f(); // Lazy initialization: // Invoke default constructor of x } }

  14. Solution 2/3: Self initializing fields • Field Circle.rect is lazily initialized on first access • Only if not previously initialized • Initialization block added to the field’s definition class Rectangle { Rectangle(int x0, int y0, int x1, int y1) { ... } } class Circle { privatefinalint cx, cy, r; private Rectangle rect { return new Rectangle(cx-r, cy-r, cx+r, cy+r); } public Circle(int cx, int cy, int r) { ... } public Rectangle getRect() { return rect; } }

  15. Solution 3/3: Initialization by constructors • The last case: • Non-null fields w/o initialization block • (The first two solutions do not apply) • The solution: • Initialization by every constructor • Statically enforced by the compiler

  16. Soundness: Summary • Assignment • Cannot set a null-safe entity to null • Initializaion • Arguments: Always initialized • Local variables: Initialization analysis • Fields • Non null types => Default constructor • Non null fileds = > Initialization block • Otherwise => Explicitly by all constructors

  17. Generics: The problem • Where’s the error here? class Cell<T> { private T value; public Cell() { } public Cell(T t) { value = t; } public T get() { return value; } } void main() { Cell<?String> c1 = new Cell<?String>(); Cell<?String> c2 = new Cell<?String>("abc"); Cell<String> c3 = new Cell<String>(); Cell<String> c4 = new Cell<String>("abc"); } • Generic code may break null-safety • When the actual generic type is non-null

  18. Generics: Solution? • The solution: Use self-initializing types • If Cell<T> uses T in a context where it hasn’t been provably initialized • => T must be self-initializing • This is statically enforced

  19. Design by contract (1/2) • Eiffel features design by contract • Pre/Post conditions, class invariants, … • How does it interact with non-null types? // This is “old” Eiffel code String niceString(Object o) require o != null; ensureresult != null; { if(o.toString() == null) return "<>"; return "<" + o.toString() + ">"; } • We can define new CAPs • Based on pre/post conditions

  20. Design by contract (2/2) • In “New” Eifflel, we can use non-null types • And get rid of many pre/post conditions // This is “new” Eiffel code String niceString(Object o) { if(o.toString() == null) return "<>"; return "<" + o.toString() + ">"; }

  21. Covariant input arguments • “old” Eiffel allow covariant input arguments • => Polymorphic calls may fail at run time • “New” Eiffel is a bit different… • The hierarchy: • PrivilegedAccount extends Account • PrivilegedCustomer extends Customer • Has a getInterest() method

  22. A covariant program • Covariance is now allowed only if the argument is nullable class Account { float interest = 0.03; Customer cus; void setCustomer(Customer c) { cus = c; } } class PrivilegedAccount { void setCustomer(?PrivilegedCustomer c) { super.setCustomer(c); // Can we invoke c.getSpecialInterest() ? } } class Account { float interest = 0.03; Customer cus; void setCustomer(Customer c) { cus = c; } } class PrivilegedAccount { void setCustomer(?PrivilegedCustomer c) { super.setCustomer(c); if((PrivilegedCustomer pc = ) c) interest = pc.getInterest(); } } • This mechanism is too flexible

  23. Comments (1/2) • Open questions • Covariance: CAP can bypass the downcast • Access to fields from constructor code • Arrays • Generics: Why not require a non-null actual type parameter • Currently requires self-initialization • Expressions such as if(list.next != null) are quite useful • With non-null being the default this becomes a bug

  24. Comments (2/2) • Downcast+Assign is used in two contexts • Null safety: Check-not-null and assign to a local • Covariance: Downcast to a restricted set of types • Why not split to two constructs? • Not trying to be backward compatible

  25. Further discussion • Null safety in standard Java • Just use the final keyword • Recursive data structures • Can we replace null values with “null objects” ?

  26. Using null-objects (1/2) // A null terminated list int max = -99999; for(Node n = start(); n != null; n = n.next) max = Math.max(max, n.value); // A null-object terminated list int max = -99999; for(Node n = start(); n.ok(); n = n.next) max = Math.max(max, n.value);

  27. Using null-objects (2/2) Class Node { ... public int max() { return Math.max(value, next.max()); } } Class NullNode { public int max() { return -99999; } }

More Related