An open API service indexing awesome lists of open source software.

https://github.com/gaeljw/typetrees

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.
https://github.com/gaeljw/typetrees

classtag generics scala scala3 typetag

Last synced: 4 months ago
JSON representation

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.

Awesome Lists containing this project

README

          

:testdir: src/test/scala/io/github/gaeljw/typetrees

= TypeTrees
:toc:

[link=https://search.maven.org/artifact/io.github.gaeljw/typetrees_3]
image::https://img.shields.io/maven-central/v/io.github.gaeljw/typetrees_3.svg[]
image::https://github.com/gaeljw/typetrees/workflows/Scala%20CI/badge.svg[]

WARNING: (2025-05) This library served as a prototype and should not used in any real project.
It is unmaintained.
More robust projects (or even vanilla Scala depending on the context) exist to achieve the same.

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
[source]
----
libraryDependencies += "io.github.gaeljw" %% "typetrees" % typetreesVersion
----

.Maven
[source,xml]
----

io.github.gaeljw
typetrees_${scala.version}
${typetrees.version}

----

== 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

[source,scala]
----
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:

[source,scala]
----
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:

[source,scala]
----
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 link:{testdir}/TestBehaviorImplicits.scala[tests].

=== Using macro

[source,scala]
----
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:

[source,scala]
----
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:

[source,scala]
----
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 link:{testdir}/TestBehaviorMacro.scala[tests].