Relate to Inline parameters for constructors.
Introduction
The Dotty inline feature offers many new possibilities without “black magic”, especially for compile-time manipulations/value retrieval. However, this feature is disallowed for constructor parameters.
**Disclaimer: This is not (yet) a SIP. It is a “simple” proposal I’m posting on Scala Contributors to get feedback and to discuss about it.
Motivation
Allowing constructors (and given ... with) to have inline parameters would enable new usages at both reducing overhead and evaluating compile-time values.
Example 1: compile-time typeclasses
Say we have a typeclass method you want to evaluate at compile-time (in an inline condition or using Expr#value in a macro), for example a refined types system
//Represent a refined type
opaque type Refined[A, B] <: A = A
//Our inline typeclass
trait Constraint[A, B]:
inline def test(value: A): Boolean
//Refine a value at compile-time
inline def assertValue[A, B](inline value: A)(using inline constraint: Constraint[A, B]): Refined[A, B] =
inline if constraint.test(value) then value
else compiletime.error("Does not satisfy the constraint")
This works for typeclass instances that doesn’t require inline params:
final class Positive
given Constraint[Int, Positive] with
override inline def test(value: Int): Boolean = value > 0
assertValue[Int, Positive](1) // 1: Refined[Int, Positive]
assertValue[Int, Positive](-1) // Compile-time error: "Does not satsify the constraint"
However, this doesn’t work when (non inline because disallowed) parameters are called:
final class Not[B]
given [A, B](using constraint: Constraint[A, B]): Constraint[A, Not[B]] with
override inline def test(value: A): Boolean = !constraint.test(value)
assertValue[Int, Not[Positive]](-1) //Compile-time error, expected a known value
because constraint.test(value) is not fully inline. As a consequence, the final condition !constraint.test(value) isn’t either.
Allowing inline parameters would fix this limitation:
final class Not[B]
given [A, B](using inline constraint: Constraint[A, B]): Constraint[A, Not[B]] with
override inline def test(value: A): Boolean = !constraint.test(value) //Get fully inlined (if value is inlinable too)
assertValue[Int, Not[Positive]](1) //Compile-time error: Does not satisfy the constraint
assertValue[Int, Not[Positive]](-1) //-1: Refined[Int, Not[Positive]]
Example 2: reduce monadic code overhead
With this change, we could eliminate overhead of some monad transformers:
//Anloguous to `A => B` but inline. This is already doable with the current Scala version
trait InlineFunction[A, B]:
inline def apply(a: A): B
class Monad[T](inline val value: => T):
inline def flatMap[A](inline f: InlineFunction[A, Monad[B]]): Monad[A] = f(value)
inline def map[A](inline f: InlineFunction[A, B]): Monad[A] = Monad(f(value))
then
Monad(5)
.map(_ * 2)
.map(_ / 10)
.value
is inlined to 5*2/10 which is also inlined to 1 (See Inline parameters)
Design
Here are some rules:
- Like method’s
inlineparameters, constructor’sinlineparameters are immutable. - Constructors cannot be
inline. The goal of this proposal is to allow classes/constructors to carryinlineparameters. Aninlineconstructor is non sense (atleast to me). given ... withsyntax is also concerned by this change.
Here is a question asked in the old thread:
This should behave the same as classic inline instance methods, which already exist in the current version of Scala: since dummy is not inline, it doesn’t desugar to Dummy(value) so dummy("Hello World").value will not be inlined.
For instance in current versions:
class Dummy:
inline def value: String = "hey"
def dummy: Dummy = Dummy()
dummy.value // -> dummy.value
class Dummy:
inline def value: String = "hey"
def dummy: Dummy = Dummy()
println(compiletime.codeOf(dummy.value)) // -> "hey"
Compatibility
This change shouldn’t break compatibility for existing features. However, note you cannot use a compiled/TASTY code that uses inline parameters in a previous version which doesn’t support them simply because it is not a “simple syntactic sugar”.

