SIP-56, to be realized in Scala 3.4.0, introduces some new restrictions to match type reduction.
As it stands, the type-safe zero-overhead physical dimensions library I wrote makes use of match types that will become illegal (according to Scala 3.4.0-RC1 and Nightly compilers).
Can anyone think of a way to make it compliant with SIP-56?
Below is a minimal toy version to illustrate the issue (Scastie link):
object OpaqueScope:
/**
* Type that keeps track of the dimension of a quantity.
*
* @tparam Length exponent for the length component of the dim
* @tparam Frequency exponent for the frequency component of the dim
*/
opaque type Dim[Length <: NatT, Frequency <: NatT] = Double
// Physical quantity representing one metre, aka SI unit for length
val metre: Length = 1.0
// Physical quantity representing one Hertz, aka SI unit for frequency
val hertz: Frequency = 1.0
extension[L <: NatT, F <: NatT] (x: Dim[L, F])
// Generic function to multiply any two physical quantities.
def *[Ly <: NatT, Fy <: NatT](y: Dim[Ly, Fy]): Dim[L, F] * Dim[Ly, Fy] = x * y
end OpaqueScope
import OpaqueScope.*
// Multiplies the two given Dims.
type *[D1, D2] = D1 match
case Dim[l1, f1] => D2 match
case Dim[l2, f2] => Dim[Sum[l1, l2], Sum[f1, f2]]
// Convenience alias for the type of physical quantities representing lengths
type Length = Dim[Succ[Zero], Zero]
// Convenience alias for the type of physical quantities representing frequencies
type Frequency = Dim[Zero, Succ[Zero]]
// Convenience alias for the type of physical quantities representing velocities
type Velocity = Length * Frequency
// Physical quantity multiplication example
val oneMetrePerSecond: Velocity = metre * hertz
// Type-level natural numbers
sealed trait NatT
case class Zero() extends NatT
case class Succ[N <: NatT](n: N) extends NatT
// Type-level natural-number sum
type Sum[M <: NatT, N <: NatT] <: NatT = (M, N) match
case (_, Zero) => M
case (Zero, _) => N
case (Succ[predM], Succ[predN]) => Succ[Succ[Sum[predM, predN]]]
The issue is that *
— the generic function to multiply any two physical quantities — has to be defined within OpaqueScope
in order to be able to treat its parameters as doubles.
On the other hand, since it is generic, its return type has to be computed using a match type, which is done with the type-level function *
.
However, since Dim
is synonymous with Double
within OpaqueScope
, according to SIP-56, Dim[L, F] * Dim[Ly, Fy]
cannot be reduced, leading to a compile-error.
Any thoughts would be greatly appreciated.
Note: this question is a continuation of the conversation with @sjrd that started on this issue.