如何使用宏来实现简洁,类型安全,无盒装的枚举?

时间:2022-02-20 16:01:24

I am learning Scala macros and thinking of this as an exercise.

我正在学习Scala宏并将其视为一种练习。

Is it possible to use Scala macros to write down something like this (maybe not exactly this concrete syntax, but something without boilerplate)

是否可以使用Scala宏来写下这样的东西(可能不是这个具体的语法,但没有样板的东西)

enum DayOfWeek = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday

And have it macro-expand to something like this?

并将它宏观扩展到这样的东西?

class DayOfWeek private (val ord: Int) extends AnyVal {

  def next: DayOfWeek = ord match {
    case 0 => Tuesday
    case 1 => Wednesday
    case 2 => Thursday
    case 3 => Friday
    case 4 => Saturday
    case 5 => Sunday
    case _ => throw Error("Sunday does not have next")
  }

  override def toString: String = ord match {
    case 0 => "Monday"
    case 1 => "Tuesday"
    case 2 => "Wednesday"
    case 3 => "Thursday"
    case 4 => "Friday"
    case 5 => "Saturday"
    case _ => "Sunday"
  }
}

object DayOfWeek {
  def count = 7

  val Monday    = new DayOfWeek(0)
  val Tuesday   = new DayOfWeek(1)
  val Wednesday = new DayOfWeek(2)
  val Thursday  = new DayOfWeek(3)
  val Friday    = new DayOfWeek(4)
  val Saturday  = new DayOfWeek(5)
  val Sunday    = new DayOfWeek(6)
}

And maybe not neccessarily using consecutive integers to represent enumerations. For example, with some flag, we can have enums with no more than 32 or 64 alternatives be represented as bits, and have an efficient unboxed implementation of its set (as Int or Long).

并且可能不一定使用连续的整数来表示枚举。例如,对于某些标志,我们可以将不超过32或64个替代的枚举表示为位,并且具有其集合的有效未装箱实现(如Int或Long)。

Another compelling reason for having something like this is we can also customize different aspects for slightly different flavors of enum, for example, above, we could have provided some parameter to enum so that next cycles around instead of erroring on Sunday.

有这样的东西的另一个令人信服的理由是我们也可以针对略微不同的enum风格定制不同的方面,例如,上面,我们可以为枚举提供一些参数,以便下一个循环而不是周日的错误。

2 个解决方案

#1


This has already been attempted (by Alois Cochard and Simon Ochsenreither) in a way that would be compatible with Java enums, but IIRC the Scala compiler would not emit some required flag into bytecode, and the project got stuck. The latest version I'm aware of is here.

这已经尝试(由Alois Cochard和Simon Ochsenreither)以与Java枚举兼容的方式,但是IIRC Scala编译器不会向字节码中发出一些必需的标志,并且项目卡住了。我知道的最新版本就在这里。

I'm not sure whether it's of use for your idea. You'll need to work on the syntax, since I'm not sure that will even parse, and you probably need some advanced flavor of macros (scala meta, for instance) to pull it off.

我不确定它是否适用于你的想法。你需要处理语法,因为我不确定它甚至会解析,你可能需要一些高级的宏(例如scala meta)来实现它。

#2


So from Rex Kerr's answer, I figured out I needed to look at StaticAnnotation, then made a simplistic implementation here. For my personal usage, I don't see the need to maintain nice interoperability with Java, but there I go.

所以从Rex Kerr的回答中,我发现我需要查看StaticAnnotation,然后在这里做了一个简单的实现。对于我个人的用法,我认为不需要保持与Java的良好互操作性,但我去了。

(Allow me to be shameless and accept my own answer ^^)

(请允许我无耻并接受我自己的答案^^)

#1


This has already been attempted (by Alois Cochard and Simon Ochsenreither) in a way that would be compatible with Java enums, but IIRC the Scala compiler would not emit some required flag into bytecode, and the project got stuck. The latest version I'm aware of is here.

这已经尝试(由Alois Cochard和Simon Ochsenreither)以与Java枚举兼容的方式,但是IIRC Scala编译器不会向字节码中发出一些必需的标志,并且项目卡住了。我知道的最新版本就在这里。

I'm not sure whether it's of use for your idea. You'll need to work on the syntax, since I'm not sure that will even parse, and you probably need some advanced flavor of macros (scala meta, for instance) to pull it off.

我不确定它是否适用于你的想法。你需要处理语法,因为我不确定它甚至会解析,你可能需要一些高级的宏(例如scala meta)来实现它。

#2


So from Rex Kerr's answer, I figured out I needed to look at StaticAnnotation, then made a simplistic implementation here. For my personal usage, I don't see the need to maintain nice interoperability with Java, but there I go.

所以从Rex Kerr的回答中,我发现我需要查看StaticAnnotation,然后在这里做了一个简单的实现。对于我个人的用法,我认为不需要保持与Java的良好互操作性,但我去了。

(Allow me to be shameless and accept my own answer ^^)

(请允许我无耻并接受我自己的答案^^)