Search code examples
c#scalaenums

How does C# Implementation of Flagged Enum work and how can Scala solve the same issue?


I am trying to understand how Flagged Enums work in C# and how I can implement similar functionality in Scala.

I was surprised that Enum, which is a special data type that enables a variable to be a set of predefined constants can be actually a combination of enums and compile in C# as follows:

[Flags]
enum Permissions
{
  None = 0,
  Read = 1,
  Write = 2,
  Execute = 4
}
// ...

Permissions x = Permissions.Read | Permissions.Write;  # How | Is Implemented???

However, when attempting to create an enum or an ADT in Scala, I could not implement the | operator since I was unable to construct new Permissions out of this and other: Permissions.

Currently, I am aware of libraries such as Enumeration and Enumeratum, as well as ADTs and Scala 3, but I have not found a way to create Flagged Enums using these methods.

Specifically, I would like to know how the | operator works with Enums in C# and how this can be achieved in Scala.

Can someone explain the implementation of Flagged Enums in C# and provide some guidance on how to achieve similar functionality in Scala?

Update: https://gist.github.com/ZviMints/e0edaabb1df169233cdf746e26fb1257


Solution

  • Unlike Scala enums, which as far as I know can only have a fixed number of instances. C# enums are just thin wrappers around integer types. There is nothing preventing anyone from creating a Permissions wrapping the value 12334567 (not that this makes sense):

    var p = (Permissions)1234567;
    

    | is just bitwise OR on the wrapped integer values. The specification specifies this here:

    Every enumeration type E implicitly provides the following predefined logical operators:

    E operator &(E x, E y);
    E operator |(E x, E y);
    E operator ^(E x, E y);
    

    The result of evaluating x «op» y, where x and y are expressions of an enumeration type E with an underlying type U, and «op» is one of the logical operators, is exactly the same as evaluating (E)((U)x «op» (U)y). In other words, the enumeration type logical operators simply perform the logical operation on the underlying type of the two operands.

    The "underlying type" here is an integer type. By default, it is int.

    You can easily implement something similar in Scala, by writing a wrapper around Int. Add an operator overload for |, and some named constants in the companion object.

    // this is just the general idea - excuse me if this is not idiomatic
    // I'm not very familiar with Scala
    final class Permissions private(private val value: Int) {
      def |(other: Permissions) = new Permissions(value | other.value)
      def hasFlag(flag: Permissions) = (value & flag.value) > 0
    }
    object Permissions {
      val None = new Permissions(0)
      val Read = new Permissions(1)
      val Write = new Permissions(2)
      val Execute = new Permissions(4)
    }
    
    // this works!
    val permission = Permissions.Read | Permissions.Write
    println(permission.hasFlag(Permissions.Read)) // true
    println(permission.hasFlag(Permissions.Write)) // true
    println(permission.hasFlag(Permissions.Execute)) // false
    

    C# enums with [Flags] also have a custom implementation of ToString, which outputs all the flags the value has. You can write a similar toString implementation in Scala.