Title: Null Considered Harmful Author: Bob Duff, AdaCore Abstract: The "not null" syntax allows an Ada 2005 program to prevent access values from being null in cases where the null value is undesirable. This new syntax helps provide useful documentation. Ada, like many languages, defines a special 'null' value for access types. All values of an access type designate some object of the designated type, except for null, which does not designate any object. The null value can be used as a special flag. For example, a singly-linked list can be null-terminated. A Lookup function can return null to mean "not found", presuming the result is of an access type: type Ref_Element is access all Element; Not_Found : constant Ref_Element := null; function Lookup (T : Table) return Ref_Element; -- Returns Not_Found if not found. An alternative design for Lookup would be to raise an exception: Not_Found : exception; function Lookup (T : Table) return Ref_Element; -- Raises Not_Found if not found. -- Never returns null. <-- Ada 95 comment. Neither design is better in all situations; it depends in part on whether we consider the "not found" situation to be exceptional. Clearly, the client calling Lookup needs to know whether it can return null, and if so, what that means. In general, it's a good idea to document whether things can be null or not, especially for formal parameters and function results. In Ada 95, we do that with comments. In Ada 2005, we can use the "not null" syntax: function Lookup (T : Table) return not null Ref_Element; -- Ada 2005 In general, it's better to use the language proper for documentation, when possible, rather than comments, because compile-time and/or run-time checks can help ensure that the "documentation" is actually true. With comments, there's a greater danger that the comment will become false during maintenance, and false documentation is obviously a menace. In many, perhaps most, cases, null is just a tripping hazard. It's a good idea to put in "not null" when possible. In fact, a good argument can be made that "not null" should be the default, with extra syntax required when null _is_ wanted. This is the way SML works, for example -- you don't get any special null-like value unless you ask for it. Of course, Ada 2005 needs to be compatible with Ada 95, so "not null" cannot be the default for Ada. One word of caution: access objects are default-initialized to null, so if you have a "not null" object (or component) you had better initialize it explicitly, or you will get Constraint_Error. "Not null" is more often useful on parameters and function results, for this reason.package Example is type Element is limited private; type Ref_Element is access all Element; type Table is limited private; Not_Found : constant Ref_Element := null; function Lookup (T : Table) return Ref_Element; -- Returns Not_Found if not found. Not_Found_2 : exception; function Lookup_2 (T : Table) return not null Ref_Element; -- Raises Not_Found_2 if not found. procedure P (X : not null Ref_Element); procedure Q (X : not null Ref_Element); private type Element is limited record Component : Integer; end record; type Table is limited null record; end Example; package body Example is An_Element : aliased Element; function Lookup (T : Table) return Ref_Element is begin -- ... return Not_Found; end Lookup; function Lookup_2 (T : Table) return not null Ref_Element is begin -- ... raise Not_Found_2; return An_Element'Access; -- suppress error: 'missing "return" statement in function body' end Lookup_2; procedure P (X : not null Ref_Element) is begin X.all.Component := X.all.Component + 1; end P; procedure Q (X : not null Ref_Element) is begin for I in 1..1000 loop P (X); end loop; end Q; procedure R is begin Q (An_Element'Access); end R; end Example;