Ideally, records are classes, with restrictions (like enums). And
again, ideally, we find the minimal set of restrictions (e.g., "no
instance fields"), and then we get out of the way.
In the case of records, we have chosen to have a compact way to declare
the _canonical_ constructor. So they're not just classes with
restrictions, but classes with restrictions and small enhancements. But
ultimately, the less we depart from "records are classes", the fewer
special rules the user has to learn.
Therefore, I don't think we should go out of our way to restrict, or
reinvent, instance initializers; I think "legal but rare" is a fine
place for this to be.
On 9/4/2019 5:58 PM, fo...@univ-mlv.fr wrote:
------------------------------------------------------------------------
*De: *"Tagir Valeev" <amae...@gmail.com>
*À: *"Remi Forax" <fo...@univ-mlv.fr>
*Cc: *"Gavin Bierman" <gavin.bier...@oracle.com>,
"amber-spec-experts" <amber-spec-experts@openjdk.java.net>
*Envoyé: *Mercredi 4 Septembre 2019 07:21:48
*Objet: *Re: Draft JLS spec for records
Hello!
Hi !
> I also believe we should make the instance initializer illegal
in record given that a require initializer is a kind a better
instance initializer because it can access local variables.
I don't think so. A compact constructor (or require initializer,
as you propose) could be not the only constructor. An instance
initializer is convenient because it's added to every constructor,
regardless of whether it's compact or not. So the new thing
doesn't supersede the instance initializer and I see no good
reason to explicitly disable it.
I've forgotten that you can have multiple constructors in a record too,
I never liked that a class can have multiple constructors because it
forces you to read the doc to choose between the constructors and i'm
too lazy for that :)
The problem with a record is that if you have multiple constructors,
you may mix classical constructors with the compact one,
like this
record Foo(Object obj, int v) {
public Foo(Object obj) {
this.obj = obj;
this.v = -1;
}
public Foo {
Objects.requireNonNull(obj); // ensure obj is non null
}
}
and i'm not sure that every readers will think seeing this code that
new Foo(null) is allowed,
and it will be worst if instead of a compact constructor syntax we
have an require initializer syntax because as you said an instance
initializer is copied in front of all constructors.
I believe there are two ways to make sure a require initializer is
always executed,
either you specify that the require initializer is copied in all
constructors but if the constructors have different parameters, you
have to restrict the require initializer to see only the common
parameters which seems to magical for me or you require explicit
constructors to delegate to another constructor, so the code above is
not valid because the first constructor doesn't call the canonical one.
The code has to be changed to
record Foo(Object obj, int v) {
public Foo(Object obj) {
this(obj, -1);
}
require {
Objects.requireNonNull(obj); // ensure obj is non null
}
}
regards,
Rémi
With best regards,
Tagir Valeev.
On Tue, Sep 3, 2019 at 7:02 PM <fo...@univ-mlv.fr
<mailto:fo...@univ-mlv.fr>> wrote:
------------------------------------------------------------------------
*De: *"Gavin Bierman" <gavin.bier...@oracle.com
<mailto:gavin.bier...@oracle.com>>
*À: *"Remi Forax" <fo...@univ-mlv.fr
<mailto:fo...@univ-mlv.fr>>
*Cc: *"Brian Goetz" <brian.go...@oracle.com
<mailto:brian.go...@oracle.com>>, "amber-spec-experts"
<amber-spec-experts@openjdk.java.net
<mailto:amber-spec-experts@openjdk.java.net>>
*Envoyé: *Mardi 3 Septembre 2019 12:37:17
*Objet: *Re: Draft JLS spec for records
Thanks Remi.
- a canonical constructor can not have throws clause
(from the text of the section) but the grammar in
8.10.2 the CompactConstructor declaration can have a
throw clause ?
That is just a typo - thanks. The rest I will get back to
you shortly.
humm,
thinking more about the canonical constructor
- does'nt really need a modifier (it's always public if you
believe the current state of the spec or it's the one of the
record anyway)
- doesn't need to declare a type parameter
- doesn't need annotations because you get the one from the record
so it's more like an initializer than a constructor.
Given that i've always find the syntax of the canonical
constructor too close to the one of the real constructor
(depending on the fact that parenthesis are present or not),
i propose a new kind of initializer, the require initializer
(obvisouly it can be another name than "require").
An example of syntax:
record Foo(String s) {
require {
Objects.requireNonNull(s);
}
}
I also believe we should make the instance initializer illegal
in record given that a require initializer is a kind a better
instance initializer because it can access local variables.
An example that should not compile
record Foo(String s) {
require {
System.out.println("am i print first ?");
}
{
System.out.println("am i print first ?");
}
}
Thanks,
Gavin
Rémi