Fwd: JDK 14 Preview Records constructors

Johannes Kuhn info at j-kuhn.de
Tue Jun 9 21:08:43 UTC 2020


Thanks for sharing this.

Highlighted a few things I was not aware of as EJC doesn't check for that.
Filled a bug on the eclipse bug tracker[1].

Playing around with that, I found the following "inconsistency":

     public record Foo(int bar) {
         public Foo() {
             super();
             this.bar = 0;
         }
     }

Fails to compile with "constructor is not canonical, so its first 
statement must invoke another constructor".
I wonder what "super();" is? (According to JLS § 8.8.7.1, it's an 
Explicit Constructor Invocation)

Should probably display a different, more specific error message.
Like "constructor is not canonical, so its first statement must invoke 
another constructor of this record".

(Also, it *might* be useful to have a non-public non-canonical 
constructor that doesn't copy an array. But that's a different discussion.)

- Johannes

[1]: https://bugs.eclipse.org/bugs/show_bug.cgi?id=564146

On 09-Jun-20 21:24, Brian Goetz wrote:
> Received on the spec-comments list.
>
>
>
>
> -------- Forwarded Message --------
> Subject:     JDK 14 Preview Records constructors
> Date:     Tue, 9 Jun 2020 00:00:09 +0200
> From:     interlink.sg7 at gmail.com
> To:     amber-spec-comments at openjdk.java.net
> CC:     james.laskey at oracle.com
>
>
>
> Hello,
>
>
> I'm not sure if this is the correct place to give feedback on Records, I
> apologise if it isn't.
>
> I recently played around with the preview Records features from JDK 14 
> a bit
> (mainly JShell).
>
> There's a few things I'm at odds with and I'd like to highlight only 
> those
> in this post and I hope you can give me some insights that led to certain
> restrictions
>
> and where I'm misunderstanding some things maybe.
>
> My main issue is mostly how different constructors work in Records 
> compared
> to Classes and the resulting inconsistency.
>
> The following examples are a bit constructed and don't make logical 
> sense,
> but I hope my idea gets across :)
>
>
> 1. Canonical constructor can not call <custom constructor>, e.g.
> delegating to spezialized normalizing constructor with a constant default
> value:
>
>
> record Example1(int x) {
>
> public Example1(int x) {
>
> this(x, 0); // compile error
>
> }
>
>
> public Example1(int x, int defaultX) {
>
> this.x = x >= 0 ? x : Math.max(defaultX, 0);
>
> }
>
> }
>
>
> 2. <Custom constructors> must call canonical constructor, e.g. support
> multiple input types or when you can't reuse canonical constructor:
>
>
> record Example2(UUID uuid) {
>
> public Example2 {
>
> uuid = UUID.nameUUIDFromBytes(uuid.toString().getBytes());
>
> }
>
>
> public Example2() { // compile error
>
> this.uuid = UUID.randomUUID();
>
> }
>
>
> public Example2(String uuid) { // compile error
>
> this.uuid = UUID.fromString(uuid);
>
> }
>
> }
>
>
>
> 3. Canonical Constructor must be public, so it's not possible to have
> only static factories or it forces normalization outside of Records
> constructor:
>
>
> record Example3(UUID uuid) {
>
>
> private Example3 { // compile error
>
> }
>
>
> public Example3(String uuid) { // compile error
>
> String uuidNormalized = StringUtils.toLowerCase(uuid);
>
> try {
>
> this.uuid = UUID.fromString(uuidNormalized);
>
> catch(IllegalArgumentException e) {
>
> this.uuid = null;
>
> }
>
> }
>
>
> public static Example3 fromString(String uuid) {
>
> return new Example3(uuid);
>
> }
>
> }
>
>
> 4. Assignment without <this> in canonical constructor is very
> unnatural, e.g. use of <this> in Classes is very logical when you would
> otherwise reassign the parameter
>
> In Records however :
>
>
> record Example4(int x) {
>
> public Example4 {
>
> x = x + 1; // assigns field, but looks nothing <like Java>
>
> }
>
>
> public Example4(int x, int plus) {
>
> this(x); // hrrng
>
> x = x + plus; // reassign parameter
>
> }
>
> }
>
>
> record Example5(int x) {
>
> public Example5 {
>
> this.x = x + 1; // read it might be forbidden in the future :(
>
> }
>
>
> public Example5(int x, int plus) {
>
> this(x); // hrrng
>
> this.x = x + plus; // is compile error
>
> }
>
> }
>
>
> 5. It's not possible to define the canonical constructor with the exact
> same parameter list as the Record definition has.
>
> The simple canonical constructor without parameters should just be an 
> alias
> for that in my opinion.
>
> For symmetrie reasons (with other constructors) and clearity I would 
> like to
> define the canonical constructor with the required parameters.
>
>
> I think most of those discrepancies (especially 4) and 5)) come from the
> desire to be less verbose and the definition of records (state and only
> state) and still have some <convenience> like Classes.
>
> However the limitations and half-way implicit <magic> makes it really
> confusing. I think it would have been better to keep constructors 
> similar to
> the ones from Classes if explicitly defined.
>
> I mean if the user is already going to manually write constructors (which
> should be a special case) the few lines of assignments don't matter 
> compared
> to the rethinking it needs each time
>
> with implicits and the restrictions that follow.
>
>
> What are your thoughts?
>
>
> Kind regards,
>
>
> Simon
>
>
>
>



More information about the amber-dev mailing list