[Checkers] Ideas for reducing verbosity of annotations

Jeff Perkins jhp at csail.mit.edu
Thu Jun 4 15:59:28 EDT 2009


Mike:

Some minor comments:

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

This might be nice for those working in an IDE, but I'd rather see
the annotations in general.  Is it an error for the annotations
not to match in an overriden method?

 > 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.

I don't fully understand this.  Are you suggesting that the parent
annotation become the new default?

 > 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.

I don't really care for this either.

I think my main concern with all of these is that they change what
you can infer when you don't see an annotation.  I think the extra
confusion is not worth the savings in typing.  That is probably because
I think these are useful annotations for the reader regardless of the
type checker.  If they were only used to make the code pass the type
checker, then using more defaults would seem reasonable.

I'm really not enthusiastic about customizaable defaults as that
would seemingly make it hard to understand code if you don't know
the defaulting scheme.

Another tool that you might consider would be a plugin to an IDE that
automatically copied down the annotations from the superclass.  If that
default is normally correct, then no extra typing would be required.
And if the IDE shows the annotation that has been defaulted, then my
concern about readability decreases.

-jeff

Michael Ernst wrote:
> 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