<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <br>
    <br>
    <blockquote type="cite"
cite="mid:CAC1Wh8ErVgE3JpJGCrwmg=XO77pz0iRfap2PgivCN--NS91omA@mail.gmail.com">
      <div dir="ltr">
        <div>Two remarks. First, I'm not sure what you mean by "static
          lambda". Of course it is already possible for a lambda to be
          declared as a static member of some class (static Runnable r =
          () -> {};), so you must mean something else, but I don't
          know what that is. Do you imagine a special declaration mode
          for a lambda that asks the compiler to ensure that it captures
          nothing?</div>
      </div>
    </blockquote>
    <br>
    Not that I am saying Java needs these, but ...<br>
    <br>
    Lambdas can capture effectively final locals; those that happen to
    not do so are translated differently (the instance is cached at the
    capture side, so have better performance characteristics.)  Thing is
    an example of the compiler _inferring_ that the lambda could have
    been "static" (captures nothing from its context).  But the flip
    side is where the author would _declare_ that the lambda _cannot_
    capture anything. This guarantees the better translation, but also
    gets better type chekcing -- if the author mistakenly captures
    something, they get a compiler error, rather than slower
    performance.  So this is what I mean by a "static lambda" -- a
    lambda that is declare to _not be allowed_ to capture anything.  <br>
    <br>
    It gets worse with anon classes, because we don't even do the
    inference and the better translation there when we can, and not
    capture the enclosing instance when it doesn't get used, causing
    more footprint and potentially unintended retention.  <br>
    <br>
    <blockquote type="cite"
cite="mid:CAC1Wh8ErVgE3JpJGCrwmg=XO77pz0iRfap2PgivCN--NS91omA@mail.gmail.com">
      <div dir="ltr">Second, how do code-containing constructs which are
        not methods or classes fit into this? I have field initializers
        in mind, but maybe static/instance initializers are relevant
        too. Does it make sense to nest a method inside of an instance
        initializer? <br>
      </div>
    </blockquote>
    <br>
    For purposes of the capturing rules, field initializers for {
    static, instance } fields should be treated as nested { static,
    instance } methods, and similar for { static, instance }
    initializers.  <br>
    <br>
    The question of whether to _allow_ local methods in these things is
    a separate story; there is a pro (consistency) and a con (ugh,
    really?) argument to be made there, but if we did, the capture rules
    would follow cleanly.<br>
    <br>
    (This rabbit hole goes deeper; in theory there could be local
    methods wherever a statement goes, such as:<br>
    <br>
    Â Â Â  int x = switch (z) { <br>
    Â Â Â Â Â Â Â  case 0 -> {<br>
    Â Â Â Â Â Â Â Â Â Â Â  int f(z) { ... }<br>
    Â Â Â Â Â Â Â Â Â Â Â  yield f(z);<br>
    Â Â Â Â Â Â Â  }<br>
    Â Â Â  }<br>
    <br>
    ... and one of these fellows could go in a static initializer.  <br>
    <br>
    Again, we get to decide how deep down the rabbit hole we want to
    go.)<br>
    <br>
    <blockquote type="cite"
cite="mid:CAC1Wh8ErVgE3JpJGCrwmg=XO77pz0iRfap2PgivCN--NS91omA@mail.gmail.com"><br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Tue, Jan 7, 2020 at 12:31
          PM Brian Goetz <<a href="mailto:brian.goetz@oracle.com"
            moz-do-not-send="true">brian.goetz@oracle.com</a>> wrote:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px
          0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div> <font size="+1"><tt>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).  <br>
                <br>
                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.)  <br>
                <br>
                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.<br>
                <br>
                Goals:<br>
                Â - Anything (class, interface, record, enum, method) can
                be nested in anything;<br>
                Â - Some things are always static (enums, records,
                interfaces) when nested; the rest can be made static
                when desired;<br>
                Â - The rule about "no static members in nonstatic nested
                classes" has to go;<br>
                Â - Rules about whether members / locals from enclosing
                contexts can be specified in a single place, using local
                reasoning.<br>
                <br>
                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.  <br>
                <br>
                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:<br>
                <br>
                Base cases:<br>
                Â - Names of static members in X are in SC(X);<br>
                Â - 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); <br>
                <br>
                Induction cases, where X is nested directly in Y:<br>
                Â - SC(Y) is in SC(X)<br>
                Â - If _X is not static_, then NC(Y) is in NC(X)<br>
                <br>
                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.) 
                <br>
                <br>
                For the math-challenged, what this means is:<br>
                Â - A nested construct can access static members of all
                the enclosing constructs;<br>
                Â - 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.)  <br>
              </tt></font><br>
            <font size="+1"><tt><font size="+1"><tt>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.<br>
                    <br>
                  </tt></font>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.) 
                <br>
                <br>
                (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.)<br>
                <br>
                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.)  <br>
                <br>
                <br>
              </tt></font> </div>
        </blockquote>
      </div>
    </blockquote>
    <br>
  </body>
</html>