-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Replace runtime.Rich* implicits on primitives by direct extension methods. #23872
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…hods. It has always been weird that the public API of primitive types, enriched by `Predef` depends on the `Rich*` classes, which are in the not-really-public `runtime` package. Moreover, the design of those classes was overabstracted, with consequences on performance (unnecessary boxing) and quality of the API (including methods that do not make sense on some types). To mitigate that, the individual `Rich*` classes redefined some (but not all) of the methods, defeating the abstraction. We solve both issues with a simple solution: define all those methods as simple `extension` methods. We do this directly in the companion objects of the primitive types.
@sjrd you have beaten me to it 😄 |
The problem is that extension methods are not equivalent to implicit classes/definition extensions. Without solving https://contributors.scala-lang.org/t/relaxed-extension-methods-sip-54-are-not-relaxed-enough/6585/1 this change will break everywhere that has methods in the same name in scope. |
I don't see how that problem appears when defining extensions for monomorphic types. You wouldn't redefine another extension of |
@deprecated("isWhole on Byte is always true", "2.12.15") | ||
def isWhole: Boolean = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand why this was done, but it feels weird to say that an extension method was deprecated since 2.12.15 😅
You are right. I thought the implementation used a typeclass approach + extension methods. My mistake. |
* | ||
* @param end The final bound of the range to make. | ||
*/ | ||
def until(end: Byte): NumericRange.Exclusive[Byte] = NumericRange(self, end, 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it is part of the very little subset where everyone agrees on it :). Same goes for to
.
def until(end: Byte): NumericRange.Exclusive[Byte] = NumericRange(self, end, 1) | |
infix def until(end: Byte): NumericRange.Exclusive[Byte] = NumericRange(self, end, 1) |
def max(that: Byte): Byte = java.lang.Math.max(self.toInt, that.toInt).toByte | ||
|
||
/** Returns `this` if `this < that` or `that` otherwise. */ | ||
def min(that: Byte): Byte = java.lang.Math.min(self.toInt, that.toInt).toByte |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(my personal preferences here)
def max(that: Byte): Byte = java.lang.Math.max(self.toInt, that.toInt).toByte | |
/** Returns `this` if `this < that` or `that` otherwise. */ | |
def min(that: Byte): Byte = java.lang.Math.min(self.toInt, that.toInt).toByte | |
infix def max(that: Byte): Byte = java.lang.Math.max(self.toInt, that.toInt).toByte | |
/** Returns `this` if `this < that` or `that` otherwise. */ | |
infix def min(that: Byte): Byte = java.lang.Math.min(self.toInt, that.toInt).toByte |
It has always been weird that the public API of primitive types, enriched by
Predef
depends on theRich*
classes, which are in the not-really-publicruntime
package.Moreover, the design of those classes was overabstracted, with consequences on performance (unnecessary boxing) and quality of the API (including methods that do not make sense on some types). To mitigate that, the individual
Rich*
classes redefined some (but not all) of the methods, defeating the abstraction.We solve both issues with a simple solution: define all those methods as simple
extension
methods. We do this directly in the companion objects of the primitive types.This would be a required step before we do anything about #23824.