Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,51 @@ the bottom of this file. Restoration ships incrementally per feature area.
compiles).
- `enum` was renamed to `e` at one call site in `GenKeyCodec` (`enum` is reserved in Scala 3).
- `@targetName` annotation added to `CloseableIterator` overloaded methods.
- `@inline def` → `inline def` across Opt family (`Opt`, `NOpt`, `OptArg`, `OptRef` — 117 sites). Scala 3 `inline def` is
implicitly `final` and cannot be overridden — a source-compat break for downstream subclassers. Mitigation: targets
are value classes (final by construction); zero impact on downstream subclassing patterns. Three trivial accessors
(`isEmpty`, `isDefined`, `nonEmpty`, `get`) kept as plain `def` per Scala 3 inline edge case: pattern-match desugaring
(`case Opt(x) =>`) calls these and cannot inline at compiler-generated call sites.
- Whitelist preserved verbatim (JVM-optimizer-hint convention on tight-loop parser hot paths): `CborInput.bits` (1
site), `JsonStringInput` (5 sites — `read`, `isNext`, `isNextDigit`, `advance`, nested `update`), `RPCFramework` (2
sites — RPC module remains Scala 2.13-only per fork strategy).
- `@publicInBinary` annotation added on private constructors and `private[misc]` members referenced from `inline def`
bodies in `Opt`, `NOpt`, `OptArg`, `OptRef` (Scala 3 compiler requirement: "Private constructors used in inline
methods require @publicInBinary"). Binary-stable extension point; no source-compat impact on callers.
- Binary-compat: Scala 3 `inline def` emits no bytecode method. MiMa would flag if/when the scala-3 baseline is
released; currently MiMa is off (`mimaPreviousArtifacts := Set.empty`).
- `inline` scope tightened (per user directive 2026-06-01): `inline def` is now applied only to methods with at least one
`Function`/`PartialFunction`-typed parameter (e.g. `map[B](inline f: A => B)`, `collect(inline pf: PartialFunction[A, B])`,
`foreach[U](inline f: A => U)`, `fold(ifEmpty: => B)(inline f: A => B)`). Methods whose only parameters are values,
implicits, or by-name (`=> T`) are reverted to plain `def` — by-name already provides call-site substitution in
Scala 3 without the `inline def` overhead. Affected reverts: `boxed`/`boxedOrNull`/`unboxed`/`toOption`/`toOpt`/`toOptRef`/
`toNOpt`/`toOptArg`/`orNull`/`flatten`/`contains`/`iterator`/`toList`/`zip`/`getOrElse`/`orElse`/`toRight`/`toLeft`/
`forEmpty` in the Opt family; `Opt.LazyOptOps.unless`; `gSupplier` in GuavaInterop; `jBooleanSupplier`/`jDoubleSupplier`/
`jIntSupplier`/`jLongSupplier`/`jSupplier` in JFunctionUtils; `onClose` in all four `ScalaJ*Stream` types.
- Redundant `inline` keyword stripped from by-name parameters across retained `inline def` methods (Scala 3: `inline x: => T`
is redundant — `=> T` already provides call-site splicing). Affected: `fold(ifEmpty: => B)`, `mapOr(ifEmpty: => B)` in
Opt family; `collect(supplier: => R)(…)` in all four `ScalaJ*Stream` types.
- `inline` extended to jiop adapters with Function-typed parameters: `JFunctionUtils` jXxx adapters (38 sites with
Function params; 5 Supplier adapters now plain `def`), `Java8CollectionUtils` (`jCollection.forEach/removeIf`,
`jMap.compute*`/`forEach`/`merge`/`replaceAll`), `GuavaInterop` gFunction/gPredicate (2 sites; gSupplier now plain
`def`), and `ScalaJ{Stream,IntStream,LongStream,DoubleStream}` pipeline ops (`filter`/`map`/`flatMap`/`forEach`/
`reduce`/`collect`/`peek`/…). Exception: `ListenableFutureAsScala.{onComplete, transform, transformWith}` in
`GuavaInterop` override `scala.concurrent.Future` methods (which have non-`inline` params) and stay as plain `def` —
Scala 3 forbids overriding a non-inline parameter with an inline parameter.
- Trailing `; ()` removed from Consumer SAM lambda bodies in `JFunctionUtils` (`jBiConsumer`/`jConsumer`/`jDoubleConsumer`/
`jIntConsumer`/`jLongConsumer`/`jObjDoubleConsumer`/`jObjIntConsumer`/`jObjLongConsumer`). Scala 3 SAM conversion to a
void-returning Java functional interface accepts a result expression of any type — explicit `()`-coercion is unnecessary
noise.
- By-name parameters reshaped to `inline` value parameters on `inline def` Opt-family forwarders where the body uses
the parameter exactly once in a straight-line `if/then/else` branch (no closure capture, no multi-evaluation, no
default value). Affected (19 sites across Opt/NOpt/OptArg/OptRef): `getOrElse(inline default: B)`,
`fold(inline ifEmpty: B)(inline f: ...)`, `mapOr(inline ifEmpty: B, inline f: ...)`, `orElse(inline alternative: Opt[B])`,
`toRight(inline left: X)`, `toLeft(inline right: X)`, `forEmpty(inline sideEffect: Unit)`. Rationale: with `inline def`,
an `inline B` parameter substitutes the expression literally at the call site — no `Function0` thunk allocation, no
by-name dispatch overhead. Strictly cheaper than `=> B` for single-use straight-line bodies. Call-site syntax is
identical (callers pass any `B`-typed expression). Suppliers (`gSupplier`, `jBooleanSupplier`, `jDoubleSupplier`,
`jIntSupplier`, `jLongSupplier`, `jSupplier`) and stream `onClose`/`collect(supplier:)` keep `=> T` — those by-name
params are wrapped inside `() => expr` closures (deferred-evaluation intent).

### mongo

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ trait GuavaInterop {
type GSupplier[T] = gbase.Supplier[T]
type GPredicate[T] = gbase.Predicate[T]

def gFunction[F, T](fun: F => T): GFunction[F, T] = fun(_)
def gSupplier[T](expr: => T): GSupplier[T] = () => expr
def gPredicate[T](pred: T => Boolean): GPredicate[T] = pred(_)
inline def gFunction[F, T](inline fun: F => T): GFunction[F, T] = fun(_)
inline def gSupplier[T](expr: => T): GSupplier[T] = () => expr
inline def gPredicate[T](inline pred: T => Boolean): GPredicate[T] = pred(_)

implicit def toDecorateAsScala[T](gfut: ListenableFuture[T]): DecorateFutureAsScala[T] =
new DecorateFutureAsScala(gfut)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,47 +50,47 @@ trait JFunctionUtils {
type JToLongFunction[T] = juf.ToLongFunction[T]
type JUnaryOperator[T] = juf.UnaryOperator[T]

def jBiConsumer[T, U](code: (T, U) => Any): JBiConsumer[T, U] = (t, u) => { code(t, u); () }
def jBiFunction[T, U, R](fun: (T, U) => R): JBiFunction[T, U, R] = fun(_, _)
def jBiPredicate[T, U](pred: (T, U) => Boolean): JBiPredicate[T, U] = pred(_, _)
def jBinaryOperator[T](op: (T, T) => T): JBinaryOperator[T] = op(_, _)
def jBooleanSupplier(expr: => Boolean): JBooleanSupplier = () => expr
def jConsumer[T](code: T => Any): JConsumer[T] = t => { code(t); () }
def jDoubleBinaryOperator(op: (Double, Double) => Double): JDoubleBinaryOperator = op(_, _)
def jDoubleConsumer(code: Double => Any): JDoubleConsumer = d => { code(d); () }
def jDoubleFunction[R](fun: Double => R): JDoubleFunction[R] = fun(_)
def jDoublePredicate(pred: Double => Boolean): JDoublePredicate = pred(_)
def jDoubleSupplier(expr: => Double): JDoubleSupplier = () => expr
def jDoubleToIntFunction(fun: Double => Int): JDoubleToIntFunction = fun(_)
def jDoubleToLongFunction(fun: Double => Long): JDoubleToLongFunction = fun(_)
def jDoubleUnaryOperator(op: Double => Double): JDoubleUnaryOperator = op(_)
def jFunction[T, R](fun: T => R): JFunction[T, R] = fun(_)
def jIntBinaryOperator(op: (Int, Int) => Int): JIntBinaryOperator = op(_, _)
def jIntConsumer(code: Int => Any): JIntConsumer = i => { code(i); () }
def jIntFunction[R](fun: Int => R): JIntFunction[R] = fun(_)
def jIntPredicate(pred: Int => Boolean): JIntPredicate = pred(_)
def jIntSupplier(expr: => Int): JIntSupplier = () => expr
def jIntToDoubleFunction(fun: Int => Double): JIntToDoubleFunction = fun(_)
def jIntToLongFunction(fun: Int => Long): JIntToLongFunction = fun(_)
def jIntUnaryOperator(op: Int => Int): JIntUnaryOperator = op(_)
def jLongBinaryOperator(op: (Long, Long) => Long): JLongBinaryOperator = op(_, _)
def jLongConsumer(code: Long => Any): JLongConsumer = l => { code(l); () }
def jLongFunction[R](fun: Long => R): JLongFunction[R] = fun(_)
def jLongPredicate(pred: Long => Boolean): JLongPredicate = pred(_)
def jLongSupplier(expr: => Long): JLongSupplier = () => expr
def jLongToDoubleFunction(fun: Long => Double): JLongToDoubleFunction = fun(_)
def jLongToIntFunction(fun: Long => Int): JLongToIntFunction = fun(_)
def jLongUnaryOperator(op: Long => Long): JLongUnaryOperator = op(_)
def jObjDoubleConsumer[T](code: (T, Double) => Any): JObjDoubleConsumer[T] = (t, d) => { code(t, d); () }
def jObjIntConsumer[T](code: (T, Int) => Any): JObjIntConsumer[T] = (t, i) => { code(t, i); () }
def jObjLongConsumer[T](code: (T, Long) => Any): JObjLongConsumer[T] = (t, l) => { code(t, l); () }
def jPredicate[T](pred: T => Boolean): JPredicate[T] = pred(_)
def jSupplier[T](expr: => T): JSupplier[T] = () => expr
def jToDoubleBiFunction[T, U](fun: (T, U) => Double): JToDoubleBiFunction[T, U] = fun(_, _)
def jToDoubleFunction[T](fun: T => Double): JToDoubleFunction[T] = fun(_)
def jToIntBiFunction[T, U](fun: (T, U) => Int): JToIntBiFunction[T, U] = fun(_, _)
def jToIntFunction[T](fun: T => Int): JToIntFunction[T] = fun(_)
def jToLongBiFunction[T, U](fun: (T, U) => Long): JToLongBiFunction[T, U] = fun(_, _)
def jToLongFunction[T](fun: T => Long): JToLongFunction[T] = fun(_)
def jUnaryOperator[T](op: T => T): JUnaryOperator[T] = op(_)
inline def jBiConsumer[T, U](inline code: (T, U) => Any): JBiConsumer[T, U] = (t, u) => code(t, u)
inline def jBiFunction[T, U, R](inline fun: (T, U) => R): JBiFunction[T, U, R] = fun(_, _)
inline def jBiPredicate[T, U](inline pred: (T, U) => Boolean): JBiPredicate[T, U] = pred(_, _)
inline def jBinaryOperator[T](inline op: (T, T) => T): JBinaryOperator[T] = op(_, _)
inline def jBooleanSupplier(expr: => Boolean): JBooleanSupplier = () => expr
inline def jConsumer[T](inline code: T => Any): JConsumer[T] = t => code(t)
inline def jDoubleBinaryOperator(inline op: (Double, Double) => Double): JDoubleBinaryOperator = op(_, _)
inline def jDoubleConsumer(inline code: Double => Any): JDoubleConsumer = d => code(d)
inline def jDoubleFunction[R](inline fun: Double => R): JDoubleFunction[R] = fun(_)
inline def jDoublePredicate(inline pred: Double => Boolean): JDoublePredicate = pred(_)
inline def jDoubleSupplier(expr: => Double): JDoubleSupplier = () => expr
inline def jDoubleToIntFunction(inline fun: Double => Int): JDoubleToIntFunction = fun(_)
inline def jDoubleToLongFunction(inline fun: Double => Long): JDoubleToLongFunction = fun(_)
inline def jDoubleUnaryOperator(inline op: Double => Double): JDoubleUnaryOperator = op(_)
inline def jFunction[T, R](inline fun: T => R): JFunction[T, R] = fun(_)
inline def jIntBinaryOperator(inline op: (Int, Int) => Int): JIntBinaryOperator = op(_, _)
inline def jIntConsumer(inline code: Int => Any): JIntConsumer = i => code(i)
inline def jIntFunction[R](inline fun: Int => R): JIntFunction[R] = fun(_)
inline def jIntPredicate(inline pred: Int => Boolean): JIntPredicate = pred(_)
inline def jIntSupplier(expr: => Int): JIntSupplier = () => expr
inline def jIntToDoubleFunction(inline fun: Int => Double): JIntToDoubleFunction = fun(_)
inline def jIntToLongFunction(inline fun: Int => Long): JIntToLongFunction = fun(_)
inline def jIntUnaryOperator(inline op: Int => Int): JIntUnaryOperator = op(_)
inline def jLongBinaryOperator(inline op: (Long, Long) => Long): JLongBinaryOperator = op(_, _)
inline def jLongConsumer(inline code: Long => Any): JLongConsumer = l => code(l)
inline def jLongFunction[R](inline fun: Long => R): JLongFunction[R] = fun(_)
inline def jLongPredicate(inline pred: Long => Boolean): JLongPredicate = pred(_)
inline def jLongSupplier(expr: => Long): JLongSupplier = () => expr
inline def jLongToDoubleFunction(inline fun: Long => Double): JLongToDoubleFunction = fun(_)
inline def jLongToIntFunction(inline fun: Long => Int): JLongToIntFunction = fun(_)
inline def jLongUnaryOperator(inline op: Long => Long): JLongUnaryOperator = op(_)
inline def jObjDoubleConsumer[T](inline code: (T, Double) => Any): JObjDoubleConsumer[T] = (t, d) => code(t, d)
inline def jObjIntConsumer[T](inline code: (T, Int) => Any): JObjIntConsumer[T] = (t, i) => code(t, i)
inline def jObjLongConsumer[T](inline code: (T, Long) => Any): JObjLongConsumer[T] = (t, l) => code(t, l)
inline def jPredicate[T](inline pred: T => Boolean): JPredicate[T] = pred(_)
inline def jSupplier[T](expr: => T): JSupplier[T] = () => expr
inline def jToDoubleBiFunction[T, U](inline fun: (T, U) => Double): JToDoubleBiFunction[T, U] = fun(_, _)
inline def jToDoubleFunction[T](inline fun: T => Double): JToDoubleFunction[T] = fun(_)
inline def jToIntBiFunction[T, U](inline fun: (T, U) => Int): JToIntBiFunction[T, U] = fun(_, _)
inline def jToIntFunction[T](inline fun: T => Int): JToIntFunction[T] = fun(_)
inline def jToLongBiFunction[T, U](inline fun: (T, U) => Long): JToLongBiFunction[T, U] = fun(_, _)
inline def jToLongFunction[T](inline fun: T => Long): JToLongFunction[T] = fun(_)
inline def jUnaryOperator[T](inline op: T => T): JUnaryOperator[T] = op(_)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ trait Java8CollectionUtils {

object Java8CollectionUtils {
class jIteratorOps[A](private val it: JIterator[A]) extends AnyVal {
def forEachRemaining(code: A => Any): Unit =
inline def forEachRemaining(inline code: A => Any): Unit =
it.forEachRemaining(jConsumer(code))
}

class jIterableOps[A](private val it: JIterable[A]) extends AnyVal {
def forEach(code: A => Any): Unit =
inline def forEach(inline code: A => Any): Unit =
it.forEach(jConsumer(code))
}

class jCollectionOps[A](private val coll: JCollection[A]) extends AnyVal {
def removeIf(pred: A => Boolean): Unit =
inline def removeIf(inline pred: A => Boolean): Unit =
coll.removeIf(jPredicate(pred))

def scalaStream: ScalaJStream[A] =
Expand All @@ -49,22 +49,22 @@ object Java8CollectionUtils {
}

class jMapOps[K, V](private val map: JMap[K, V]) extends AnyVal {
def compute(key: K, remappingFunction: (K, V) => V): V =
inline def compute(key: K, inline remappingFunction: (K, V) => V): V =
map.compute(key, jBiFunction(remappingFunction))

def computeIfAbsent(key: K)(mappingFunction: K => V): V =
inline def computeIfAbsent(key: K)(inline mappingFunction: K => V): V =
map.computeIfAbsent(key, jFunction(mappingFunction))

def computeIfPresent(key: K)(remappingFunction: (K, V) => V): V =
inline def computeIfPresent(key: K)(inline remappingFunction: (K, V) => V): V =
map.computeIfPresent(key, jBiFunction(remappingFunction))

def forEach(action: (K, V) => Any): Unit =
inline def forEach(inline action: (K, V) => Any): Unit =
map.forEach(jBiConsumer(action))

def merge(key: K, value: V)(remappingFunction: (V, V) => V): V =
inline def merge(key: K, value: V)(inline remappingFunction: (V, V) => V): V =
map.merge(key, value, jBiFunction(remappingFunction))

def replaceAll(function: (K, V) => V): Unit =
inline def replaceAll(inline function: (K, V) => V): Unit =
map.replaceAll(jBiFunction(function))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class ScalaJDoubleStream(private val jStream: JDoubleStream) extends AnyVa
def iterator: Iterator[Double] =
jStream.iterator().asInstanceOf[JIterator[Double]].asScala

def onClose(closeHandler: => Any): ScalaJDoubleStream =
inline def onClose(closeHandler: => Any): ScalaJDoubleStream =
new ScalaJDoubleStream(jStream.onClose(jRunnable(closeHandler)))

def parallel: ScalaJDoubleStream =
Expand All @@ -28,10 +28,10 @@ final class ScalaJDoubleStream(private val jStream: JDoubleStream) extends AnyVa
def unordered: ScalaJDoubleStream =
new ScalaJDoubleStream(jStream.unordered())

def allMatch(predicate: Double => Boolean): Boolean =
inline def allMatch(inline predicate: Double => Boolean): Boolean =
jStream.allMatch(jDoublePredicate(predicate))

def anyMatch(predicate: Double => Boolean): Boolean =
inline def anyMatch(inline predicate: Double => Boolean): Boolean =
jStream.anyMatch(jDoublePredicate(predicate))

def average: Option[Double] =
Expand All @@ -40,7 +40,7 @@ final class ScalaJDoubleStream(private val jStream: JDoubleStream) extends AnyVa
def boxed: ScalaJStream[Double] =
new ScalaJStream(jStream.boxed.asInstanceOf[JStream[Double]])

def collect[R](supplier: => R)(accumulator: (R, Double) => Any, combiner: (R, R) => Any): R =
inline def collect[R](supplier: => R)(inline accumulator: (R, Double) => Any, inline combiner: (R, R) => Any): R =
jStream.collect(jSupplier(supplier), jObjDoubleConsumer(accumulator), jBiConsumer(combiner))

def count: Long =
Expand All @@ -49,7 +49,7 @@ final class ScalaJDoubleStream(private val jStream: JDoubleStream) extends AnyVa
def distinct: ScalaJDoubleStream =
new ScalaJDoubleStream(jStream.distinct)

def filter(predicate: Double => Boolean): ScalaJDoubleStream =
inline def filter(inline predicate: Double => Boolean): ScalaJDoubleStream =
new ScalaJDoubleStream(jStream.filter(jDoublePredicate(predicate)))

def findAny: Option[Double] =
Expand All @@ -58,28 +58,28 @@ final class ScalaJDoubleStream(private val jStream: JDoubleStream) extends AnyVa
def findFirst: Option[Double] =
jStream.findFirst.asScala

def flatMap(mapper: Double => ScalaJDoubleStream): ScalaJDoubleStream =
inline def flatMap(inline mapper: Double => ScalaJDoubleStream): ScalaJDoubleStream =
new ScalaJDoubleStream(jStream.flatMap(jDoubleFunction(d => mapper(d).jStream)))

def forEach(action: Double => Any): Unit =
inline def forEach(inline action: Double => Any): Unit =
jStream.forEach(jDoubleConsumer(action))

def forEachOrdered(action: Double => Any): Unit =
inline def forEachOrdered(inline action: Double => Any): Unit =
jStream.forEachOrdered(jDoubleConsumer(action))

def limit(maxSize: Long): ScalaJDoubleStream =
new ScalaJDoubleStream(jStream.limit(maxSize))

def map(mapper: Double => Double): ScalaJDoubleStream =
inline def map(inline mapper: Double => Double): ScalaJDoubleStream =
new ScalaJDoubleStream(jStream.map(jDoubleUnaryOperator(mapper)))

def mapToInt(mapper: Double => Int): ScalaJIntStream =
inline def mapToInt(inline mapper: Double => Int): ScalaJIntStream =
new ScalaJIntStream(jStream.mapToInt(jDoubleToIntFunction(mapper)))

def mapToLong(mapper: Double => Long): ScalaJLongStream =
inline def mapToLong(inline mapper: Double => Long): ScalaJLongStream =
new ScalaJLongStream(jStream.mapToLong(jDoubleToLongFunction(mapper)))

def mapToObj[U](mapper: Double => U): ScalaJStream[U] =
inline def mapToObj[U](inline mapper: Double => U): ScalaJStream[U] =
new ScalaJStream(jStream.mapToObj(jDoubleFunction(mapper)))

def max: Option[Double] =
Expand All @@ -88,16 +88,16 @@ final class ScalaJDoubleStream(private val jStream: JDoubleStream) extends AnyVa
def min: Option[Double] =
jStream.min.asScala

def noneMatch(predicate: Double => Boolean): Boolean =
inline def noneMatch(inline predicate: Double => Boolean): Boolean =
jStream.noneMatch(jDoublePredicate(predicate))

def peek(action: Double => Any): ScalaJDoubleStream =
inline def peek(inline action: Double => Any): ScalaJDoubleStream =
new ScalaJDoubleStream(jStream.peek(jDoubleConsumer(action)))

def reduce(identity: Double)(op: (Double, Double) => Double): Double =
inline def reduce(identity: Double)(inline op: (Double, Double) => Double): Double =
jStream.reduce(identity, jDoubleBinaryOperator(op))

def reduce(op: (Double, Double) => Double): Option[Double] =
inline def reduce(inline op: (Double, Double) => Double): Option[Double] =
jStream.reduce(jDoubleBinaryOperator(op)).asScala

def skip(n: Long): ScalaJDoubleStream =
Expand Down
Loading
Loading