Hi, I’m wondering whether it is possible to use structural types to obtain computed field names.
In the below example, I have a Wrapper class that uses computed field types so that subfield access returns a Wrapper type for the subfield type.
However, since NamedTuple.From[T] and Mirror.ProductOf[T] works only for ADTs, I can only define the schema of Aggregates using case classes.
However, I would really love the users of the API to be able to define the schema as a structural type as it removes the need to define a custom constructor for the schema.
Would this be possible in any way or is this a fundamental limitation of Scala3?
package playground5
import scala.deriving.*
import scala.compiletime.*
import scala.NamedTuple
sealed trait ValueType
sealed class IntValue(val x: Int) extends ValueType
trait Aggregate extends ValueType
final class Wrapper[T](val t: T) extends Selectable:
type Fields = NamedTuple.Map[
NamedTuple.From[T],
[X] =>> Wrapper[X & ValueType]]
inline def selectDynamic(name: String): Wrapper[?] =
summonFrom {
case m: Mirror.ProductOf[T] =>
val labels = constValueTuple[m.MirroredElemLabels].toArray
val idx = labels.indexOf(name)
val child = t.asInstanceOf[Product].productElement(idx).asInstanceOf[ValueType]
new Wrapper(child)
case _ =>
throw new NoSuchElementException(s"${t.getClass.getName} has no field '$name'")
}
@main def demo(): Unit =
final case class AggExample(a: IntValue, b: IntValue) extends Aggregate
val agg = AggExample(IntValue(2), IntValue(3))
val wrap = Wrapper(agg)
val wrap_a: Wrapper[IntValue] = wrap.a
// What I wish:
//
// trait AggregateSelectable extends Aggregate with Selectable
// class AggSelectable extends AggregateSelectable:
// val a = IntValue(2)
// val b = IntValue(3)
//
// val wrap = Wrapper(new AggSelectable)