0

I want to create a general purpose method def getOptionalArgs[T](): List[String] such that when passed a type, it returns the list of all arguments to that type that are an Option[_]

E.g. I have a case class Foo(bar: String, baz: Option[String]). In this case, getOptionalArgs[Foo]() would return List("baz").

I've been messing around with the reflections library, and I think I'm close via:

import scala.reflect.runtime.{universe, universe => ru}

def getOptionalArgs[T]() = {
 val constructor = ru.typeOf[T].decl(ru.termNames.CONSTRUCTOR).asMethod
 ...
}

But I cant figure out how map/filter the reflected constructors parameters. What is missing here?

Update

constructor.paramLists.head.map(t => (t.name.toString, t.info)) will return List[(String, reflect.runtime.universe.Type)] = List((bar,Int), (baz,Option[Int])). So Its very close. Now I have to be able to figure out how to test equality between Type, and no, equals doesn't seem to work.

Logister
  • 1,852
  • 23
  • 26
  • 1
    May I ask, why do you need this? Are you sure runtime reflection is the best answer to your meta-problem? – Luis Miguel Mejía Suárez Feb 09 '21 at 21:04
  • Its... complicated. I'm writing a spark application using the Dataset API and lots of case classes. I need to be able to construct arbitrary filters on the data depending on the type signature of said classes. There are other ways of achieving the same results, but not without a lot of overhead. – Logister Feb 09 '21 at 21:09
  • Oh well, **Spark** is already an inefficient and unsafe pile of runtime reflection nevertheless. Good luck with that. – Luis Miguel Mejía Suárez Feb 09 '21 at 21:11

1 Answers1

0

The solution is:

val constructor = ru.typeOf[I].decl(ru.termNames.CONSTRUCTOR).asMethod
val notOptionalColNames = constructor.paramLists.head
      .map(t => (t.name.toString, t.info))
      .filter(t => !(t._2 <:< typeTag[Option[_]].tpe)).map(_._1)
Logister
  • 1,852
  • 23
  • 26