File: interning-checker.tex

package info (click to toggle)
checker-framework-java 3.2.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 22,840 kB
  • sloc: java: 145,910; xml: 839; sh: 518; makefile: 401; perl: 26
file content (461 lines) | stat: -rw-r--r-- 17,921 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
\htmlhr
\chapterAndLabel{Interning Checker}{interning-checker}

If the Interning Checker issues no errors for a given program, then all
reference equality tests (i.e., all uses of ``\code{==}'') are proper;
that is,
\code{==} is not misused where \code{equals()} should have been used instead.

Interning is a design pattern in which the same object is used whenever two
different objects would be considered equal.  Interning is also known as
canonicalization or hash-consing, and it is related to the flyweight design
pattern.
Interning has two benefits:  it can save memory, and it can speed up testing for
equality by permitting use of \code{==}.

The Interning Checker prevents two types of problems in your code.
First, it prevents using \code{==} on
non-interned values, which can result in subtle bugs.  For example:

\begin{Verbatim}
  Integer x = new Integer(22);
  Integer y = new Integer(22);
  System.out.println(x == y);  // prints false!
\end{Verbatim}

\noindent
Second,
the Interning Checker helps to prevent performance problems that result
from failure to use interning.
(See Section~\ref{checker-guarantees} for caveats to the checker's guarantees.)

Interning is such an important design pattern that Java builds it in for
these types: \<String>, \<Boolean>, \<Byte>, \<Character>, \<Integer>,
\<Short>.  Every string literal in the program is guaranteed to be interned
(\href{https://docs.oracle.com/javase/specs/jls/se11/html/jls-3.html#jls-3.10.5}{JLS
  \S3.10.5}), and the
\sunjavadoc{java.base/java/lang/String.html\#intern()}{String.intern()} method
performs interning for strings that are computed at run time.
The \<valueOf> methods in wrapper classes always (\<Boolean>, \<Byte>) or
sometimes (\<Character>, \<Integer>, \<Short>) return an interned result
(\href{https://docs.oracle.com/javase/specs/jls/se11/html/jls-5.html#jls-5.1.7}{JLS \S5.1.7}).
Users can also write their own interning methods for other types.

It is a proper optimization to use \code{==}, rather than \code{equals()},
whenever the comparison is guaranteed to produce the same result --- that
is, whenever the comparison is never provided with two different objects
for which \code{equals()} would return true.  Here are three reasons that
this property could hold:

\begin{enumerate}
\item
  Interning.  A factory method ensures that, globally, no two different
  interned objects are \code{equals()} to one another.
  (For some classes, every instance is interned; however, in other cases it is
  possible for two objects of the class to be
  \code{equals()} to one another, even if one of them is interned.)
  Interned objects should always be immutable.
\item
  Global control flow.  The program's control flow is such that the
  constructor for class $C$ is called a limited number of times, and with
  specific values that ensure the results are not \code{equals()} to one
  another.  Objects of class $C$ can always be compared with \code{==}.
  Such objects may be mutable or immutable.
\item
  Local control flow.  Even though not all objects of the given type may be
  compared with \code{==}, the specific objects that can reach a given
  comparison may be.
  \begin{itemize}
  \item
    When searching for an element (say, in a collection), \code{==} may be
    appropriate.
  \item
    Some routines return either their argument, or a modified version of
    it.  Your code might compare \code{s == s.toLowerCase()} to see whether
    a string contained any upper-case characters.
  \end{itemize}
\end{enumerate}

To eliminate Interning Checker errors, you will need to annotate the
declarations of any expression used as an argument to \code{==}.
Thus, the Interning Checker
could also have been called the Reference Equality Checker.
% In the
% future, the checker will include annotations that target the non-interning
% cases above, but for now you need to use \<@Interned>, \<@UsesObjectEquals>
% (which handles a surprising number of cases), and/or
% \<@SuppressWarnings>.

\begin{sloppypar}
To run the Interning Checker, supply the
\code{-processor org.checkerframework.checker.interning.InterningChecker}
command-line option to javac.  For examples, see Section~\ref{interning-example}.
\end{sloppypar}


\sectionAndLabel{Interning annotations}{interning-annotations}

\subsectionAndLabel{Interning qualifiers}{interning-qualifiers}

These qualifiers are part of the Interning type system:

\begin{description}

\item[\refqualclass{checker/interning/qual}{Interned}]
  indicates a type that includes only interned values (no non-interned
  values).

\item[\refqualclass{checker/interning/qual}{InternedDistinct}]
  indicates a type such that each value is not \<equals()> to any other
  Java value.  This is a stronger (more restrictive) property than
  \<@Interned>, but is a weaker property than writing \<@Interned> on a
  class declaration.  For
  details, see Section~\ref{interning-distinct}.

\item[\refqualclass{checker/interning/qual}{UnknownInterned}]
  indicates a type whose values might or might not be interned.
  It is used internally by the type system and is not written by programmers.

\item[\refqualclass{checker/interning/qual}{PolyInterned}]
  indicates qualifier polymorphism (see
  Section~\ref{qualifier-polymorphism}).

\end{description}

\subsectionAndLabel{Interning method and class annotations}{interning-declaration-annotations}

\begin{description}

\item[\refqualclass{checker/interning/qual}{UsesObjectEquals}]
  is a class annotation (not a type annotation) that indicates that this class's
  \<equals> method is the same as that of \<Object>.  In other words,
  neither this class nor any of its superclasses overrides the \<equals>
  method.  Since \<Object.equals> uses reference equality, this means that
  for such a class, \<==> and \<equals> are equivalent, and so the
  Interning Checker does not issue errors or warnings for either one.

\item[\refqualclass{checker/interning/qual}{InternMethod}]
  is a method declaration annotation that indicates that this method
  returns an interned object and may be invoked
  on an uninterned object. See Section~\ref{interning-intern-methods} for more details.
\end{description}

\sectionAndLabel{Annotating your code with \code{@Interned}}{interning-annotating}

\begin{figure}
\includeimage{interning}{2.5cm}
\caption{Type hierarchy for the Interning type system.}
\label{fig-interning-hierarchy}
\end{figure}

In order to perform checking, you must annotate your code with the \refqualclass{checker/interning/qual}{Interned}
type annotation.  A type annotated with \<@Interned> contains the canonical
representation of an
object:

%BEGIN LATEX
\begin{smaller}
%END LATEX
\begin{Verbatim}
            String s1 = ...;  // type is (uninterned) "String"
  @Interned String s2 = ...;  // type is "@Interned String"
\end{Verbatim}
%BEGIN LATEX
\end{smaller}
%END LATEX

The Interning Checker ensures that only interned
values can be assigned to \code{s2}.

\sectionAndLabel{Interned classes}{interning-interned-classes}

An interned annotation on a class declaration indicates that all objects of a
type are interned \textit{except for newly created objects}. That means that
all uses of such types are \<@Interned> by default and the type \<@UnknownInterned
MyClass> is an invalid type.

An exception is \textit{constructor results}. Constructor results and \<this> within the
body of the constructor are \<@UnknownInterned> by default. Although \<@UnknownInterned InternClass>
is not a legal type, no ``type.invalid'' error is issued at constructor declarations.
Instead, an ``interned.object.creation''
error is issued at the invocation of the constructor. The user should inspect
this location and suppress the warning if the newly created object is interned.

For example:

\begin{Verbatim}
@Interned class InternedClass {
  @UnknownInterned InternedClass() {
  // error, "this" is @UnknownInterned.
  @Interned InternedClass that = this;
  }

  @SuppressWarnings("intern") // Only creation of an InternedClass object.
  static final InternedClass ONE = new InternedClass();
}
\end{Verbatim}

\subsectionAndLabel{The intern() methods}{interning-intern-methods}
Some interned classes use an \<intern()> method to look up the interned version of
the object. These methods must be annotated with the declaration annotation
\<@InternMethod>. This allows the checker to verify that a newly created object
is immediately interned and therefore not issue an interned object creation
error.

\begin{Verbatim}
new InternedClass().intern() // no error
\end{Verbatim}

Because an \<intern> method is expected to be called on uninterned objects, the
type of \<this> in \<intern> is implicitly \<@UnknownInterned>. This will cause an
error if \<this> is used someplace where an interned object is expected.  Some
of these warnings will be false positives that should be suppressed by the
user.

\begin{Verbatim}
@InternMethod
public InternedClass intern() {
  // Type of "this" inside an @InternMethod is @UnknownInterned
  @Interned InternedClass that = this; // error

  if (!pool.contains(this)) {
    @SuppressWarning("interning:assignment.type.incompatible")
    @Interned InternedClass internedThis = this;
    pool.add(internedThis);
  }
  return pool.get(this);
}
\end{Verbatim}

Some interned classes do not use an intern method to ensure that every object
of that class is interned.  For these classes, the user will have to manually
inspect every constructor invocation and suppress the ``interned.object.creation''
error.

If every invocation of a constructor is guaranteed to be interned, then the
user should annotate the constructor result with \<@Interned> and suppress a
warning at the constructor.

\begin{Verbatim}
@Interned class AnotherInternedClass {
  // manually verified that all constructor invocations used such that all
  // new objects are interned
  @SuppressWarnings("super.invocation.invalid")
  @Interned AnotherInternedClass() {}
}
\end{Verbatim}


\subsectionAndLabel{Default qualifiers and qualifiers for literals}{interning-implicit-qualifiers}

The Interning Checker
adds qualifiers to unannotated types, reducing the number of annotations that must
appear in your code (see Section~\ref{effective-qualifier}).

For a complete description of all defaulting rules for interning qualifiers, see the
Javadoc for \refclass{checker/interning}{InterningAnnotatedTypeFactory}.

\subsectionAndLabel{InternedDistinct: values not equals() to any other value}{interning-distinct}

The \refqualclass{checker/interning/qual}{InternedDistinct} annotation
represents values that are not \<equals()> to any other value.  Suppose
expression \<e> has type \<@InternedDistinct>.  Then \<e.equals(x) == (e ==
x)>.  Therefore, it is legal to use \<==> whenever at least one of the
operands has type \<@InternedDistinct>.

\<@InternedDistinct> is stronger (more restrictive) than \<@Interned>.
For example, consider these variables:

\begin{Verbatim}
@Interned String i = "22";
          String s = new Integer(22).toString();
\end{Verbatim}

\noindent
The variable \<i> is not \<@InternedDistinct> because \<i.equals(s)> is true.

\<@InternedDistinct> is not as restrictive as stating that all objects of a
given Java type are interned.

The \<@InternedDistinct> annotation is rarely used, because it arises from
coding paradigms that are tricky to reason about.
%
One use is on static fields
that hold canonical values of a type.
Given this declaration:

\begin{Verbatim}
class MyType {
  final static @InternedDistinct MyType SPECIAL = new MyType(...);
  ...
}
\end{Verbatim}

\noindent
it would be legal to write \<myValue == MyType.SPECIAL> rather than
\<myValue.equals(MyType.SPECIAL)>.

The \<@InternedDistinct> is trusted (not verified), because it would be too
complex to analyze the \<equals()> method to ensure that no other value is
\<equals()> to a \<@InternedDistinct> value.  You will need to manually
verify that it is only written in locations where its contract is satisfied.
For example, here is one set of guidelines that you could check manually:
\begin{itemize}
\item The constructor is private.
\item The factory method (whose return type is annotated with
  \<@InternedDistinct> returns the canonical version for certain values.
\item The class is final, so that subclasses cannot violate these properties.
\end{itemize}


\sectionAndLabel{What the Interning Checker checks}{interning-checks}

Objects of an \refqualclass{checker/interning/qual}{Interned} type may be safely compared using the ``\code{==}''
operator.

The checker issues an error in two cases:

\begin{enumerate}

\item
  When a reference (in)equality operator (``\code{==}'' or ``\code{!=}'')
  has an operand of non-\refqualclass{checker/interning/qual}{Interned} type.
  As a special case, the operation is permitted if either argument is of
  \refqualclass{checker/interning/qual}{InternedDistinct} type

\item
  When a non-\refqualclass{checker/interning/qual}{Interned} type is used
  where an \refqualclass{checker/interning/qual}{Interned} type
  is expected.

\end{enumerate}

This example shows both sorts of problems:

\begin{Verbatim}
                    Date  date;
          @Interned Date idate;
  @InternedDistinct Date ddate;
  ...
  if (date == idate) ...  // error: reference equality test is unsafe
  idate = date;           // error: idate's referent might no longer be interned
  ddate = idate;          // error: idate's referent might be equals() to some other value
\end{Verbatim}

\label{lint-dotequals}

The checker also issues a warning when \code{.equals} is used where
\code{==} could be safely used.  You can disable this behavior via the
javac \code{-Alint=-dotequals} command-line option.

For a complete description of all checks performed by
  the checker, see the Javadoc for
  \refclass{checker/interning}{InterningVisitor}.

\label{checking-class}
You can also restrict which types the checker should examine and type-check,
using the \code{-Acheckclass} option.  For example, to find only the
interning errors related to uses of \code{String}, you can pass
\code{-Acheckclass=java.lang.String}.  The Interning Checker always checks all
subclasses and superclasses of the given class.


\subsectionAndLabel{Imprecision (false positive warnings) of the Interning Checker}{interning-limitations}

% There is no point to linking to the Javadoc for the valueOf methods,
% which don't discuss interning.

The Interning Checker conservatively assumes that the \<Character>, \<Integer>,
and \<Short> \<valueOf> methods return a non-interned value.  In fact, these
methods sometimes return an interned value and sometimes a non-interned
value, depending on the run-time argument (\href{https://docs.oracle.com/javase/specs/jls/se11/html/jls-5.html#jls-5.1.7}{JLS
\S5.1.7}).  If you know that the run-time argument to \<valueOf> implies that
the result is interned, then you will need to suppress an error.
(The Interning Checker should make use of the Value Checker to estimate the upper
and lower bounds on char, int, and short values so that it can more
precisely determine whether the result of a given \<valueOf> call is
interned.)



\sectionAndLabel{Examples}{interning-example}

To try the Interning Checker on a source file that uses the \refqualclass{checker/interning/qual}{Interned} qualifier,
use the following command:

\begin{mysmall}
\begin{Verbatim}
  javac -processor org.checkerframework.checker.interning.InterningChecker docs/examples/InterningExample.java
\end{Verbatim}
\end{mysmall}

\noindent
Compilation will complete without errors or warnings.

To see the checker warn about incorrect usage of annotations, use the following
command:

\begin{mysmall}
\begin{Verbatim}
  javac -processor org.checkerframework.checker.interning.InterningChecker docs/examples/InterningExampleWithWarnings.java
\end{Verbatim}
\end{mysmall}

\noindent
The compiler will issue an error regarding violation of the semantics of
\refqualclass{checker/interning/qual}{Interned}.
% in the \code{InterningExampleWithWarnings.java} file.


The Daikon invariant detector
(\myurl{http://plse.cs.washington.edu/daikon/}) is also annotated with
\refqualclass{checker/interning/qual}{Interned}.  From directory \code{java/},
run \code{make check-interning}.



\sectionAndLabel{Other interning annotations}{other-interning-annotations}

The Checker Framework's interning annotations are similar to annotations used
elsewhere.

If your code is already annotated with a different interning
annotation, the Checker Framework can type-check your code.
It treats annotations from other tools
as if you had written the corresponding annotation from the
Interning Checker, as described in Figure~\ref{fig-interning-refactoring}.
If the other annotation is a declaration annotation, it may be moved; see
Section~\ref{declaration-annotations-moved}.


% These lists should be kept in sync with InterningAnnotatedTypeFactory.java .
\begin{figure}
\begin{center}
% The ~ around the text makes things look better in Hevea (and not terrible
% in LaTeX).
\begin{tabular}{ll}
\begin{tabular}{|l|}
\hline
 ~com.sun.istack.internal.Interned~ \\ \hline
\end{tabular}
&
$\Rightarrow$
~org.checkerframework.checker.interning.qual.Interned~
\end{tabular}
\end{center}
%BEGIN LATEX
\vspace{-1.5\baselineskip}
%END LATEX
\caption{Correspondence between other interning annotations and the
  Checker Framework's annotations.}
\label{fig-interning-refactoring}
\end{figure}



% LocalWords:  plugin MyInternedClass enum InterningExampleWithWarnings java
% LocalWords:  PolyInterned Alint dotequals quals InterningAnnotatedTypeFactory
% LocalWords:  javac InterningVisitor JLS Acheckclass UsesObjectEquals
%  LocalWords:  consing valueOf superclasses s2 cleanroom canonicalization
%%  LocalWords:  InternedDistinct UnknownInterned myValue MyType MyClass
% LocalWords:  toLowerCase InternMethod uninterned InternClass