Agreed with Brian. With best regards, Tagir Valeev.
On Fri, Jan 10, 2020 at 11:22 PM Brian Goetz <brian.go...@oracle.com> wrote: > > There is a whole category if "ooh, shiny new language construct, this is an > opportunity to slide in some new features." We saw this with lambdas -- "can > you please make the parameters of lambdas implicitly final." The motivation > for such requests is obvious; we wish all parameters could be implicitly > final (perhaps with an opt-out), but we can't turn back the clock, so we > console ourselves with "well, at least I can have _some_ finality.) But this > consolation is often disappointing, because it creates (a) challenges for > migration between existing constructs (anon classes) and the new construct > (lambdas), often in both directions, and (b) requires users to keep track of > complex, history-driven rules for when they can use a feature ("oops, can't > have static fields in inner classes.") These are often a siren song, and are > best avoided. > > Turning to records, an example of a feature we've rejected on the basis of > this siren song: Named parameter invocation (`new Point(x: 1, y: 2)`.) Yes, > parameter names are part of the API, so this becomes easier for records than > constructors/statics (which is easier, in turn, than for instance methods.) > Instead, we specified that record component names are always reified through > reflection, so that if/when we ever get to a more general story for named > invocation, records will be ready. > > While the user burden is less in this case, compiling `new R(...)` to a > factory invocation feels like pushing on the wrong end of the "constructor > rehabilitation" lever, because doing so will create binary compatibility > trouble for records that want to migrate back to classes. (Like with enums, > this is not 100% compatible, because of the supertype (Enum/Record), but like > with enums, it is not uncommon to hit the wall and want to refactor back to > classes. Let's not make this harder.) > > So my vote is #0. But, if we have a story for moving _all_ classes towards > factory construction, then we should make sure records play well. I don't > think we have to do anything now for which we'd regret inaction, because > whatever problem we have with legacy records, we'll already have with every > class ever written. > > > > > On 1/10/2020 1:36 AM, John Rose wrote: > > Another bit of translation strategy: What does “new R(a,b,c)” compile > to, at the bytecode level? At some point we will cut over to factory methods, > for at least some types (inlines). Should be pre-empt this trend for records, > and mandate that records are *always* created by factory methods? > > The benefit is that records can be evolved to inline types without > recompiling their *clients*. The risk is that (if we don’t take this > option) that we will have records which are constrained to be identity] > types *until all clients are recompiled*. (No I don’t believe that you > can translate “new;dup;invokespecial<init>” into “invokestatic”. > Sorry, that's a pipe dream.) This seems sad, given that records are > partially inspired by value types. > > (From my 2012 blog on value types: “A value type is immutable… The > equals and hashCode operations are strictly component-wise.” Kind > of like a record. Meanwhile, inlines in Valhalla give component-wise > meaning to acmp not equals and identityHashCode not hashCode.) > > I see three options regarding factories (apart from the above pipe dream): > > 0. Do nothing. Records are just abbreviated classes. Whatever works > or doesn’t for evolving general identity classes to inline classes works > or doesn’t for records. No special benefit, in this vein, to declaring > something a record. > > 1. Define a factory, on top of today’s JVM. Records use a hidden API, > desugaring “new R(a,b)” to a static “R.$make$(a,b)”. > > 2. Define a factory, anticipating Valhalla, using a JVM-defined entry point. > The expression “new R(a,b)” compiles to “invokestatic R.<init>(int,int)R”, > preceded by a push of a and b. This requires a (relatively shallow) change > to the JVM to double down on the name “<init>” as the factory behind a > constructor. > > The advantage of 2 is that, if we correctly predict that “<init>” is the > claimed > factory method for value types, then records can be evolved to inlines out > of the box. The advantage of 1 is that we don’t need to make that prediction. > > There’s also this: > > 3. Do 1. but when 2. becomes an option create an auto-bridge from “$make$” > to “<init>”. New code doesn’t need the bridge because it compiles to call > “<init>” out of the box. > > Here’s a gut check for this group: Are we confident enough with Valhalla > that we can settled on “invokestatic <init>” as the new dance for creating > an instance that may or may not be an inline? > > — John > >