Derived record creation and Data Oriented programming

Brian Goetz brian.goetz at oracle.com
Tue Apr 30 16:22:01 UTC 2024


>
>     So let's back up: what problem are we trying to solve here?
>
>
> The problem is that the syntax of "with" does not show that with 
> depends on the deconstructor and the constructor of the record, so the 
> behavior in case of separate compilation is not clear.

I think the lack of clarity you are concerned about is that the names of 
the components are being used as a new kind of API, where we lift API 
elements to variables, and you're concerned that those names are "weakly 
coupled" between declaration and client?  Is this right?

> I see several ways to fix that:
> - restrict the uses of "with" to the package/module containing the 
> record (as we have done with sealed types),

With this restriction, I think the feature is not really useful enough 
to justify.  Plus this will annoy people.

> - allows a syntax variation where the components of the record are listed,

So, this would be like a C++ lambda:

     // don't take the syntax seriously, purely meant to evoke C++ 
lambda syntax
     p = p with [x,y]{ x = 3; }

and then the [x,y] would be used for the ctor/dtor lookup?

> - link the canonical deconstructor/constructor of the record at 
> runtime (which can be simpler if the local variable declared outside 
> of the block are captured (like the variables inside a "when" 
> expression)).

Not sure what you mean here, but it probably doesn't scale to classes?

> and maybe there are other solutions ?
>
> Rémi
>
>
>     On 4/30/2024 9:22 AM, Remi Forax wrote:
>
>         Hello,
>         they have been several messages on amber-dev about the compatibility of the derived record creation.
>
>         I think part of the issue reported is that with the proposed syntax, the call to the desconstructor and the canonical constructor is implicit.
>
>         Let's take an example
>
>            record Point(int x, int y) {}
>
>            var point = new Point(2, 3);
>
>
>         In fact,
>            var point2 = point with { x = y; };
>
>         is a shortcut for:
>
>            var point2 = point with {
>              Point(int x, int y) = this;  // i.e. int x = this.x(); int y = this.y();
>              x = y;
>              yield new Point(x, y);
>            };
>
>         One problem with the current syntax is that because the call to the [de]constructors is implicit. I think we shoud allow users to write the implicit calls if they want.
>
>         I wonder if
>         - we should not allow yield to be used so the compiler adds yield automatically only if there is no yield ?
>         - we should in the future when deconstructors are introduced, allow users to call a deconstructor explicitly and only provide one if not explicitly written ?
>
>         Being able to write the calls explicitly is important because it's a way to detect if the record has been modified without the proper constructor/destructor has been written to be backward compatible (Like in a switch, a record pattern detects when a record component is added while a type pattern does not).
>
>         Being able to call a the deconstructor explicitly also have the advantage to avoid to declare a variable/calls the accessor if not needed.
>         By example
>            var point2 = point with {
>              Point(_, var y) = this;
>              x = y;
>            };
>
>         regards,
>         Rémi
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20240430/52156c67/attachment.htm>


More information about the amber-spec-observers mailing list