Specialized primitive implementations after generics specialization

Nir Lisker nlisker at gmail.com
Thu Sep 2 13:32:20 UTC 2021

Thanks for the replies, this is very interesting and encouraging.

On Tue, Aug 31, 2021 at 5:26 PM Brian Goetz <brian.goetz at oracle.com> wrote:

> We surely would like for all the hand-specifications to retreat to the
> dustbin of past expediences.  For some, we can fairly easily coopt them by
> retroactively giving them supertypes:
>     interface IntPredicate extends Predicate<int> { }
>     interface Predicate<T> extends Function<T, boolean> {
>         boolean apply(T t) { return test(t); }
>     }
> and guiding future usage towards the more general `Function` type.
> For others, like IntStream, we're not going to be able to make IntStream
> extends Stream<int> (try it, you'll run into the fact that the dual of
> covariant overrides is not present) but we can eventually deprecate
> IntStream in favor of Stream<int> (the "cut off the head of the snake"
> strategy.)  As you suggest, this leaves the question of what to do with
> methods that are not total (e.g., sum(), max(), sorted()), but this is
> merely an extension of a more general need to express behavior that is
> conditioned on the properties of a particular type parameter.  Stream is
> not special here; if the elements of a List are "comparable", it would be
> nice if List had a sort() method, etc.
> In Haskell, we'd express this as follows:
>     Ord t => sort :: List t -> List t
> which says roughly "given the precondition that t is orderable, List
> supports a sort operation".  We almost have something like that today:
> generic type bounds.  But we don't yet have the ability to express
> something like:
>     <where T has Comparator<T>>
>     void sort()
> which would constrain the sort() method on List to instantiations where
> the type parameter can provide a witness to ordering.  This requires a lot
> of things to pull off, including the ability to associate behaviors with
> types, not just instances (e.g., something more like type classes), and
> either specialization (so that the witness to `Ord t` can be derived from
> `t`) or something like Scala's implicits to access the witness at runtime,
> etc.
> Rest assured we're exploring these areas as well, since they are essential
> to creating expressive libraries.  (But, let's not discuss it further here;
> let's wait for a more complete story first.)
> On 8/30/2021 10:26 PM, John Rose wrote:
> We expect to upgrade the existing generics so that the
> JVM can access enough information about types to
> perform various customizations.  The details are hazy,
> but we fully expect to be able to supply ad hoc methods
> like sum.  Maybe even ad hoc protocols like Summable,
> if we are lucky.  Hopefully also ad hoc fields, like an
> “Optional::isPresent” field that is elided (typed as “void”
> or some other unit or empty type) when the isPresent
> logic can be derived from the main field of the Optional,
> as today.
> The basic insight here is that, if there is enough runtime
> information to guide the customization of data structures
> (as today’s primitive arrays and fields have layouts
> customized to the primitives), then there is also enough
> runtime information to perform the coordinated task
> of customizing algorithms (think Arrays.sort, on flat
> monomorphic inputs).
> Then, given those two firm requirements, the JVM
> surely also has enough information to drive the creation
> of optional methods, especially if (as we hope) the
> optional methods can be modeled as always-present
> but sometimes-degenerate methods.
> To take your example, List<X>::sum would do what
> you want if X has a “summable” type.  (Where the
> condition of “summability” is encoded by a type bound
> or perhaps a type class; details to be worked out.)
> Meanwhile, if X has some other random type, then
> List::sum would still link but throw a suitable error
> when called.  (The static compiler javac might report
> a static error when it can prove that this is bound to
> happen, for some static type X.)
> This scheme, of degenerate methods and fields, plays
> well with raw types and wildcards, where the decision
> to throw that error would depend on the type of the
> receiver object.
> For our current thought on how to rewire the JVM
> to pass around sufficient information about generics,
> please see the Parametric VM manifesto:
> https://github.com/openjdk/valhalla-docs/blob/main/site/design-notes/parametric-vm/parametric-vm.md
> — John
> On Aug 30, 2021, at 6:45 PM, Nir Lisker <nlisker at gmail.com> <nlisker at gmail.com> wrote:
> Hi,
> I have a question(s) about the need for primitive specialized
> implementations when type parameters will accept primitives.
> Today we need various specializations like IntFunction and IntStream.
> However, the difference between them is that IntStream brings with it
> methods that make sense on int, like sum(), while IntFunction does not.
> Does this mean that some specializations will still be needed, or will
> there be another way of doing it?
> (I'm not advocating to do anything with IntFunction or IntStream, just
> using them as examples.)
> - Nir

More information about the valhalla-dev mailing list