Towards cleaner nesting

Brian Goetz brian.goetz at oracle.com
Tue Jan 7 21:31:38 UTC 2020


Yes, good catch.  Type parameters for a class X or method X are in 
NC(X); done.

On 1/7/2020 4:27 PM, Remi Forax wrote:
> Hi Brian,
> Nice sump-up, i like it very much.
>
> I believe we also need to think about type parameters, they are also 
> impacted by the nesting/static context so should be in NC(X).
>
> Rémi
>
> ------------------------------------------------------------------------
>
>     *De: *"Brian Goetz" <brian.goetz at oracle.com>
>     *À: *"amber-spec-experts" <amber-spec-experts at openjdk.java.net>
>     *Envoyé: *Mardi 7 Janvier 2020 21:30:27
>     *Objet: *Towards cleaner nesting
>
>     Everything about nesting in Java is a mess. The terminology is a
>     mess (top level classes, nested classes, inner classes, local
>     classes, anonymous classes); the set of restrictions on what can
>     nest in what is ad-hoc (can have local classes but not local
>     interfaces; inner classes cannot have static members, including
>     static nested classes), and the set of rules about what must be,
>     can be, or cannot be static is also ad-hoc (nested classes can be
>     static or not, nested interfaces are implicitly static, but local
>     and anonymous classes may not be static, even though it might make
>     sense.)  On top of that, we can nest classes in methods
>     (sometimes) and methods in classes but not methods in methods
>     (local methods).
>
>     Not only does this make for a lot of accidental complexity in
>     specification, implementation, and user's brains, but it means
>     every feature interact with this complexity.  Nested records are
>     implicitly static, but this meant that in 14 we can't have nested
>     records in non-static classes, because, non-static classes can't
>     have static members.  (Yes, this could be fixed; hold your "why
>     don't you just" suggestions.)  And we borked up the implementation
>     of local records the first time around, where they accidentally
>     capture effectively final locals, which they shouldn't -- because
>     we'd never really charted the "static local class" territory, and
>     got it wrong the first time.  (Yes, this can be fixed too, and
>     will be before 14 goes out.)
>
>     So, I'd like to propose a simpler, general story of nesting (which
>     is consistent with the ad-hoc rubbish we have) which we can get to
>     in stages.  The purpose of this mail is to discuss the model; in
>     what increments we get there is a separate story.
>
>     Goals:
>      - Anything (class, interface, record, enum, method) can be nested
>     in anything;
>      - Some things are always static (enums, records, interfaces) when
>     nested; the rest can be made static when desired;
>      - The rule about "no static members in nonstatic nested classes"
>     has to go;
>      - Rules about whether members / locals from enclosing contexts
>     can be specified in a single place, using local reasoning.
>
>     The core of this is coming to an understanding of what "static"
>     means.  When construct X nests in Y (whether X and Y are classes,
>     methods, interfaces, etc), for "X" to be "static" means that
>     nesting is being used purely for purposes of namespacing, and not
>     for purposes of having access to names (locals or nonstatic class
>     members) from enclosing constructs.
>
>     Unfortunately all the terms we might use for whether or not a
>     symbol in an outer construct can be used in a nested construct --
>     such as "accessible" -- are overloaded with other meanings.  For
>     purposes of this discussion, let's call this "capturable" (this is
>     also overloaded, but less so.)  Each construct (class type or
>     method) has two sets of names from outer constructs that are
>     capturable -- a _statically capturable_ set SC(X), and a
>     _non-statically capturable_ set NC(X).  We can define
>     capturability using local reasoning:
>
>     Base cases:
>      - Names of static members in X are in SC(X);
>      - Names of instance members of X (if X is a class) or effectively
>     final locals of X (if X is a method) are in NC(X);
>
>     Induction cases, where X is nested directly in Y:
>      - SC(Y) is in SC(X)
>      - If _X is not static_, then NC(Y) is in NC(X)
>
>     We then say that X can capture names in SC(X) and NC(X); all we
>     need to compute capturability is the capture sets of X's
>     immediately enclosing construct, and whether X is static or not in
>     that construct (modulo shadowing etc.)
>
>     For the math-challenged, what this means is:
>      - A nested construct can access static members of all the
>     enclosing constructs;
>      - A nested non-static construct can access instance members and
>     effectively final locals of all enclosing constructs, up until we
>     hit a static construct, and then capturing stops.  (So if Z is
>     nested in Y is nested in static X, Z can access instance members /
>     eff final locals of Y and X but not anything non-static from
>     outside of X.)
>
>     Note that this is consistent with what currently happens when X is
>     a method as well as a class type; static methods in a class
>     "capture" the static members of the enclosing class, and instance
>     methods also capture the instance members of the enclosing class
>     -- and also consistent with capturing in lambdas and anonymous
>     classes, if we assume that these are always non-static constructs.
>
>     We then say enums, records, and interfaces are _always_ static
>     when nested, whether declared so or not, we eliminate the
>     restriction about static members in non-static nested classes (now
>     that we have a clear semantics for them), and allow local classes
>     to be declared as static.  (Eventually, we also relax the
>     restrictions about methods in methods, static or not.)
>
>     (Additionally, the model supports the notion of "static lambda"
>     and "static anonymous class" with obvious semantics (can't capture
>     anything); we can decide later whether adding this flexibility is
>     worth the additional surface syntax.)
>
>     This is a strict superset of the status quo, and yields a more
>     flexible and regular language -- and hopefully a simpler spec
>     (since so many of these cases are specified as ad-hoc corner cases.)
>
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200107/cc5fc5ab/attachment.htm>


More information about the amber-spec-experts mailing list