Open iTakeshi opened 6 years ago
Do you have examples of what you would like to accomplish?
I want use this feature to generate json formatter for all case classes in a playframework application
example:
// original
@genFormatters package object formatters { // NOTE: @annotation for a package object is not allowed
case class A(id: Int, name: String)
case class B(id: Int, name: String, foreignId: Int)
}
// I want it be converted to
package object formatters {
case class A(id: Int, name: String)
object A {
implicit val format = (
(__ / "id").format[Int] and
(__ / "name").format[String]
)(A.apply _, unlift(A.unapply))
}
case class B(id: Int, name: String, foreignId: Int)
object B {
implicit val format = (
(__ / "id").format[Int] and
(__ / "name").format[String] and
(__ / "foreign_id").format[Int]
)(B.apply _, unlift(B.unpply))
}
}
Of course I know I can annotate to case classes one by one, but it is annoying especially when a package has dozens of formatter classes.
The scala language spec does not permit annotations on package objects https://www.scala-lang.org/files/archive/spec/2.11/09-top-level-definitions.html#package-objects
Interestingly however, scala.meta.Pkg.Object
has a field for annotations https://github.com/scalameta/scalameta/blob/d4822c8758e108bc1825c0f0f6856f86019c7262/scalameta/trees/shared/src/main/scala/scala/meta/Trees.scala#L314 but it's not used in the parser https://github.com/scalameta/scalameta/blob/d4822c8758e108bc1825c0f0f6856f86019c7262/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala#L3402
There is no requirement to only expand annotations in scalagen, we can come up with any convention we like. For example, in this json formatters case it might make sense to configure it in the build that all case classes in a given package or project should get a json formatter.
I see, that's a limitation of Scala itself. I thought it came from scala.meta because Pkg.Object has mods
, as you mentioned.
There is no requirement to only expand annotations in scalagen
I agree, and your suggestion that
configure it in the build that all case classes in a given package
seems nice. Should this kind of configuration be managed by a SBT plugin?
Yeah, we could even explore expanding based on comments.
Provided the name is fully qualified (_root_
would not be necess thoughary)
// Apply Generator: org.scalagen.Formatting
package object formatters { // NOTE: @annotation for a package object is not allowed
case class A(id: Int, name: String)
case class B(
Although in that case it would be way easier to do the following:
package object formatters extends formatters
@genFormatters trait formatters {
case class A(id: Int, name: String)
case class B(id: Int, name: String, foreignId: Int)
}
There are plenty of other ways too, outside of annotations. We can definately explore those. The annotation based infrastructure is being written first as that is what most of the community is used to.
Note: Typeclass derivation is very high on my agenda. Especially for AST code (which Json effectively is).
I plan to write derivations for Eq
, Show
, Traverse
and others.
Yeah, we could even explore expanding based on comments.
I think we should use comments as a last resort. I would prefer to explore build configuration first.
Yeah, we could even explore expanding based on comments.
Actually comments will give us the biggest flexibility (and personally I'm interested in this idea), but it is a kind of double-edged sword. As @olafurpg said, it's better to explore other stuff for this moment.
However, after considering for some time, I doubt that the "build configuration" is the best way, because it forces us to separate generation rules from where it should be applied. One good point of annotation is that it can literally "annotate" where to generate code, and a problem is there are not other suitable syntactic elements which can be put anywhere in code, except for comments.
In scalafix we use comments to suppress false positives instead of annotations precisely because it's possible to comment on any syntax. If you think comments are better then don't mind me! It seems tools like related tools like go generate use comments
With more thought. I'm pretty against comments now... The point of Generators is to extend the functionality of a given tree etc. Personally, I leave comments collapsed in my editor.
An annotation is much more discoverable then a comment.
If a user is exploring an API, he's less likely to check for generator comment, then an annotation. The annotation serves as documentation to the user.
This is the opposite of scalafix. Scalafix targets the author of the code, not the user.
The further away from actual syntax a generator is, the more documentation is required to surround it.
For example:
Annotation Generators:
Comment Generators:
Build Tool Generators:
Hi,
I'm very excited about this project is trying to solve many shortcomings of scala.meta-based macro annotation. One big problem of macro annotation was it couldn't expand
Pkg
andPkg.Object
because we can use@annotation
only forDefn
s. However it seems highly useful if we can generate code based onPkg
s.So, is there any way to bypass this limitation when applying
scalagen
generators? Or, should we request for a modification in specification ofscalameta
itself?