Thoughts on opt-in mutability?
Brian Goetz
brian.goetz at oracle.com
Thu Jan 18 19:02:01 UTC 2024
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.
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".
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:
package-private class Foo {
non-static non-final package-private int x;
...
}
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.)
I'd rather spend our efforts on pattern matching and value types.
On 1/18/2024 1:43 PM, Red IO wrote:
> 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.
>
> 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)
>
> An example class would look similar to this :
>
> public immutable class Test {
> private int field1;
> private int field2;
> private int field3;
> private int field4;
> private int field5;
> private int field6;
> private int field7;
> private int field8;
> private mutable int field9;
> private mutable int field10;
> }
>
> Rather to combine default final and default private is another
> discussion.
>
> A counter argument would be that allowing for any combination of
> defaults would result in a keyword explosion:
> immutable
> mutable
> closed (wip to make a class private default)
> package-private
>
> Just to allow inverting the defaults.
>
> 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.
>
> 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.
>
> That are my thoughts on this topic. As one might have heard out I'm
> undecided on the topic.
>
> Great regards
> RedIODev
>
> On Thu, Jan 18, 2024, 17:56 Brian Goetz <brian.goetz at oracle.com> wrote:
>
> 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.
>
> 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.
>
> 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.
>
> 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:
>
> class X {
> #pragma default-final
>
> ...
> }
>
> 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.
>
>> 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."
>
> 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."
>
>
> On 1/17/2024 10:20 PM, Subra V wrote:
>> Hello Project Amber team,
>>
>> 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).
>>
>> If there's prior relevant material, I'd appreciate a pointer; Dr.
>> Google hasn't uncovered anything of note.
>>
>> 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.
>> ---
>>
>> 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.
>>
>> 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
>>
>> 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
>>
>> 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.
>>
>> 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."
>>
>> Appreciate thoughts.
>>
>> Thank you,
>> Subrahmanyam
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20240118/7b931076/attachment-0001.htm>
More information about the amber-dev
mailing list