[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