optics-dev / Monocle

Optics library for Scala
https://www.optics.dev/Monocle/
MIT License
1.66k stars 206 forks source link

Mononcle doesn't support `@Lenses` in Scala3. #1337

Open dev-jiwonyang opened 1 year ago

dev-jiwonyang commented 1 year ago

I used @Lenses macro annotation in Scala2, but I can't find @Lenses in Monocle 3.1.0 with Scala3. Does anyone know anything about this issue? Does Monocle have any plan to support @Lenses in Scala3?

cquiroz commented 1 year ago

Scala 3 doesn't support (yet) macro annotations such as @Lenses. Until such support is provided it won't be possible to support @Lenses

armanbilge commented 1 year ago

Coming soon though!

nkgm commented 1 year ago

I am no expert, but following these PR's I'm under the impression this is still impossible under Scala3 post-typer Macro Annotations. I'm sure there will be other similar opportunities under the new Scala3 metaprogramming facilities, but in any case, Macro Annotations have been merged since 3.3.0-RC2 so hopefully we'll have a definitive answer soon.

nafg commented 1 year ago

@nkgm correct. I think a more fruitful approach would actually be to lobby for inclusion in Scala proper. It doesn't mean including an optics library, just the following:

A. A case class or something basically of the form case class Field[A, B](get: A => B, set: B => A => A). Although I would like for it to also include name: String. B. Some syntax (e.g. a macro annotation or something else) that gets the compiler to generate a bunch of these for you

A macro that generates a single one would be very easy to write, so there's no need for them to special-case that.

Meanwhile, the recommended migration path is to use the focus macros instead. Although, I wonder if there's a performance effect, since lenses as fields would reuse the same instance.

yilinwei commented 11 months ago

I think it's been enough time that we need to start looking into alternatives for folks to migrate.

Off the top of my head I know that simulacrum looked into using scalafix rules to do this.

nafg commented 11 months ago

Maybe some way with named tuples?

Or like I said before, just start a pre-SIP.

Code gen seems dubious since it belongs in a companion. Unless I make the companions extend a trait that is generated.

The quick fix approach that was discussed on the forums might be interesting though.

yilinwei commented 11 months ago

I was hoping to do the rewrite pre-compliation so it wouldn't be in your source tree; for all intents and purposes it would just allow the same source to be used for Scala 2/3.

What quick fix approach were you referencing?

nafg commented 11 months ago

The idea discussed here: https://contributors.scala-lang.org/t/scala-3-macro-annotations-and-code-generation/6035

nafg commented 11 months ago

How can code not in the source tree be part of the companion object of code that is

yilinwei commented 11 months ago

Some build tools (dune from the OCaml ecosystem iirc) distinguish the source tree to the sources compiled by the compiler - the first step is to symlink the files into a target directory before compilation and run the compiler on those sources. Generated sources are also written directly to this directory and the compiler essentially runs on this folder.

In this build model, it's quite trivial to rewrite the sources before the compile step - I'm not entirely sure whether sbt or mill follows the same model. If it didn't, we could do something a little bit more involved where we filter the sources which use the trait and instead dump an edited source in the managedSources/generatedSources.

The idea would be to look for the @Lens marker trait and rewrite an existing companion object to add some extra lines of code to synthesize the required companion objects. That way, the semantics are the same for Scala 3/Scala 2 and it will ease migration until a better alternative emerges.