3 Questions about unsigned numeric primitives and Valhalla

In 2015 @sjrd and @densh drafted a SIP for the addition of 4 “primitive” types to the standart library for representing unsigned integers: UByte, UShort , UInt and ULong.
However, based on the following quoted requirement, the SIP was rejected because the performance of unsigned AnyVals was inferior to native built-in signed JVM primitives.

Since they will inevitably be “branded” as primitive data types, unsigned integer types should be as efficient as signed integer types.

Despite it was rejected i have some questions about some SIP quotes but in the context of Valhalla language model. Answer if you want.

Topics:

Scala has custom-made AnyVal s and other Object-Oriented abstractions on top of primitive types that can allow for additional, zero-overhead “primitive” types

  1. Is Valhalla project trying to achieve something like Scala´s AnyVal (inlined classes with zero overhead), if that is the case does Scala benefits at all?

Java cannot decently add new primitive types for compatibility reasons

  1. Valhalla also suffers from Boxing/Unboxing of primitives, does that make the quote above still stand true?
  2. Does the JEP 402: Classes for the Basic Primitives (Preview) improves it at all?

arrays of unsigned integer types will suffer from the same performance penalty as arrays of user-defined AnyVal s, because the elements will be boxed.

  1. Is there any hope for this ever to be addressed at the JVM level?

Pertinent references:
JEP draft: Value Objects (Preview)
JEP 402: Classes for the Basic Primitives (Preview)
JEP 401: Primitive Classes (Preview)

1 Like

So apologies if I’ve misunderstood the SIP’s, but for myself the most helpful thing would be an unsigned Int that was a subset of Int. Again just speaking for myself the next most useful thing would be a non negative floating point number that was a subset of Double. it really is a bit odd that here we are in 2022 and still no Natural number in the type system. A natural number type that can just be widened to an Int when required.

What would also be helpful is if Avoid bridge clashes… could be fixed. This. at least for me causes problems in Scala.js on Scala 3, but not JVM or Native. I get round it by stripping the AnyVal from the src file for Js. This is unfortunate because its actually in Scala.js where AnyVals can be most needed given the reduced resources of the browser and the less smart translation of high level code into its final compilation.

2 Likes
  1. Scala’s AnyVal desugars to statics calls with the value as just another argument in most cases. AnyVal is limited to only wrapping a single value. Meanwhile from what I understand, Valhalla aims to alter the JVM to truly support something more lightweight than an object. These new types are not limited to just a single value. The new valhalla types is not just a trick with static methods.

  2. As I see it, if we truly do get what we want from Valhalla, then you can make unsigned data types as efficient as the primitives we currently have. They will box in all the cases where primitives will box.

  3. You can view JEP 402 as declaring int and Integer to be basically the same from what I understand. In some ways it’s quite similar to how Int is currently defined in the Scala library. It’s just another AnyVal class given a bit of an special treatment by the compiler. Java will do something similar in JEP 402.

  4. Valhalla is an attempt at addressing this at the JVM level

2 Likes

To check out Java’s Valhalla project in general, go here:
https://openjdk.java.net/projects/valhalla/

And to specifically check out how they are super-charging Java’s primitives (which is what is required to get to performant unsigned integer types), go here:
https://openjdk.java.net/jeps/169

2 Likes

thanks @RichType @Katrix and @chaotic3quilibrium, will try to respond you, this fragment from the JEP 401: Primitive Classes (Preview) i found useful and highlighted some pertinent parts.

Primitive classes give developers the capability to define new primitive types that aren’t subject to these limitations. Programs can make use of class features without giving up any of the performance benefits of primitives.

Applications of developer-declared primitives include:

  • Numbers of varieties not supported by the basic primitives, such as unsigned bytes, 128-bit integers, and half-precision floats;
  • Points, complex numbers, colors, vectors, and other multi-dimensional numerics;
  • Numbers with units—sizes, rates of change, currency, etc.;
  • Bitmasks and other compressed encodings of data;
  • Map entries and other data structure internals;
  • Data-carrying tuples and multiple returns;
  • Aggregations of other primitive types, potentially multiple layers deep

it’s odd to get an integer : { ...,-3-2-1,0,1,2,3,... } from String.length() and array.length when the correct API representation are whole numbers, {0,1,2,4...}
How cumbersome it is that Scala’s numeric type system, the most fundamental type system, is stuck and limited by an initial primitive specification of the runtime?

I really hope, another question may be, if Valhalla really delivers developer-declared primitives with the same performance as the built-in ones, then, should Scala get its own unsigned integers or wait for java to add them to the standard library?

1 Like

I echo @RichType’s observation that its 2022, we don’t have natural numbers out of the box, and that’s frustrating. Personally, I’d trade a lot of the Scala 3 featureset for a built-in natural number refinement. It would close so many opportunities for bugs and make types more expressive.

Are we limited by the JVM here? Couldn’t we distinguish between richer refined compile-time types, vs the underyling runtime type. For example, a type for an “Int between 0 and 10”, that erases to regular Int at runtime. Of course, such richer refined types could not be available for libraries distributed solely as jvm bytecode, since the extra info has been discarded by then. But I guess they would be available for TASTY libs. Personally, I’d grab that tradeoff with both hands.

I think the matter of refined subtypes of the regular primitive types is largely orthognal to Valhalla.

-Ben

4 Likes

it’s curious that Kotlin had a similar proposal, and was approved: unsigned-types · Kotlin/KEEP, started experimental in Kotlin 1.3, now it’s beta and integrated with the compiler, it won’t let a program compile if you try to add negative vaules like -2 to a kotlin.UInt.

Just clarifying, by no means I’m suggesting Scala must follow Kotlin, they were born for different purposes, still I believe they will reach some level of feature convergence over time.

I guess that also responds my question:

as if Java adds their own unsigned primitives to the standard library, Kotlin could map his own to the Java ones

2 Likes

This is actually the goal of some existing libraries like Iron or Refined.

This means this is entirely possible in Scala and it is even easier in Scala 3 with inlines and scala.compiletime. We almost don’t need a single macro to achieve this in 3.x and thanks to opaque types, this is reachable without boxing/unboxing overhead.

3 Likes

Typelevel Spire Unsigned Types somehow do the job for now.

1 Like