[Checkers] Ideas for reducing verbosity of annotations

Michael Ernst mernst at cs.washington.edu
Tue Jun 2 15:55:22 EDT 2009


With 105K lines annotated, Daikon has 1990 nullness annotations, or about 1
per 50 lines of code.

At least 85% of these can be attributed, directly or indirectly, to 4
causes (prototypes and 3 specific methods):

Prototype invariants (1042 annotations, or over 50% of all annotations):
  @Prototype
  @Dependant(when=Prototype.class, ...)
In the long term, it would be nice to refactor Daikon to remove these (if
the new design would be no worse than the current one, which I suspect can
be done).

Methods that return null if nothing is found (700 annotations, or about 35%):
 * isObvious and other uses of DiscardInfo:  320
 * get_ni_suppressions and other uses of NISuppressionSet: 250
 * find: 115

Here are some defaulting schemes that would make Daikon type-check with far
fewer annotations.

1. Inherit annotations from overridden method declarations.
   If no annotations are given, then copy down those from the parent class.

2. Inherit annotations from overridden method declarations if necessary.
   If no annotations are given, then copy down those from the parent class,
   if using the default would be a type error.  For example, if the default
   is Nullable, then a Nullable annotation on an argument would be
   inherited.  But if the default is NonNull, then no Nullable annotation
   on an argument would be inherited.

3. Mark a class as having a default for its uses, that overrides the
   default of the location where the use appears.  For example, if we so
   marked DiscardInfo, then every use of DiscardInfo would mean "@Nullable
   DiscardInfo".  Flow-sensitive local type inference would still work, and
   it would still be possible to write "@Nullable DiscardInfo" to override
   the default.

   Note that this is rather different than writing an annotation, such as
   @Interned or @Immutable, on a class declaration.  That states that all
   instances have the given property -- there is no way to get the alternate
   behavior.


Having too many annotations causes cognitive load, and having too few
annotations causes cognitive load.

 * Too few annotations:  Having the exact type available can be useful for
   documentation purposes; a developer doesn't have to hunt around for
   defaults to determine the annotation on a variable.

   Here are the currently proposed defaulting mechanisms:
    * syntactically containing elements (variable, method, class, package)
    * the overridden method declaration
    * the declaration of the type (whose qualifier we are trying to determine)
   (Have I missed any?)

 * Too many annotations:
    * Too much programmer effort to begin using the checkers.
    * Code clutter.  (This may be especially important if the annotations relate
      to some issue that does not matter to most programmers, most of the time.)
    * Marketing and PR:  without very low numbers, we may not be able to
      get people to try the tools!

I am not troubled by the verbosity of one annotation every 50-100 lines.
However, to cater for work styles different than my own, and to attract
developers, it likely makes sense to permit these additional techniques for
setting defaults.

What are your thoughts regarding the defaulting schemes above?  Should we
support them all and see which ones are most popular?


Here are some tools that might be useful:
 * A tool that determines the current annotation on a given type.  This can
   be looked up in the classfile (complication:  flow-sensitive type
   refinement), or written using the checker framework.
 * A tool that identifies all extraneous annotations (for instance, a
   programmer write add a default and see how many annotations it makes
   redundant).
 * A tool that converts from one set of defaults to another,
   adding/removing source code annotations as appropriate in such a way
   that the semantics of the program is preserved (the effective qualifier
   on each variable remains the same).
 * An "annotation minimizer" that determines the set of defaults that
   minimizes the annotations in a given codebase.


                    -Mike



More information about the checkers mailing list