Skip to content

This library is intended to solve the use case of getting the erased types of a (generic) parameter. Something which was possible in Scala 2 with TypeTag and is now a bit more complex with Scala 3.

License

Notifications You must be signed in to change notification settings

gaeljw/typetrees

Repository files navigation

TypeTrees

typetrees 3
badge

This library is intended to solve the use case of getting the erased types of a (generic) parameter. Something which was possible in Scala 2 with TypeTag and is now a bit more complex with Scala 3.

Get it

sbt
libraryDependencies += "io.github.gaeljw" %% "typetrees" % typetreesVersion
Maven
<dependency>
  <groupId>io.github.gaeljw</groupId>
  <artifactId>typetrees_${scala.version}</artifactId>
  <version>${typetrees.version}</version>
</dependency>

Usage

Two implementations are available:

  • using implicits (given s)

  • using macro

Implementation Pros 👍 Cons 👎

Implicits

Easier

Only supports up to 4 generic parameters (i.e. a type T[A, B, C, D])

Macro

Can handle all cases

Requires to be used in inline method

Using implicits

import io.github.gaeljw.typetrees.TypeTree
import io.github.gaeljw.typetrees.TypeTreeTag

import scala.reflect.ClassTag

val tag: TypeTreeTag = summon[TypeTree[T]].tag // (1)

val classTag: ClassTag[_] = tag.self // (2)
val actualClass: Class[_] = classTag.runtimeClass

val typeParameters: List[TypeTreeTag] = tag.args // (3)
  1. Get a TypeTreeTag for a generic type T

  2. Get a ClassTag for this type

  3. Get a TypeTreeTag for each type parameters if any

Examples

The main usage is as follows:

def someGenericMethod[T](t: T)(using typeTree: TypeTree[T]): String = {
    val tag: TypeTreeTag = typeTree.tag
    s"I have been called with a parameter of type $tag"
}

someGenericMethod(Map[String, Int]())
// Gives: I have been called with a parameter of type TypeTreeTag(scala.collection.immutable.Map,List(TypeTreeTag(java.lang.String,List()), TypeTreeTag(Int,List())))

Or with context bounds:

def someGenericMethod[T : TypeTree](t: T): String = {
    val tag: TypeTreeTag = summon[TypeTree[T]].tag
    s"I have been called with a parameter of type $tag"
}

You can find more examples in our tests.

Using macro

import io.github.gaeljw.typetrees.TypeTreeTag
import io.github.gaeljw.typetrees.TypeTreeTagMacros.typeTreeTag

import scala.reflect.ClassTag

val tag: TypeTreeTag = typeTreeTag[T] // (1)

val classTag: ClassTag[_] = tag.self // (2)
val actualClass: Class[_] = classTag.runtimeClass

val typeParameters: List[TypeTreeTag] = tag.args // (3)
  1. Get a TypeTreeTag for a generic type T

  2. Get a ClassTag for this type

  3. Get a TypeTreeTag for each type parameters if any

Examples

The main usage is as follows, within a generic inline method:

inline def someGenericMethod[T](t: T): String = {
    val tag: TypeTreeTag = typeTreeTag[T]
    s"I have been called with a parameter of type $tag"
}

someGenericMethod(Map[String, Int]())
// Gives: I have been called with a parameter of type TypeTreeTag(scala.collection.immutable.Map,List(TypeTreeTag(java.lang.String,List()), TypeTreeTag(Int,List())))

Or:

inline def someGenericMapMethod[T <: Map[_,_]](map: T): String = {
    val mapTag: TypeTreeTag = typeTreeTag[T]
    val keyTag: TypeTreeTag = mapTag.args(0)
    val valueTag: TypeTreeTag = mapTag.args(1)
    s"I have been called with a Map where key is of type $keyTag and value is of type $valueTag"
}

It can also be applied to non generic types: in such case it doesn’t need to be part of a inline def but you probably can just use regular ClassTag then.

You can find more examples in our tests.

About

This library is intended to solve the use case of getting the erased types of a (generic) parameter. Something which was possible in Scala 2 with TypeTag and is now a bit more complex with Scala 3.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •  

Languages