Skip to content

Facilitate compile-time typeclass creation #14282

Closed
@Iltotore

Description

@Iltotore

There was a quiproquo in the original issue #14226 and it got closed before clarifying it. I will try to reformulate and be as accurate as possible.

Compiler version

3.1.0

Introdution

In Scala 3, you can create traits with inline methods:

trait Test {

  inline def msg: String
}

msg is compiles and runs as expected if the implementation's exact type is known at compile-time:

inline given Test = new TestImpl
summon[Test].msg //Deferred inline

inline given TestImpl = new TestImpl
summon[TestImpl].msg //Compiles and runs

transparent inline given Test = new TestImpl
summon[TestImpl].msg //Compiles and runs

This behaviour is useful when creating typeclasses that have to (or can) be evaluated at compile-time. A minimized example from on of my projects:

trait Constraint[A, -B] {

  inline def assert(value: A): Boolean

  inline def getMessage(value: A): String
}

implicit inline def refineValue[A, B, C <: Constraint[A, B]](value: A)(using inline constraint: C): A / B = {
  Constrained(compileTime.preAssert[A, B, C](value, constraint.getMessage(value), constraint.assert(value)))
}

This code will pass the compile time-evaluated String constraint.getMessage(value) and Boolean constraint.assert(value)

Note: the C redudant type parameter forces the compiler to get the exact type of the Constraint implementation.

The Issue

Currently, for Constraints with type parameters, we have to create a brand new class for each implementation:

trait Less[V] extends AlgebraEntryPoint[MathAlgebra] with Transitive[V] with Asymmetric[V, Greater]

class LessConstraint[A <: Number, V <: A] extends Constraint[A, Less[V]] {
  override inline def assert(value: A): Boolean = NumberOrdering.lt(value, constValue[V])

  override inline def getMessage(value: A): String = "value should be less than the specified one"
}

transparent inline given[A <: Number, V <: A]: Constraint[A, Less[V]] = new LessConstraint

Which works but we actually can't use anonymous given instances for this:

given [A <: Number, V <: A]: Constraint[A, Less[V]] with {

  override inline def assert(value: A): Boolean = NumberOrdering.lt(value, constValue[V])

  override inline def getMessage(value: A): String = "value should be less than the specified one"
}

The assert and getMessage methods are not fully inline even when called with an inline value input.

Expectation

I would expect this last example to behave the same as the preceding one above: method calls fully inline.

I hope my issue is now clearer. My goal is not to spam my issue.

Metadata

Metadata

Assignees

Labels

stat:needs triageEvery issue needs to have an "area" and "itype" label

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions