Comments (3)
Listing derived classes of a sealed trait is interesting. I also have some use cases, but mostly for testing purpose. I'd like to see how complex your implementation is before deciding to support it in airframe-surface.
In JVM world, I would use just Java reflection as in
airframe/airframe-log/.jvm/src/main/scala/wvlet/log/io/Resource.scala
Lines 378 to 382 in 75cd4b3
which is simpler to use and does not need to generate a lot of code at compile time.
def Surface.derivedClassesWithMethods[T]: Seq[(Surface, Seq[MethodSurface])]
will generate too large code, which may hit 64k-byte code size limitation in JVM. Enumerating Surface.methodsOf[X], methodsOf[Y], .. would be much easier now that GitHub copilot can generate such enumeration code at ease.
def Surface.derivedClassesWithMethods[T]: Seq[(Surface, Seq[MethodSurface])].
from airframe.
Checking my source code it seems my Scala 2 version is not producing Surface
, only Type
. I guess producing Surface
from it should be possible, but Surface.of
is a macro and therefore will not work with it:
private def listDerivedClasses(t: Type): Set[Type] = {
def recurse(tpe: Type): Set[Type] = {
if (tpe.typeSymbol.isAbstract && tpe.typeSymbol.isClass && tpe.typeSymbol.asClass.isSealed) {
val subclasses = tpe.typeSymbol.asClass.knownDirectSubclasses.map(sym => sym.asType.typeSignature)
subclasses.flatMap(recurse)
} else {
Set(tpe)
}
}
recurse(t)
}
def listDerivedClasses[T: TypeTag]: Set[TypeDesc] = {
listDerivedClasses(implicitly[TypeTag[T]].tpe)
}
Here is Scala 3 version, which produces list of Surface
s just fine:
def getSurface(quotes: Quotes)(classSymbol: quotes.reflect.Symbol): Option[Expr[Surface]] = {
given q: Quotes = quotes
import quotes.reflect.*
val subclassType = classSymbol.typeRef
Option.when(!classSymbol.flags.is(Flags.Trait) || !classSymbol.flags.is(Flags.Sealed)) {
subclassType.asType match {
case '[t] =>
'{ Surface.of[t] }.asExprOf[Surface]
}
}
}
def enumerateSubclassesImpl[T: Type](using Quotes): Expr[List[Surface]] = {
import quotes.reflect.*
// Get the symbol of the sealed trait T
val traitSymbol = TypeRepr.of[T].typeSymbol
if (traitSymbol.flags.is(Flags.Sealed)) { // Ensure T is a sealed trait and get its subclasses
// Recursive function to get all subclasses, including indirect ones
def getAllSubclasses(symbol: Symbol): List[Symbol] = {
symbol.children.flatMap { child =>
child :: getAllSubclasses(child)
}
}
// documentation seems unclear, it seems children already include indirect children, but not always
val process = getAllSubclasses(traitSymbol).distinct
val childrenExpr = process.flatMap(getSurface(summon[Quotes]))
Expr.ofList(childrenExpr)
} else {
report.error(s"${traitSymbol.fullName} is not a sealed trait")
'{ List.empty[Surface] }
}
}
inline def enumerateSubclasses[T]: List[Surface] = ${ enumerateSubclassesImpl[T] }
from airframe.
Enumerating Surface.methodsOf[X], methodsOf[Y], .. would be much easier now that GitHub copilot can generate such enumeration code at ease.
I think the trouble with such solutions is a maintenance burden - you need to update the list each time the list of subclasses changes. It may be easy to do, but it may be easy to forget to do so. However, as I said, I personally have no need for such function at this moment, therefore I will not press to implement it.
from airframe.
Related Issues (20)
- parquet: Failed to write Map, ListMap data
- Milestone: Airframe 2024
- Surface for `Option` with a default value crashing with Scala 3 HOT 2
- Method surface for methods with multiple parameter lists fails with Scala 3
- Unable to get surface of a class with protected members in Scala 3
- http client: Record RPCException stack trace to http-client.json logs
- Surface.methodsOf - assertion failed: Tree had an unexpected owner for method HOT 1
- sbt-airframe: getNextTarEntry is deprecated
- `Surface.methodsOf` for `Seq` fails with Scala 3 HOT 1
- `Surface.methodsOf` for a function fails in Scala 3 HOT 1
- `Surface.methodsOf` for `Enumeration` fails in Scala 3 HOT 1
- Method surface for `Int` uses deprecated string addition with Scala 3.4.1
- Unable to get a surface of a class with package private members in Scala 3
- Surface.of sometimes fails for classes using generic types on parameters
- Surface.of fails with error for a class containing generic list of tuples in Scala 3
- Unable to get a surface of a class with a protected constructor in Scala 3 HOT 1
- http-client: Support multi-part upload HOT 3
- http: Handle HTTP/2 GOAWAY errors in Java's http client HOT 1
- Cannot get `methodsOf` for some generic types, esp. in Scala 3 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from airframe.