So the default value may a valid value or may be an invalid value,
if it's an invalid value it should be the author of the class that say that
because in Java we prefer declaration site to use site.
One way is to try to teach the VM how to do the conversions, i want to explore
another way where we try to solve that issue at the language level, to avoid to
have a more complex VM.
A default value which is invalid should behave like null, i.e. calling any
methods on the default value should result in an exception.
Doing that at the language level means adding a check before calling any
instance methods and before accessing any instance fields.
So there are two parts to solve,
1/ how to specify the check, is it just this == Inline.default or is it
whatever the user want (or something in the middle, like a field check)
2/ how to execute that check when accessing a field or a method ?
Let explore the solution that offers the maximum freedom for the author of the
inline class, i.e. for 1/, the check is user defined.
For that we can introduce a new kind of initializer, like the static block,
let's call it the invariant block
inline class Foo {
private final Object o;
invariant {
if (o == null) {
throw new InvalidFooException();
}
}
}
this invariant block is translated into a method (that has the name
see later why) and is called each time a method or a field is accessed.
For 2/, we can either change the spec of the VM so the invariant block is
called automatically by the VM or we can use invokedynamic.
invokedynamic has the advantage of not requiring more VM support at the expanse
of the bootstrap issue.
The main issue with invokedynamic is that it's not a backward compatible change
because it requires to change the call sites.
So we can lessen the requirement like this, requiring only the call to
when accessing an instance method because
we suppose that people will not be foolish enough to declare the fields public,
In that case, there is no need for using invokedynamic because a call to the
invariant method can be inserted by the compiler at the beginning of any
instance method.
This solution also has the advantage of lowering the cost at runtime compared
to using invokedynamic.
In term of performance, i believe the language spec should say that the
invariant block has to be idempotent.
Because in that case, the VM is free to not execute several calls to the
method once one is executed on a specific instance
(like the JITs do nullchecks collapsing currently).
To summarize, i believe we should allow more value based classes to be
retrofitted as inline class by adding the concept of invariant block to the
Java language spec.
An invariant block being a simple idempotent method called at the beginning of
every instance methods.
Rémi
- Mail original -
> De: "daniel smith"
> À: "valhalla-spec-experts"
> Envoyé: Vendredi 10 Juillet 2020 20:23:25
> Objet: Revisiting default values
> Brian pointed out that my list of candidate inline classes in the Identity
> Warnings JEP (JDK-8249100) includes a number of classes that, despite being
> "value-based classes" and disavowing their identity, might not end up as
> inline
> classes. The problem? Default values.
>
> This might be a good time to revisit the open design issues surrounding
> default
> values and see if we can make some progress.
>
> Background/status quo: every inline class has a default instance, which
> provides
> the initial value of fields and array components that have the inline type
> (e.g., in 'new Point[10]'). It's also the prototype instance used to create
> all
> other instances (start with 'vdefault', then apply 'withfield' as needed). The
> default value is, by fiat, the class instance produced by setting all fields
> to
> *their* default values. Often, but not always, this means field/array
> initialization amounts to setting all the bits to 0. Importantly, no user code
> is involved in creating a default instance.
>
> Real code is always useful for grounding design discussions, so let's start
> there. Among the classes I listed as inline class candidates, we can put them
> in three buckets:
>
> Bucket #1: Have a reasonable default, as declared.
> - wrapper classes (the primitive zeros)
> - Optional & friends (empty)
> - From java.time: Instant (start of 1970-01-01), LocalTime (midnight),
> Duration
> (0s), Period (0d), Year (1 BC, if that's acceptable)
>
> Bucket #2: Could have a reasonable default after re-interpreting fields.
> - From java.time: LocalDate, YearMonth, MonthDay, LocalDateTime,
> ZonedDateTime,
> OffsetTime, OffsetDateTime, ZoneOffset, ZoneRegion, MinguoDate, HijrahDate,
> JapaneseDate, ThaiBuddhistDate (months and days should be nonzero; null
> Strings, ZoneIds, HijrahChronologies, and JapaneseEras require special
> handling)
> - ListN, SetN, MapN (null array interpreted as empty)
>
> Bucket #3: No good default.
> - Runtime.Version