Type information erased after value assignment inside function

Hey!

I have a pretty usual Selectable trait implementation and an associated macro to create it:

trait Record extends Selectable:
  type In
  type Members <: NonEmptyTuple

  val all: Members
  def selectDynamic(s: String) =
    all.toList.find(_.toString.contains(s)).get

object Record:
  transparent inline def build[In] = ???

I then want to pass the resulting type to another class:

class Wrapper[R](record: R):
  def process(f: R => Output): Result =
    known.implementation.using(f(record))

But the problem is that if I instantiate the record and assign it to value:

transparent inline def wrap =
  val record = Record.build[T]
  new Wrapper(r)

…I’m losing most of type info. It becomes something like:

val res0: Record{type In; type Members} = anon$1@16ef1160 

…which is effectively useless in my process HOF. Without assignment it gives me a working selectable:

transparent inline def wrap = Record.build[T]      // No assignment

wrap

val res0: Record {
  type In = Insert[?, ?, Foo];
  type Members = Tuple2[Insert["first_name", String, Foo], Insert["age", Int, Foo]]
} & Record {
  val first_name: Insert["first_name", String, Foo];
  val age: Insert["age", Int, Foo]
} = anon$1@16ef1160 

I guess my questions are:

  1. Is it possible to preserve the full type info inside a function?
  2. Is there a working way to make my Wrapper.process a typed function?

Another way to look at the problem I want to solve is via imaginable typeOf operator:

transparent inline def wrap =
  type RecordType = typeof(Record.build[T])
  new Wrapper[RecordType]

I wanted to achieve this via type inference, but failing at it.

i have 0 practical experience with metaprogramming, but maybe this would work?

transparent inline def build = Record.build[T]
transparent inline def wrap = new Wrapper(build)

i.e. split the method to multiple transparent inline defs and avoid assignment inside.

just a quick suggestion.

Yup, tried that, didn’t work out. I instead had to write another macro:

object Wrapper:
  inline def build[R](record: R): Wrapper[R] = ???

…which then inspects the R type at compile-time and builds the Wrapper[R] based on that. That’s bit more work, but the only way I found so far.

i have 0 practical experience with metaprogramming

You should try, it’s awesome :wink: