Seeking Feedback : make quotes.reflect.* top-level definitions #23330
+3,245
−0
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Precursor : The power of the scala 3 macro system is AMAZING. By far the best metaprogramming experience I have had. That being said, there are a few usability issues because of the way the API is defined that makes it hard to work with, that this proposal aims to address.
Problem Statement
As a user of the
Quotes
API, the nesting of all the types within theQuotes.reflect
module makes the API very difficult to use.Any program of any significance ends up doing something like
This is NOT because its an issue to have a
(using Quotes)
everywhere, its an issue because all the types are within the quotes object itself. So, unless you have some outer scopedQuotes
, you cant do something like:You can get around this by doing something like
but then the nesting of types will make working with different instances very difficult.
It can be seen in the
Quotes.scala
file, which is over 5.5k lines long, and this is exactly what projects that end up working with the quotes API end up looking like, huge files, because the structure of the API makes it very difficult, if not sometimes impossible to split into separate files, without having to do all sorts ofasInstanceOf
in order to get the compiler to comply.Proposed Solution
then you can use this at a top level like
The core principle here is that you need an instance of
Meta
in order to create any of these types, but they are not scoped to an individual instance, like withQuotes
.Potential Pushback
As long as the
Quotes
API is backwards compatible after such a change, the only downside I can think of with this change is that all types are not scoped to the same exact instance, if that was important, which based on my impression, does not seem to be the case. The only way you can get an instance ofQuotes
is the entry-point to a macro, so I dont anticipate this being an issue.Also , when you are quoting and splicing, it is my understanding that those functions are creating nested instances of
Quotes
. It therefore seems far more detrimental to have an API that encourages use like this:Ive seen this paradigm used in other helper libs like
magnolia
, and used it many times in my own projects, and not once has it caused an issue, which tells me that its really not that important that these instances are scoped. It seems to be an unfortunate design decision, with the aim of abstracting away the actual compiler types under the hood. It is entirely possible to achieve this withtrait
s that are not implemented until downstream, but the user gets normal types to work with.Compatibility
It seems like it should be possible to deprecate the
reflect
module, and have all the implementations within it defer to theinternal: Meta.Internal
functions. I believe this would be considered binary compatible? Also, with having an instance ofQuotes
at the entry-point of your macro,Quotes
is aMeta
, and you can therefore easily use the proposed API.