Semantics of an empty PermittedSubtypes attribute for the VM
John Rose
john.r.rose at oracle.com
Thu Apr 2 23:38:43 UTC 2020
On Apr 2, 2020, at 4:58 AM, Remi Forax <forax at univ-mlv.fr> wrote:
>
> the implementation in Hotspot ignores the attribute PermittedSubtypes if there is no subtype listed
AFAICT this behavior is an accident of prototype engineering,
and I’m glad we are clarifying it to be illegal.
Here are principles that I think are generally applicable to cases
like this one. I put them roughly in priority order.
- Strive for simple regular “clean” specifications.
(so, edge cases are corollaries not requiring separate spec rules)
- Avoid and/or reject useless degrees of freedom in specified inputs.
(so, don’t encourage inputs which say the same thing in two different ways)
- Avoid needlessly confusing the spec. reader.
(while satisfying the previous principles; specs are always somewhat tricky)
- Be ready to disregard prototype behavior and discard prototype code.
(because the spec. will have a 10x longer career than the prototype)
(The rest of this note expands a little more, FTR, on those points
as they apply to this case.)
The best approach to an edge case like this is either to base
its meaning on the same definition that applies to the non-edge
cases, or make it a checked error if the edge case occurs.
It is bad practice to accept the behavior of a prototype
implementation without change into a specification,
if that adds edge cases to the specification which don’t
provide value. The specification will long outlive the
code of the prototype, and it is the specification that
provides the long-term behavior of the JVM, not the
code. Therefore, spec. errors tend to be more costly
than code errors. We strive to get the spec right because
we’re going to have to live with it for many years.
We know from bad experience what it’s like to live
with the trail of bugs caused by a sloppy, inexact,
or needlessly complex spec.
In this case, the general rule for permitted subtypes of C
is that it denotes a set S of potential subtypes of C. If that
set S is empty, it’s just good logic that this means, according
to the specified rule, that there are no permitted subtypes,
which means C acts like it’s final (permits no subtypes).
It’s not good logic to say, “the writer of the subclass must
have meant to drop the attribute but wrote an empty set
instead”, although this is the sort of interpretation that
VM code might accidentally give to the occurrence, if it
fails to distinguish “missing attribute” from “empty list
attribute”. We could choose to import this irregular
interpretation as an edge case *in the spec*, and we are
sometimes forced to, but we prefer not to.
You might think I’m arguing here for allowing S to be
an empty set, and I might in similar cases, but there are two
other reasons to outlaw the edge case, rather than ask
the spec. to account for it (either by extending the general
rule, or adding a special rule). First, if C wants to permit
exactly zero subclasses, there’s already a notation for that.
Another principle of spec design is to try to avoid allowing
two ways to say that same thing. If two classfiles would
appear to be asking for different classes, but they actually
mean the same thing, there’s a smell in the classfile language.
We already have a way to say “permit no subs”, so it’s a smell
if we add another way.
Also, although often edge cases can be interpreted consistently
with a general rule (as above), they can have misleading connotations.
Zero length arrays and empty sets are notoriously confusing.
Apparently it took humans millennia to realize that zero is
a number. Although it is surely reasonable to demand that
people working with JVMs and classfiles understand how to
reason consistently about zero and empty sets, it’s still graceful
to avoid the occasion, if there are other reasons to do so.
And maybe there’s a way to color the behavior in the present
code as more than just an accident of prototyping, though I
doubt it. If so we’d have even more motivation to outlaw the
edge case, if there were two reasonable rules leading to
conflicting outcomes. But I think the present case is a
conflict between an unnecessary but reasonable extension
to the main rule, versus irregular behavior arising from
an incompletely considered decision during prototyping.
Which is fine, as long as we give it its due weight, and throw
away any behavior that muddies the spec.
Bottom line (for those who read to the bottom):
The JVM specification must be free of needless complications.
Given prototype behavior vs. clean spec, clean spec wins.
— John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200402/2b54d928/attachment-0001.htm>
More information about the amber-spec-experts
mailing list