What we have lost ?
forax at univ-mlv.fr
forax at univ-mlv.fr
Wed Sep 7 07:56:55 UTC 2022
----- Original Message -----
> From: "daniel smith" <daniel.smith at oracle.com>
> To: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "valhalla-spec-experts" <valhalla-spec-experts at openjdk.java.net>
> Sent: Wednesday, September 7, 2022 12:08:57 AM
> Subject: Re: What we have lost ?
>> On Sep 6, 2022, at 1:32 AM, Remi Forax <forax at univ-mlv.fr> wrote:
>>
>> What is missing/not supported by the current model is value classes that should
>> not be used by reference,
>> either because it will cause performance issues or because the user will not get
>> the semantics he think he will get.
>
> This is a useful question to explore, so thanks for bringing it up: can we think
> of use cases in which a class should, in the informed opinion of its author,
> always be referred to via its value type? If so, a reference-by-default
> approach is definitely problematic, because one of our starting assumptions was
> that most uses of value classes would be totally fine using a reference type.
>
>> Here is a list of such value types:
>> - unit types, value types like by example Nothing (which mean that a method
>> never returns) with no fields.
>> Because creating a ref on it creates something :)
>
> If you truly mean for such a class to have no instances, that's not something a
> class with a value type can assert—the default instance always exists. I can
> see how it would be nice, for example, to have a type like Void that is also
> non-nullable, but value types are not the feature to accomplish that.
no, such classes have instances but they are empty.
By example, an array of Nothing stores just its length in memory. Accessing a cell return the default value, Nothing.default which is equivalent to new Nothing().
And it can be used in generics too, a HashMap<Integer.val, Nothing> is more or less a set of ints.
>
>> - wrappers/monads that modify the semantics, by example a generic value class
>> Atomic that plays the same role as an AtomicReference, AtomicInteger, etc
>> the problem here is that the default semantics is not the semantics the user
>> want.
>
> Okay, so say we have value class Atomic<T>, and we're in a future where this
> gets specialized. I think you're saying it will be important to say
> 'Atomic.val<Foo>' at all uses rather than 'Atomic<Foo>'. But I'm not clear on
> the argument for why that would be. Can you elaborate?
If Atomic is declared as a ref-by-default value class, Atomic<Foo> behave as a ref an not as a Foo + some atomic magic.
So it is always wrong to use it.
As the author of Atomic, i don't want my users to have a way to shoot themselves into the foot.
Here, Atomic should be flat-by-default and also the ref variant should not exist, so there is no way to misuse the Atomic API.
>
>> - SIMD vectors, if those are nullable, the VM/JIT will insert implicit null
>> checks which are not usually a problem apart in thigh loop like users write
>> with SIMD vectors.
>
> The *storage* should definitely use a value type, so in this sort of application
> we'd encourage value-typed array allocations (and value-typed type arguments
> for wrapping data structures).
>
> In a loop over a flat array, I would expect it to be okay to talk about the
> reference type in source, and have the JIT generate optimal code to work with
> the underlying flat storage, without any allocations or null checks. My sense
> is that we suspect that this can work reliably, but it could use more targeted
> performance testing to confirm.
Sorry for not being clear, i'm more worry about people using IntVector instead of IntVector.val on stack and the VM having to emit a nullcheck inside a loop, by example if there is a call to a method that returns an IntVector is not inlined. For me, the vector API represents operation so a ref-by-default IntVector is a kind of useless, worst it will work but performance will suffer with no simple way to fix that apart taking a look to the generated assembly code.
>
>> - existing value classes in Scala or Kotlin, those are not nullable by default
>> but in the current design, getClass() will happily reflect them with a nullable
>> class making Scala/Kotlin second class citizens of the Java platform.
>
> Is the problem here that Scala/Kotlin will want reference-default interpretation
> of names in Java source? (If so, <shrug>, if you want a good user experience
> with Kotlin types, write Kotlin source.)
>
I don't know the answer to that question but i disagree with your conclusion, interrop with Java, so with the Java ecosystem is important.
> Or is the problem that they will want the reflection API to behave differently,
> making Foo.val.class the "primary" class object, not a secondary one? (If so,
> <shrug> again, the Java reflection API is Java-oriented, interop is not a major
> factor in its design.)
>
> Maybe I'm missing your point on this one?
The problem is that we are forcing the companion class design to other languages than Java.
C# has done the same mistake with their generics being too specific to C# so other languages on the .Net platform all suffer.
Other languages than Java can not makes Foo.val.class their primary class object because the companion class design is bolt into the VM.
Rémi
More information about the valhalla-spec-observers
mailing list