<div dir="ltr"><div>Dr. Goetz, Thanks for the thoughts. My takeaway is that it is on the back burner waiting on potential triggers like the C# nullability experiment. That it is not being summarily dismissed is encouraging. </div><div><br></div><div>I am content for it to remain on its current trajectory, but I wish to leave a few thoughts.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span style="font-family:monospace;font-size:large">I'll just add that none of this "adds" anything to the language (unlike records, or value types, or pattern matching); it just seeks to streamline the declaration of what the language already supports.  That makes it a pretty weak feature. </span></blockquote><div>To my 'language user' eyes, streamlining switch statement into switch expression was a strong feature despite the fact that it didn't add anything to the language (strictly speaking). I think of streamlined immutable classes in a similar way. I recognize that switch expressions got prioritized the way it did because it unlocked the bigger prize of pattern matching, while "streamlining immutability" doesn't have that big prize except perhaps a subset of thankful devs. But, even in isolation, switch expressions were a strong feature in their own right because of the improved cognition, something that "streamlined immutability" could possibly claim as well.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span style="font-family:monospace;font-size:large">I'd rather spend our efforts on pattern matching and value types.</span></blockquote><div>I think the overwhelming majority would agree:  Value Types > Pattern matching > [Day light] > Streamlining immutability. </div><div><br></div><div>Let me conclude with one aspect that I haven't seen discussed publicly.</div><div><br></div><div>[Shifting bottlenecks] All of the Amber changes are producing strong network effects that are increasing (in fact, have increased) the set of programs for which Java is a very strong choice. In turn, the bottlenecks in producing such programs have also moved. For example, the other day I needed a command line utility to transform java source code (like inlining a class into another, renaming a class and such). I encoded the changes as a small language [example: RenameClass(NewMain, InlineClass(OldMain, Child1, Child2, Child3)) says: Inline the children classes into a parent class called OldMain and then rename it into NewMain] and wrote a quick parser using parser combinator style in Java. It was a pleasant experience except for the aforementioned [Poor Rapid Prototyping Velocity] in my first post - the bottleneck was fiddling with moving fields around and dealing with the verbosity and effort of immutability. Sealed types and pattern matching were relatively effortless.</div><div><br></div><div>A decade ago, I wouldn't even have chosen Java; Visitors make my head spin. A few years ago (and perhaps still), I've seen Go recommended for command line apps, but I couldn't pull off Parser combinator style with Go effortlessly (lack of first class union types). In other words, Java has gone from Heck No --> Plausible --> even Pleasant in the space of a few Amber releases and the bottleneck in producing the program correspondingly moved from "Visitors" to "Second class Immutability". I know this is just one example, but it is a recurring theme in my practice.</div><div><br></div><div>Like I said before, I am content for things to remain on their current trajectory - I trust the language designers' judgment calls - but I hope this anecdote helps in some little way.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jan 19, 2024 at 12:32 AM Brian Goetz <<a href="mailto:brian.goetz@oracle.com">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"><u></u>

  
  <div>
    <font size="4" face="monospace">I'll just add that none of this
      "adds" anything to the language (unlike records, or value types,
      or pattern matching); it just seeks to streamline the declaration
      of what the language already supports.  That makes it a pretty
      weak feature.  <br>
      <br>
      People have argued in the past for having explicit versions of
      everything that is currently implicit (if you don't say "static"
      you get an instance method/field; if you don't say
      public/private/protected you get a package-private member).  For
      most of these, there's no way to explicitly say "instance" or
      "package-private".  <br>
      <br>
      We could of course do this; we even reserved the `non-` keyword
      naming convention to reduce the bikeshed painting over what to
      call them.  But we never did any of these, because: we don't
      really think anyone is going to use them.  No one wants to say:<br>
      <br>
         package-private class Foo { <br>
             non-static non-final package-private int x;<br>
             ...<br>
         }<br>
      <br>
      So such features are often just to satisfy an abstract sense of
      completion, which is to say, mostly useless.  (And to add insult
      to injury, the bikeshed quotient of such features is very high.) 
      <br>
      <br>
      I'd rather spend our efforts on pattern matching and value types.<br>
      <br>
    </font><br>
    <div>On 1/18/2024 1:43 PM, Red IO wrote:<br>
    </div>
    <blockquote type="cite">
      
      <div dir="auto">One idea could be to make the class declaration
        special. In well structured classes all fields should live at
        the top so having a class modifier like "immutable" would be
        rather obvious even with lots of fields. Also rather a field
        declared at line 20 and used in line 650 is mutable already
        requires scrolling to the top. 
        <div dir="auto">
          <div dir="auto"><br>
          </div>
          <div dir="auto">On that note the editor/ide is a more often
            used indicator for mutablity of fields by having color or
            styling differences in the variable name. (I know relying on
            tooling to make things clear is not preferable but it's
            kinda already this way)</div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">An example class would look similar to this :</div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">public immutable class Test {</div>
          <div dir="auto">private int field1;</div>
          <div dir="auto">private int field2;</div>
          <div dir="auto">private int field3;<br>
          </div>
          <div dir="auto">private int field4;<br>
          </div>
          <div dir="auto">private int field5;<br>
          </div>
          <div dir="auto">private int field6;</div>
          <div dir="auto">private int field7;</div>
          <div dir="auto">private int field8;</div>
          <div dir="auto">private mutable int field9;</div>
          <div dir="auto">private mutable int field10;</div>
          <div dir="auto">}</div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">Rather to combine default final and default
            private is another discussion. </div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">A counter argument would be that allowing for
            any combination of defaults would result in a keyword
            explosion:</div>
          <div dir="auto">immutable </div>
          <div dir="auto">mutable </div>
          <div dir="auto">closed (wip to make a class private default) </div>
          <div dir="auto">package-private</div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">Just to allow inverting the defaults. </div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">Also c# already has this for immutable fields.
            They have the readonly keyword which is equivalent to final
            on fields in java but it also works on the class making
            every field readonly. The problem with that approach in java
            is that we already used final on classes to block
            inheritance.</div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">Maybe we could instead drop the inversion
            (package-private and mutable) and make it a 1 way decision
            like in records. But then the question would be why not just
            use a record. </div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">That are my thoughts on this topic. As one
            might have heard out I'm undecided on the topic.</div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">Great regards </div>
          <div dir="auto">RedIODev </div>
        </div>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Thu, Jan 18, 2024, 17:56
          Brian Goetz <<a href="mailto:brian.goetz@oracle.com" target="_blank">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="4" face="monospace">So, you provide several
              good arguments here for "Java picked a bad default with
              respect to mutability."  (It is in good company; Java
              picked many bad defaults, such as package visibility
              rather than private, classes being extensible rather than
              closed, etc.)  Let's just take it as given that non-final
              is an imperfect default for fields. <br>
              <br>
              Which brings us to the next question: "now that we realize
              the default is bad, should we change it?"  This is a much
              harder question, because it involves the reality of 10M
              developers and billions of lines of code.  <br>
              <br>
              One bit of prior art here that might be relevant (and the
              experiment is still playing out) is C#'s flipping of the
              nullability default on a per-module basis (with injecting
              checking at the boundaries.)  This was a bold experiment
              and we are interested in seeing the results.<br>
              <br>
              The problem with trying to fix the mistakes of the past is
              that in most cases, you are just creating a fork and
              forcing users to deal with both branches.  If we had a
              directive:<br>
              <br>
                  class X { <br>
                      #pragma default-final<br>
              <br>
                      ...<br>
                  }<br>
              <br>
              then now users have to keep track (possibly on a per-file
              basis) of where "int x" means final or mutable.  This is
              adding cognitive load to all users, since almost no Java
              developer has the luxury of controlling 100% of the code
              they deal with.  <br>
              <br>
              <blockquote type="cite">
                <div>A one line distillation of the above is perhaps:
                  "Immutability is common enough to consider a fast path
                  at source level; the current slow path has negative
                  consequences for cognition and devx."</div>
              </blockquote>
              <br>
              Valid, but what this misses is: "having to constantly
              reason about whether line #656 of Moo.java is on the fast
              path or the slow path has even higher cognitive load."  <br>
              <br>
            </font><br>
            <div>On 1/17/2024 10:20 PM, Subra V wrote:<br>
            </div>
            <blockquote type="cite">
              <div dir="ltr">Hello Project Amber team, 
                <div><br>
                </div>
                <div>What are the current thoughts on providing source
                  level mechanisms for opting-in to mutability rather
                  than the current opt-out? For example, a notion of
                  immutable class (not a record) can obviate specifying
                  "private final" for fields. Opt-in mutability would
                  perhaps also jive with two recent themes in language
                  evolution: 1. Functional style 2. More cognition, less
                  ceremony (switch statement, pattern matching to name a
                  few). </div>
                <div><br>
                </div>
                <div>If there's prior relevant material, I'd
                  appreciate a pointer; Dr. Google hasn't uncovered
                  anything of note.
                  <div><br>
                  </div>
                  <div>I realize that this question has red flags of
                    "proposing a solution" to "my specific problem". So,
                    let me clarify that (1) I only write because I
                    believe there's a reasonable chance that opt-in
                    mutability is of fairly broad interest. (2) I am not
                    proposing obviating the need for 'private final' as
                    a solution; instead, it is meant to be analogous to
                    saying 'I want String interpolation', a 'solution'
                    from which language designers carefully teased apart
                    a general problem and solved it in the form of
                    String Templates.
                    <div>---</div>
                    <div><br>
                    </div>
                    <div>I am certain language designers are aware of
                      this (and plenty more), but in the interest of
                      intellectual honesty, let me attempt to articulate
                      problems with default-mutability from my
                      default-immutable practice.</div>
                    <div><br>
                    </div>
                    <div>1. [Immutable style feels second class] Java
                      has moved in a functional direction much to my
                      (and most practitioner's?) pleasure. For
                      the subset of folks who buy into this direction,
                      Immutable classes are natural. Yet, they
                      feel second class in that (1) notions of "private
                      final" aren't relevant yet pollute (2) It requires
                      extra work [making all fields final, binding them
                      in constructor] compared to the default case of
                      mutability</div>
                    <div><br>
                    </div>
                    <div>2. [Cognitive Cost of Ceremony] For non-record
                      Immutable classes, I have to (1) Write 'private
                      final X' and then add a constructor param and set
                      `this.X = X` in the constructor. (2) Read and
                      verify `private final` on every field to know that
                      the class is immutable. Even though IDEs help, it
                      breaks the flow of thought both when reading and
                      writing</div>
                    <div><br>
                    </div>
                    <div>3. [Poor Prototyping Velocity] I often find the
                      ceremony especially frustrating in early phases of
                      design, especially when using immutable classes.
                      Imagine I have 20 concepts/fields and I am
                      attempting to organize them. A common occurrence
                      is to realize 'ohh this field/method logically
                      belongs to that other class; let me move it there'
                      but it is a pretty big chore to do so (even with
                      Intellij) given that immutability takes extra work
                      to achieve. Such moves also come with further
                      transitive ripple effects. All the busy work
                      perhaps accounts for upwards of 30% of the initial
                      few hours/days of design and more importantly,
                      constantly interrupts thoughts. For contrast, if I
                      just make every field public during the initial
                      period, it'd probably be a better experience, but
                      then I need a magic wand to make them all
                      immutable after the design settles down.</div>
                    <div><br>
                    </div>
                    <div>A one line distillation of the above is
                      perhaps: "Immutability is common enough to
                      consider a fast path at source level; the current
                      slow path has negative consequences for cognition
                      and devx."</div>
                    <div><br>
                    </div>
                    <div>Appreciate thoughts.</div>
                    <div><br>
                    </div>
                    <div>Thank you,</div>
                    <div>Subrahmanyam</div>
                    <div><br>
                    </div>
                  </div>
                </div>
              </div>
            </blockquote>
            <br>
          </div>
        </blockquote>
      </div>
    </blockquote>
    <br>
  </div>

</blockquote></div></div>