Value types design decisions
Brian Goetz
brian.goetz at oracle.com
Sat Jan 20 15:24:33 UTC 2024
(1) and (2) are really the same question, and reflect a misunderstanding
of what an implicit constructor is. I think what you are hoping for is
that you would be able to select the _default value_ used to initialize
freshly allocated memory, rather than the VM-selected all-zero. This is
not what an implicit constructor means, because, unfortunately, this is
not consistent with the physics of the problem; the VM initializes
memory with a wide roller, not a fine brush. While I can certainly
sympathize with the _desire_ to have this, it's not really practical.
So what *is* an implicit constructor? First, let's understand what
happens when you say `new Foo(3)`. An uninitialized object is allocated
and zeroed out, and then the Foo(int) constructor is run to initialize
its state. The runtime takes some care (though badly written
constructors can undermine this) to ensure that the object is not
exposed to "regular code" before initialization has completed.
An implicit constructor is a statement by the class author that "calling
the constructor is optional"; in other words, that the uninintialized
object allocated by the JVM is a perfectly valid instance, and a good
default value. (Many important classes fit this description, such as
nearly all numerics, and some library classes like Duration and
Optional.) In turn, this means it is safe for the VM to expose an
otherwise-uninitialized object, which in turn, enables richer flattening
optimizations. Since it is a statement that "construction is optional",
having a body would make no sense, since the constructor might never be
called. And since construction is optional, the "make me one without
construction" is an inherently public operation (to the extent that the
class itself is public). You can't restrict it without restricting
things like "no one can declare a field of type Foo".
We went back and forth between representing this as a special
constructor, and representing this as a modifier on the class (e.g.,
`implicitly-constructible`.) Each had pros and cons (but this isn't the
time or place to discuss syntax choices). I suspect that you (though
not everyone) would have found the "class modifier" route to be more
evocative of what is really going on, though had we gone the other way,
there would be different complaints.
Of course, you _can_ omit the implicit constructor, and write an
ordinary no-arg constructor that lets you set your preferred "default"
values. But the cost of that might be not getting all the memory
flattening you might hope for. Valhalla, unlike some other projects, is
more constrained by the physics of object layout and allocation, and as
such, exposes some difficult tradeoffs. (Previously, the VM made these
tradeoffs for you, often conservatively.)
To your third question, yes, this syntax is controversial. (The
alternatives are not necessarily better, and everything you propose has
already been discussed. As always, we may reconsider this after
gathering more experience.)
(As an aside, I would suggest that when confronted with something that
seems confusing or surprising, to strive to fully understand before
reaching for language like "make the same mistake again.")
Cheers,
-Brian
On 1/20/2024 2:00 AM, Smith Wilson wrote:
> Hello Valhalla community,
> I have reviewed the latest documents on the project and have some
> concerns about current design decisions.
>
> 1) Implicit constructor cannot have body.
> While I understand why we need implicit ctor and why it must have no
> args, I still don't understand why we can't allow users to set default
> values on their own using that ctor instead of implicitly defaulting
> them to (0, false, null). It could solve problems with such classes
> like LocalDate which require more special zeroInstance (1970-1-1) than
> value with pure defaults.
> I believe that even String class could be somehow adopted to be value
> class in future having default null-restricted value of "" with
> (byte[] value) assigned to empty byte array. Non-final fields (hash,
> hashIsZero) could be placed into separate final field (i.e.
> hashHolder) given that it will be forcedly flattened, so there will be
> no overhead.
>
> 2) Implicit constructor must be public.
> We all learned that overextending public apis can lead to problems.
> Great example of this is wrapper classes whose constructors have been
> deprecated long time ago and still causing a lot of problems. So, new
> classes (i.e. Optional) were designed to have static factories
> (Optional#of, Optional#empty), rather than exposing their internal
> constructors. (Moreover, constructor calls use different byte-code
> instructions than method calls, which also can cause byte-code
> incompatibilities in case of future migrations.)
> I don't understand why we are going to make same mistake again and why
> we can't allow implicit constructors to have any kind of visibility
> modifier. So, VM will be able to freely use zeroInstances where
> necessary, while user himself will be able to control use of class
> exposing special apis.
>
> 3) Using interface (LooselyConsistentValue) to express non-atomicness.
> Same story as with Serializable interface. It is considered that using
> marker-interface for such a problem was bad design. Although this was
> justified by the fact that we did not have annotations, it is now
> unclear what makes us to use interfaces again. While it is possible to
> come up with real-life use cases of Serializable where type
> restrictions may be required (some usage of ObjectI/OStream apis), for
> such VM-close features like non-atomicness there is no real need for
> such opportunity. (Moreover, we already have some inconveniences
> because of that. In some cases, type inference of "var" is already
> blowing up from large type unions like Number & Comparable &
> Serializable.)
> So, I believe we should use alternatives like class modifier or
> annotation, rather than polluting the type system for no reason.
>
> Regards,
> Wilson.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-dev/attachments/20240120/0b15a0a2/attachment.htm>
More information about the valhalla-dev
mailing list