Records: construction and validation

Kevin Bourrillion kevinb at google.com
Mon Mar 12 18:25:29 UTC 2018


On Mon, Mar 12, 2018 at 10:48 AM, Brian Goetz <brian.goetz at oracle.com>
wrote:

Historically, this() or super() must be first in a constructor. This
> restriction was never popular, and perceived as arbitrary.
>

It is *very very occasionally* annoying. Do we have enough motivation to
change it? Are they any circumstances today in which I have to worry that
`this` might be unassigned, or would that be new? If I reviewed the code
above, I would move the `super` to the top anyway. It's how we've always
done it and there's nothing at all wrong with it, since it's an exception
case. What are the more motivating examples? (OTOH, this is just a tangent
to the main thread.)



> If we put our implicit construction at the beginning, this would be a dead
> assignment to the parameter, after the record was initialized, which is
> almost certainly not what the user meant.  If we put it at the end, this
> would pick up the update.  The former seems pretty error-prone, so the
> latter seems attractive.
>

You've reminded me that this is how we make defensive copies, which I would
call critically important for records, so yes.


However, this runs into another issue, which is: what if we have additional
> fields?  (We might disallow this, but we might not.)


Let's go to Crazy Town for a second... (and I mean it, this could be insane)

Today, field initializers and instance initializers certainly don't have
any constructor parameters in scope, because they apply to *all* constructors.
But for records we've discussed mandating that all constructors must funnel
through the primary one (which I think is good). That means there is really
only one true constructor. Is it insane to say that initializers, then,
only apply to that primary constructor, and ergo we allow that
constructor's parameters to be referenced in initializers?

Consequence 1: you could do

 public record B(int a, int b) {
   int cachedSum = a + b;
 }

Consequence 2: maybe the precondition example doesn't have to be

 public record B(int a, int b) {
   public B {
     if (b < 0) throw...
   }
 }

but simply

 public record B(int a, int b) {
   {
     if (b < 0) throw...
   }
 }

(again, imho, "the right amount of repetition is no repetition")

I like this outcome, but I would imagine that when we pull on the thread of
everything else that follows from a decision like this we probably won't
end up liking it...


-- 
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com


More information about the amber-spec-observers mailing list