Presentation is loading. Please wait.

Presentation is loading. Please wait.

Declaring and Checking Non-null Types in an Object-Oriented Language Authors: Manuel Fahndrich K. Rustan M. Leino OOPSLA’03 Presenter: Alexander Landau.

Similar presentations


Presentation on theme: "Declaring and Checking Non-null Types in an Object-Oriented Language Authors: Manuel Fahndrich K. Rustan M. Leino OOPSLA’03 Presenter: Alexander Landau."— Presentation transcript:

1 Declaring and Checking Non-null Types in an Object-Oriented Language Authors: Manuel Fahndrich K. Rustan M. Leino OOPSLA’03 Presenter: Alexander Landau

2 2 Exceptions are Everywhere class A { private string s; public A(string str) { s = str; } public int length() {return s.Length);} } int x = new A(null).length(); Exception!

3 3 Exceptions Used to signal about “bad things” during runtime. Better to find errors at compile-time! Types of exceptions:  Bad cast: dynamic type may only be known at runtime.  Division by zero: divisor unknown at compile time.  NULL dereference: compile-time checker can be created!  …

4 4 General Idea Splitting reference types into non-null and possibly-null types  Already implemented in ML’s and some other languages’ type systems. A non-null field provides a contract:  At construction, must be initialized with a non-null value.  Read access yields a non-null value.  Write access requires a non-null value.

5 5 Simple Solution Require that an object under construction cannot be accessed until fully constructed.  Possible in some languages, but not in mainstream ones like C#/Java, where this may be accessed from the constructor or from methods called by it.

6 6 Example (1) class A { [NotNull] string name; public A([NotNull] string s) { this.name = s; this.m(55); } virtual void m(int x) { … } } name initialized before use

7 7 Example (2), but what if… class B : A { [NotNull] string path; public B([NotNull] string p, [NotNull] string s) : base(s) { this.path = p; } override void m(int x) { … this.path … } m() called from A’s c’tor before B() initialized path!

8 8 A Glance at C++ In C++ base-class object is created and initialized (by c’tor). Then, derived-class object is created and initialized.  Virtual functions act as non-virtual when called from within c’tors.  The problem from the previous example is eliminated. In C#/Java, the object including all superclass objects is created first, then c’tors are called.  Virtual functions act as virtual even from within c’tors.

9 9 Advantages Documentation of method input parameters, output parameters and return values. Static (compile-time) check of object invariants such as non-null fields. Error detection at the point of error commitment, not when dereferencing nulls. No need to check for nulls at runtime – boosts performance. Reduce/eliminate unexpected null reference exceptions.

10 10 Non-null Types Notation:  T - - non-null references of type T. Just like T& in C++  T + - possibly-null references of type T. Just like T* in C++ Examples:  T - t = new T(…);// new never returns null  T + n = t;// n may be null  if (n != null) t=n;// here n is of type T -  int x = t.f;// t must be non-null

11 11 Construction Problem: half-baked objects in constructors.  this.f may be null even though f is declared as non- null. Notation: T raw- denotes partially-initialized object types.  T - ≤ T raw-. Rule: A T - field in C raw- object Read: May be null Write: Must be with a T - value.

12 12 The Construction Duty The c’tor must initialize all non-null fields.  Restricted to the object proper, not including sub- or super-class object fields. Every path through a c’tor must include an assignment to every non-null field. When a c’tor is called, all ancestor c’tors have already been called, thus members initialized. The last c’tor called due to new C(…) casts this from C raw- to C -. The annotation [Raw] allows a method to be called with this of type C raw-.

13 13 Example class A { [NotNull] string name; public A([NotNull] string s) { this.name = s; this.m(55); } [Raw] virtual void m(int x) { … } } class B : A { [NotNull] string path; public B([NotNull] string p, [NotNull] string s) : base(s) { this.path = p; } [Raw] override void m(int x) { … this.path … }

14 14 Arrays Arrays are references themselves and contain references. The array itself and/or its elements may be non- null or possibly-null:  T - [] - non-null array of non-null elements  T + [] - non-null array of possibly-null elements  T - [] + possibly-null array of non-null elements  T + [] + possibly-null array of possibly-null elements

15 15 Arrays - Problem In contrast to objects, there is no “constructor” that initializes all array elements to non-null values after allocation.  new T - [n] returns a reference of type T - [] raw-.  Reading a[i] may yield null.  Writing a[i] requires non-null.

16 16 Arrays - Solution Compiler can not know when array has finished initialization  Explicit cast required from programmer.  The cast validates the non-nullity of the elements. T - [] raw- aTmp = new T - [n]; // initialize the elements of aTmp T - [] - a = (T - [] - )aTmp;

17 17 Other Language Constructs (1) Structs  Default constructor initializes fields to zero- equivalent values (e.g. null for references).  Problem: Cannot be overridden!  Solution: All c’tors for a struct S produce a value of type S except the default c’tor which produces S raw.

18 18 Other Language Constructs (2) Call-by-reference parameters  Used for input – formal parameter type is a supertype of the actual parameter type.  Used for output - formal parameter type is a subtype of the actual parameter type. Required in order to maintain conformance.  Thus, no-variance on ref parameters  Problem: For a raw object, a field f of type T - yields T + on read and requires T - on write.  Solution: Disallow passing such fields as ref parameters.

19 19 Implementation Possible! Created by the authors.  Does not (yet) implement the full design.  Implemented at the CIL level. Does not modify the compiler or runtime. Works with other languages compiled into CIL. Tested on a ~20,000 lines program.

20 20 Implementation - Benefits Catches hard to find errors:  Vacuous initialization – this.foo = foo inside a c’tor. The goal was to initialize a field with a parameter, but there was no parameter named foo.  Wrong local bool m(Q other) { T that = other as T; if (other == null) return false;// should have used “that” if (this.bar != that.bar) …// “that” may be null

21 21 Conclusion Non-null types allow moving some errors from runtime to compile-time. Not a theoretical-only beast, implementations possible and exist. Less runtime checks, faster code. Backward compatible except in initialization, mainly in constructors.


Download ppt "Declaring and Checking Non-null Types in an Object-Oriented Language Authors: Manuel Fahndrich K. Rustan M. Leino OOPSLA’03 Presenter: Alexander Landau."

Similar presentations


Ads by Google