> From: "Brian Goetz" <brian.go...@oracle.com> > To: "amber-spec-experts" <amber-spec-experts@openjdk.java.net> > Sent: Friday, June 10, 2022 2:44:51 PM > Subject: "With" for records
> In > [ > https://github.com/openjdk/amber-docs/blob/master/eg-drafts/reconstruction-records-and-classes.md > | > https://github.com/openjdk/amber-docs/blob/master/eg-drafts/reconstruction-records-and-classes.md > ] > we explore a generalized mechanism for `with` expressions, such as: > Point shadowPos = shape.position() with { x = 0 } > The document evaluates a general mechanism involving matched pairs of > constructors (or factories) and deconstruction patterns, which is still > several > steps out, but we can take this step now with records, because records have > all > the characteristics (significant names, canonical ctor and dtor) that are > needed. The main reason we might wait is if there are uncertainties in the > broader target. > Our C# friends have already gone here, in a way that fits into C#, using > properties (which makes sense, as their language is built on that): > object with { property-assignments } > The C# interpretation is that the RHS of this expression is a sort of "DSL", > which permits property assignment but nothing else. This is cute, but I think > we can do better. > In our version, the RHS is an arbitrary block of Java code; you can use loops, > assignments, exceptions, etc. The only thing that makes it "special" is that > that the components of the operand are lifted into mutable locals on the RHS. > So inside the RHS when the operand is a Point, there are fresh mutable locals > `x` and `y` which are initialized with the X and Y values of the operand. > Their > values are committed at the end of the block using the canonical constructor. GREAT ! I've several questions, that we will have to answer later. The block is also special because there is an implicit return at the end ? so i believe "return" should be disallowed inside the block, right ? Does the lifting that appears at the beginning of the block call all accessors ? or the compiler try to be clever and not call an accessor when its value is not needed. For example, in point with { y = 3; } calling point.y() is useless, or is it something the JIT will take care of ? Do we allow "with" followed by an empty block ? As a way to clone a record ? About the declaration of local variables, in Java, there is no hiding/shadowing between local variables, so a code like this is rejected ? Or do we introduce a special rule for the hiding of implicit variables ? int x = Integer.parseInt(); ... foo(point with { y = 3; }); // x is declared twice because there is an implicit int x = point.x(); > This should remind people of the *compact constructor* in a record; the body > is > allowed to freely mutate the special variables (who also don't have obvious > declarations), and their terminal values determine the state of the record. > Just as we were able to do record patterns without having full-blown > deconstructors, we can do with expressions on records as well, because (a) we > still have a canonical ctor, (b) we have accessors, and (c) we know the names > of the components. > Obviously when we get value types, we'll want classes to be able to expose (or > not) such a mechanism (both for internal or external use). yes, Complex.default with { re = 3; im = 4; } seems a great fit for value classes. RĂ©mi