Discussion:
Deprecation beyond the level of types
Stephan Herrmann
2018-04-01 11:31:50 UTC
Permalink
I'm looking at how deprecation affects elements larger than types,
and it seems to me that deprecation is much weaker than it could be.

Packages: JLS & javadoc agree that @Deprecated applied to a package
has no effect. Given that @Target explicitly includes PACKAGE this
looks inconsistent to me. A user adding @Deprecated to a package would
certainly expect *some* effect, no?
JLS argues about the same programmer developing the package and
managing its export from then enclosing module. I fail to see how this
justifies the decision to let deprecation of packages go without warning.
If a library developer deprecates an exported package, shouldn't this
signal to consumers of the library, that they should migrate away from
using types within that package? Currently it doesn't, because consumers
will see no effect of that deprecation.

Modules: I could find no reference in JLS specifying any relation between
modules and deprecation. In the javadoc of @Deprecated, however, I find
some additions (apparently not provided/reviewed via jigsaw), notably:
"A module being deprecated does not cause warnings to be issued for
uses of types within the module."
I assume "within the module" binds to "types" not "uses", right?
(nitpick: "within the module" is not a specified term, "associated with" is).
For a named module, this makes sense, since "requires" will already raise
a warning for the deprecated module, and hence flagging each use of a type
from that module adds little value.
For unnamed modules, however, this seems to completely bypass any module-
level deprecation. There is no "requires" that could be flagged, and use
of types from the deprecated modules isn't flagged either.

Ergo: most today's consumers of libraries that deprecate either a module
or a package will not be informed about this deprecation by compilers.


If the rules of JEP 261 define the set of default root modules in a way
that ensures that no deprecated modules are in the module graph, then I
could imagine as the very minimum that any command line option that pulls
in a deprecated module (--add-modules, --modulepath, maybe more), will
trigger a warning. The only real problem with that approach is that there
is no place where these warnings could be individually suppressed (unless
new options were introduced like --add-deprecated-modules ...).


I see two consequences from the above:
There's little to no incentive to use @Deprecated at any level greater than
types, because it is not reliably communicated to users. We keep thinking
in terms of types, not modules (not even packages).
Second, developers of unnamed modules will see fewer deprecation warnings.
Hence, migrating from unnamed to named has an additional burden of having
to deal with warnings that could have been dealt with before, but simply
weren't visible.

Are there any plans to improve in this area?
Stephan

PS: I also checked if JEP 277 has a say on these issues, but the JEP page
doens't give any hints in this direction. As always please let us know if
there is more recent information regarding any of the closed JEPs.
Alex Buckley
2018-04-03 00:49:46 UTC
Permalink
Post by Stephan Herrmann
certainly expect *some* effect, no?
I understand that JSR 175 forgot to restrict the targets of the
Deprecated annotation type, which meant it was possible to write
@Deprecated on a package declaration. This should have been disallowed,
because (as you imply) no-one conceived of a warning or an error when
the package is imported/used. The targets of Deprecated were specified
in Java SE 7 as part of the background work for JSR 308; PACKAGE was
included for source compatibility with package declarations that already
Post by Stephan Herrmann
JLS argues about the same programmer developing the package and
managing its export from then enclosing module. I fail to see how this
justifies the decision to let deprecation of packages go without warning.
If a library developer deprecates an exported package, shouldn't this
signal to consumers of the library, that they should migrate away from
using types within that package? Currently it doesn't, because consumers
will see no effect of that deprecation.
The JLS "argument" that you mention is a corner case that concerns a
deprecated package being exported in a qualified fashion. It's not meant
to be a general justification "to let deprecation of packages go without
warning". The reason why exporting a deprecated package doesn't generate
a warning is because no other use of a deprecated package generates a
warning. (And note JEP 211, which reduced the population of warnings for
a deprecated package even further, at `import`.)

Of course, we could change this behavior, and have long discussions
about whether deprecating a package means "deprecate the package, not
its types" or "deprecate its types, not the package". But it's not on
the radar at this time.
Post by Stephan Herrmann
Modules: I could find no reference in JLS specifying any relation between
modules and deprecation.
I enumerated "program elements" in the first sentence of JLS 9.6.4.6
specifically to show that "modules" are as subject to deprecation as
classes, fields, etc. It's easily concluded from the section that, say,
requiring a deprecated module (directly or indirectly) should cause a
warning.
Post by Stephan Herrmann
"A module being deprecated does not cause warnings to be issued for
uses of types within the module."
For a named module, this makes sense, since "requires" will already raise
a warning for the deprecated module, and hence flagging each use of a type
from that module adds little value.
For unnamed modules, however, this seems to completely bypass any module-
level deprecation. There is no "requires" that could be flagged, and use
of types from the deprecated modules isn't flagged either.
Ergo: most today's consumers of libraries that deprecate either a module
or a package will not be informed about this deprecation by compilers.
...
Post by Stephan Herrmann
types, because it is not reliably communicated to users. We keep thinking
in terms of types, not modules (not even packages).
Second, developers of unnamed modules will see fewer deprecation warnings.
Hence, migrating from unnamed to named has an additional burden of having
to deal with warnings that could have been dealt with before, but simply
weren't visible.
You're right -- the JLS does not mandate a warning when compiling code
on the classpath that uses code in deprecated modules. But it's
short-sighted to say that deprecation warnings mandated by
modularization are a burden; they communicate important information
which couldn't be communicated by the compiler before.

Alex
Stephan Herrmann
2018-04-24 18:55:34 UTC
Permalink
Thanks, Alex, for your answer, and sorry for the long delay on my side.

I found the background regarding deprecation of packages quite interesting,
and agree to most of what you say.
You're right -- the JLS does not mandate a warning when compiling code on the classpath that uses code in deprecated modules.
Wouldn't it be more consistent to give such warnings?
Why should writing code in an unnamed vs. named module make a
difference in whether or not I'm seeing deprecation warnings?

Would you consider a compiler that issues such warnings as violating JLS?

thanks,
Stephan
Alex Buckley
2018-04-24 19:32:28 UTC
Permalink
Post by Stephan Herrmann
Post by Alex Buckley
You're right -- the JLS does not mandate a warning when compiling code
on the classpath that uses code in deprecated modules.
Wouldn't it be more consistent to give such warnings?
Why should writing code in an unnamed vs. named module make a
difference in whether or not I'm seeing deprecation warnings?
Consistent yes, usable no. The possibility of a module being deprecated
is not understood by vast amounts of code on the classpath written
before Java SE 9. If deprecating a module implicitly deprecated all its
exported public types, then code on the classpath would start to see
warnings "out of thin air" -- nothing that the classpath code refers to
by name would be explicitly deprecated. We thought such "action at a
distance" was too great a burden to impose on classpath code. (And we
are consistent in not imposing "action at a distance" -- applying
@SuppressWarnings to a module declaration does NOT implicitly suppress
warnings for all the type declarations in the module.)
Post by Stephan Herrmann
Would you consider a compiler that issues such warnings as violating JLS?
A compiler can only issue _deprecation warnings_ (and their brother,
_removal warnings_) where the JLS mandates it. But a compiler is free to
issue other kinds of warnings anywhere. For example, javac has
-Xlint:dep-ann which issues warnings related to, but not exactly about,
deprecation.

Alex

Loading...