Any idea how to enable them? A Scastie link with an example would be best.
Here is what it should look like:
However RCs are not considered nightly or snapshot (at least for the purposes of experimental features), so the above does not work
We would need to add a nightly version to Scastie, which is a known issue, for example see this
Okay, as discussed in the issue, there is a work around, here is a fully working example:
Cool, thanks!
Is there a reason why Scala cannot allow type parameter groups in the same way as regular parameter groups? For example:
def f[A, B][C](f (A, B) => C)
That way we could require some types and let the compiler to infer the others, e.g.:
f[Int, Int]: (a, b) =>
(a + b).toString
Currently the interleaved type parameters feature doesn’t allow that directly, because every type parameter list should be followed by regular parameters (in parentheses), but here the first parameter requires all the types at once. There is a work-around though:
def f[A, B]()[C](f (A, B) => C) = ???
f[Int, Int](): (a, b) =>
(a + b).toString
But it doesn’t look very neat.
Nevertheless, the work-around shows that it should be feasible in principle.
If there were paramter groups in Scala, a “partial apply” pattern (which is quite ubiqutous, I’d say) could look way nicer. For example, currently in cats:
final class OptionOps[A](private val oa: Option[A]) extends AnyVal {
def liftTo[F[_]]: LiftToPartiallyApplied[F, A] = new LiftToPartiallyApplied(oa)
}
object OptionOps {
final class LiftToPartiallyApplied[F[_], A](oa: Option[A]):
def apply[E](ifEmpty: => E)(implicit F: ApplicativeError[F, ? >: E]): F[A] =
ApplicativeError.liftFromOption(oa, ifEmpty)
}
All that hassle is only required to support this syntax:
val opt: Option[String] = ...
opt.liftTo[IO]:
new Exception("OOPS")
That could be simplified substantially with parameter groups, I guess:
// We could also benefit from `extension` here but it is out of the scope...
final class OptionOps[A](private val oa: Option[A]) extends AnyVal:
def liftTo[F[_]][E](ifEmpty: => E)(using F: ApplicativeError[F, ? >: E]): F[A] =
ApplicativeError.liftFromOption(oa, ifEmpty)
Then in opt.liftTo[IO] we define the first type, but let the compiler to infer the rest.
Moreover, it would presumably unify type parameters and regular parameters to some extent.
That could be solved by named type arguments but according to the doc it’s not expected to be a part of scala 3. I’m unsure if maybe scala 4 or if they just put it there not to lose it but don’t intend to use it? very weird to add something to the compiler with the intention of not using it.
The reason was purely forward compatibility:
If we add it now, we can’t remove it later
The question then becomes, why might we want to remove it ?
Because named type parameters might be better:
def foo[A, B](x: A): B = ???
foo[B = String](4) // A inferred to =:= Int (or maybe the singleton type 4)
And we don’t want 2 features that solve the same problem
(Because then the user has to make a choice every time, and that’s added mental load)
It is not expected to be part of “Scala 3.0”, that’s very different !
We’re at 3.7 now I think, meaning it could come in 3.8 or 3.9 or …
But there would need to be a SIP first
But I agree that the writing is a bit misleading
Oh, I see: it really works with import scala.language.experimental.namedTypeArguments , thanks!
closely related discussion on the “partial application” aspect: How to solve the “PartiallyApplied” problem? - #2 by s5bug