-
Notifications
You must be signed in to change notification settings - Fork 1.1k
DRAFT (seeking feedback) : started refactoring of Quotes.reflect into a top level package #24833
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| trait BooleanConstant private[compiletime] () extends Constant { | ||
|
|
||
| override def value: Boolean | ||
|
|
||
| } | ||
| object BooleanConstant { | ||
|
|
||
| def quoted(using quotes: Quotes): BooleanConstant.Module = quotes.reflectV2.BooleanConstant | ||
| given moduleConversion: (quotes: Quotes) => Conversion[BooleanConstant.type, BooleanConstant.Module] = _ => quotes.reflectV2.BooleanConstant | ||
|
|
||
| def unapply(x: BooleanConstant): Some[Boolean] = Some(x.value) | ||
|
|
||
| trait Module private[compiletime] () { | ||
| def apply(x: Boolean): BooleanConstant | ||
| def make(x: Boolean): BooleanConstant | ||
| } | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public definition of BooleanConstant + BooleanConstant.Module
as long as you have a given Quotes, can be used at the top level as such:
def myFunction(bool: Boolean)(using Quotes): Nothing = {
val ex1: BooleanConstant = BooleanConstant.quoted.make(bool)
val ex2: Constant = BooleanConstant.make(bool)
???
}Thanks to the Conversion, we can treat object BooleanConstant exactly like we would expect to treat a normal companion object, but we still achieve the desired obfuscation of the private API.
| type BooleanConstant = BooleanConstantImpl | ||
| final case class BooleanConstantImpl(value: Boolean) extends ConstantImpl, pub.BooleanConstant | ||
| object BooleanConstantImpl { | ||
|
|
||
| object Module extends pub.BooleanConstant.Module { | ||
| override def apply(x: Boolean): BooleanConstant = BooleanConstantImpl(x) | ||
| override def make(x: Boolean): BooleanConstant = BooleanConstantImpl(x) | ||
| } | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we are able to implement BooleanConstant and BooleanConstant.Module with BooleanConstantImpl and BooleanConstantImpl.module. The impl of this one is dead simple, so its an object Module, but there are other such cases with final class Module(using val ctx: Context) extends pub.Ex.Module { /* ... */ }.
| trait Quotes { | ||
|
|
||
| lazy val reflectV2: pub.reflect.Module | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quotes exposes top level defined reflect.Module
| object reflect { | ||
|
|
||
| trait Module { | ||
|
|
||
| lazy val Symbol: pub.Symbol.Module | ||
| lazy val Position: pub.Position.Module | ||
| lazy val SourceFile: pub.SourceFile.Module | ||
| lazy val Signature: pub.Signature.Module | ||
| lazy val Flags: pub.Flags.Module | ||
|
|
||
| lazy val Selector: pub.Selector.Module | ||
| lazy val SimpleSelector: pub.SimpleSelector.Module | ||
| lazy val RenameSelector: pub.RenameSelector.Module | ||
| lazy val OmitSelector: pub.OmitSelector.Module | ||
| lazy val GivenSelector: pub.GivenSelector.Module |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reflect.Module contains implementations of all the *.Module
Context
I opened a draft MR a while back proposing something like this, and was told it would need some proving out. I have built a full blown auto-derived SQL codec + scala DSL + migration library on top of a wrapper I wrote with the same principles in this MR (except it wraps
Quotesone level out instead of directly wrapping the compiler internals like this MR begins to do).I am hoping to receive feedback of the receptiveness of such a change. If it will be received and used if working, I will happily see it through to a complete and working state.
Problem with Quotes.reflect.* Currently
This is a
5,500that is extremely difficult for anyone to read, and feelsnothinglike any interface I have used in 5 years of Scala development, at least from a "how are things defined, and how can I find what I need" perspective. On top of this, the way the interface is defined is very confusing to the IDE, making an already very complex domain even harder, borderline impossible to get anything done. I have built an entire wrapper around this API, and have been diving into this domain for 6 months now, and I still can not get anything done in the few times I try to use the API directly without the wrapper.Core Design
I commented out a few highlights, but the TLDR is you have a
Example,Example.Module,ExampleImplandExampleImpl.Module. The only way to get an instance ofExample.Moduleis viaquotes.reflectV2.Example, although the canonical way to get that is viaExample.quoted(using quotes).myAbcorExample.myAbc(viaExample.moduleConversion).Benefits
5,500+ line filethat looks nothing like they have ever seen beforego to definition+ completeExample.myA(completesmyAbc)