enumeratum icon indicating copy to clipboard operation
enumeratum copied to clipboard

Scala 3: What should be done

Open lloydmeta opened this issue 4 years ago • 17 comments

Looking at Scala 3, the enumerations built into the language look pretty good.

The questions are

  1. What should enumeratum look like in a Scala 3 world?
    • What problems are we trying to solve? The problems with Scala 2 enums were pretty obvious, which led to the core of this lib

lloydmeta avatar Feb 03 '21 09:02 lloydmeta

The first step towards Scala 3 for any real-world project is cross-compilation between Scala 2.13/Scala 3. Most of the OSS libs added Scala 3 to their cross-builds.

IMO, this will be a status quo for the next few years. Only then we'll drop Scala 2 support and migrate to the new enums.

Thus, the Enumeratum macros should be ported.

catostrophe avatar Feb 03 '21 09:02 catostrophe

My 2c: we use Enumeratum mostly to model things that map to postgres enums, with a nice benefit of being able to have safe withName* overloads for decoding.

I'm not sure if Scala 3 enums has support for this...

hmemcpy avatar Feb 03 '21 09:02 hmemcpy

The first step towards Scala 3 for any real-world project is cross-compilation between Scala 2.13/Scala 3. Most of the OSS libs added Scala 3 to their cross-builds.

IMO, this will be a status quo for the next few years. Only then we'll drop Scala 2 support and migrate to the new enums.

Thus, the Enumeratum macros should be ported.

Fair point; have you checked that the macro(s) in its current form can be ported? A PR would be welcome to start concrete discussions as well.

lloydmeta avatar Feb 03 '21 09:02 lloydmeta

My 2c: we use Enumeratum mostly to model things that map to postgres enums, with a nice benefit of being able to have safe withName* overloads for decoding.

I'm not sure if Scala 3 enums has support for this...

~I think there is a way of having custom names, based on this doc https://github.com/dotty-staging/dotty/blob/master/docs/docs/reference/enums/desugarEnums.md#translation-of-enums-with-singleton-cases~

Nevermind... looks like support for custom enumLabel was added, then later removed, and I can't figure out how to get it working (Scastie attempts)

lloydmeta avatar Feb 03 '21 09:02 lloydmeta

@lloydmeta I think you were looking for valueOf: scastie session

note avatar Apr 30 '21 10:04 note

@note Hmmm I think that's almost it, but how do we make the second print resolve Red from the custom name "red"?

lloydmeta avatar May 01 '21 12:05 lloydmeta

@lloydmeta Ah, I missed the point that it's about custom names as I mostly looked at scastie session using outdated ofValue. I am not sure about support for custom names in Scala 3 as well

note avatar May 03 '21 15:05 note

Thus, the Enumeratum macros should be ported.

any plan to have the macros ported?

jtjeferreira avatar Jul 02 '21 01:07 jtjeferreira

Thus, the Enumeratum macros should be ported.

any plan to have the macros ported?

The plan is:

  1. Come up with a working prototype for the macro, either on Scastie or a PR
    • In particular, the enclosingModule function is basically gone with no replacement in Scala 3 AFAIK, so we can't explore inside a "scope" for findValues https://github.com/lloydmeta/enumeratum/blob/dddab99216fed3b5443d4698893dfc1f4877e7c1/macros/src/main/scala/enumeratum/EnumMacros.scala#L79-L95
  2. Implement the prototype.

Currently stuck on (1).

lloydmeta avatar Jul 02 '21 07:07 lloydmeta

In particular, the enclosingModule function is basically gone with no replacement in Scala 3 AFAIK

There is some dotty/scala3 issue about that?

Alternatively, could we change the signature of findValues so we can pass that enclosingModule, like:

sealed abstract class Light extends EnumEntry
case object Light extends Enum[Light] {
  val values = findValues[Light]
  case object Red   extends Light
  case object Blue  extends Light
  case object Green extends Light
}

Sorry if this, does not make sense at all, because I am not very familiar with macros...

jtjeferreira avatar Jul 02 '21 09:07 jtjeferreira

In particular, the enclosingModule function is basically gone with no replacement in Scala 3 AFAIK

There is some dotty/scala3 issue about that?

Nope. I think it was a conscious decision/redesign around the Scala 3 macro system.

Alternatively, could we change the signature of findValues so we can pass that enclosingModule, like:

sealed abstract class Light extends EnumEntry
case object Light extends Enum[Light] {
  val values = findValues[Light]
  case object Red   extends Light
  case object Blue  extends Light
  case object Green extends Light
}

It's not so much a problem of having to provide the type param (the compiler can figure that out in the same way I think), just AFAICT, the functionality to explore the object scope is gone.

I think one way might be to change it into something that works on a defined scope like so, but it's not backwards-source compatible.

sealed abstract class Light extends EnumEntry
@findEnumValues // or find members at this point
case object Light extends Enum[Light] {
   case object Red   extends Light
   case object Blue  extends Light
   case object Green extends Light
}

To be clear: the only helpful next step in this issue is for someone to come forth with a working prototype.

lloydmeta avatar Jul 04 '21 05:07 lloydmeta

Actually it's possible to access "enclosingModule" via Symbol.spliceOwner.owner...owner. Here is a prototype: Scastie

marq avatar Jul 20 '21 17:07 marq

@marq Thanks so much for that (even including a Scastie!). I'm very unfamiliar with the new Scala 3 macros (and it seems like the documentation may not be the most complete ?) so I'm having a hard time and would really appreciate the help of those who are such as yourself 🙏🏼

To provide a clean sandbox to hack around, I created a separate repo to explore porting macros to Scala 3 some more, and split it into 3 issues, one for each main macro method:

https://github.com/lloydmeta/mune/issues

Since you've done most of the work, https://github.com/lloydmeta/mune/issues/1 is basically done, but I'm running into some errors on https://github.com/lloydmeta/mune/issues/2 (materialising the companion object of an enum entry type); wondering you can spot anything wrong there. https://github.com/lloydmeta/mune/issues/3 is also a TODO.

lloydmeta avatar Jul 23 '21 08:07 lloydmeta

Hi @lloydmeta ! It seems that enumeratum still provides stuff that native scala3 enums don't, does it? Would be great to have I guess. Are you actively working on that?

mauhiz avatar Dec 06 '21 02:12 mauhiz

Hi @lloydmeta ! It seems that enumeratum still provides stuff that native scala3 enums don't, does it? Would be great to have I guess. Are you actively working on that?

Hey there @mauhiz , yeah, it turns out there are some things missing from the official Scala 3 enums that is supported here. I agree it would be nice to have, but I got stuck in my attempt to port the macro to Scala3 (see https://github.com/lloydmeta/enumeratum/issues/300#issuecomment-885486518). I'm not actively working on it and any help would be appreciated :)

lloydmeta avatar Dec 06 '21 04:12 lloydmeta

Thanks to @tpunder, the Scala 3 port is mostly complete.

The remaining bit is https://github.com/lloydmeta/mune/issues/3, which involves porting over this bit

https://github.com/lloydmeta/enumeratum/blob/d91d191cd11a630cc4d1b7cc6c82decdf436ac1b/macros/src/main/scala/enumeratum/ValueEnumMacros.scala#L85-L117

I think the main tricky bit is finding how to destructure the different ways to declare value in a Scala 3 world.

lloydmeta avatar Jan 30 '22 04:01 lloydmeta

@lloydmeta this might be helpful: https://github.com/theiterators/kebs/blob/master/macro-utils/src/main/scala-3/pl/iterators/kebs/macros/enums/EnumEntryMacros.scala

luksow avatar May 17 '22 18:05 luksow

@lloydmeta any update on this? Thanks

coreywoodfield avatar Nov 02 '22 22:11 coreywoodfield

There's a PR open (https://github.com/lloydmeta/enumeratum/pull/349) that I've slowly been reviewing over iterations.

lloydmeta avatar Nov 03 '22 00:11 lloydmeta

Done.

lloydmeta avatar Dec 03 '22 18:12 lloydmeta

First off, thank you.

Second, I notice that there are two separate libraries: one for scala 3 and one for scala 2. Is there any plan or desire to have a mixed library that can be used in scala 3 and in scala 2? This would be useful for large projects that use enumeratum that want to migrate to scala 3 gradually. I think the alternatives would be either migrating all at once, or depending on both libraries, and I don't know how well depending on both libraries would work out in practice (I imagine not well)

coreywoodfield avatar Dec 23 '22 00:12 coreywoodfield

Is there any plan or desire to have a mixed library that can be used in scala 3 and in scala 2

There's no plan, but it does sound desirable; do you want to give it a stab ?

lloydmeta avatar Dec 23 '22 00:12 lloydmeta

Sure, I'll take a stab at it

coreywoodfield avatar Dec 29 '22 20:12 coreywoodfield

I have something that I think would work, but there's a bug in the macro mixing functionality that is triggered by using type parameters from the class level in a scala 2 macro call. So I don't think any further progress can be made until that's fixed.

branch: https://github.com/lloydmeta/enumeratum/compare/master...lucidsoftware:enumeratum:mix-scala-2-and-3-macros scala bug: https://github.com/lampepfl/dotty/issues/16630

coreywoodfield avatar Jan 07 '23 00:01 coreywoodfield