One of my more favorite features of C# is the use of FlagsAttribute. If you’re not familiar with the concept, [Flags] allows you to treat an integral enum type as a bitmask. In other words, you can store 64 different on/off settings in a 64-bit integer.
The example from MSDN shows the storage of Tuesday + Thursday in a variable called meetingDays:
[Flags]
enum Days2
{
None = 0x0,
Sunday = 0x1,
Monday = 0x2,
Tuesday = 0x4,
Wednesday = 0x8,
Thursday = 0x10,
Friday = 0x20,
Saturday = 0x40
}
class MyClass
{
Days2 meetingDays = Days2.Tuesday | Days2.Thursday;
}
In C#, the operators are built into the compiler, so meetingDays becomes an integer with the 3rd and 5th bits set. With too many flags options, it can become difficult to keep track of the values, so I prefer using a left shift operator:
[Flags]
enum Days2
{
None = 0,
Sunday = 1 << 0,
Monday = 1 << 1,
Tuesday = 1 << 2,
Wednesday = 1 << 3,
Thursday = 1 << 4,
Friday = 1 << 5,
Saturday = 1 << 6
}
class MyClass
{
public Days2 meetingDays = Days2.Tuesday | Days2.Thursday;
}
Because Kotlin doesn’t support flags directly, to add programmatic support for this, we’ll need to implement some operators or infix operators. Unfortunately, as of right now Kotlin doesn’t support overloading the bitwise OR (|) operator. A workaround is to use a specialized operator that means “set”, or to explicitly use the named “or” operator.
The below example doesn’t support all bitwise operators, but it should be enough to get a project moving forward with a generalized Flags implementation.
fun main(args : Array<String>){
val mask: BitMask = ParameterFeature.Path +
ParameterFeature.Query +
ParameterFeature.Header;
val enabled = enabledValues<ParameterFeature>(mask)
println("flags enabled: $enabled")
println("flags disabled: ${enumValues<ParameterFeature>().filterNot { enabled.contains(it) } }")
println("mask hasFlag ParameterFeature.Query: ${mask hasFlag ParameterFeature.Query}")
println("mask hasFlag ParameterFeature.Body: ${mask hasFlag ParameterFeature.Body}")
}
An interesting point to notice here is that setting multiple flags results in a BitMask instance rather than a ParameterFeature instance as you’d have in C#. Another point is that, like C#, there’s no compiler control that requires each enum entry to be a single bit or even to be contiguous bits. I actually prefer the Kotlin syntax here for shifting a bit to the left: 1 shl 1.
The implementation of a flag would look like this:
enum class ParameterFeature(override val bit: Long) : Flags {
Undefined(0),
Path(1 shl 0),
Query(1 shl 1),
Header(1 shl 2),
Body(1 shl 3),
FormUnencoded(1 shl 4),
FormMultipart(1 shl 5);
}
Notice how this requires extending from the Flags interface and overriding the bit constructor parameter. Unlike C#, which allows you to define flags using any integral type, my prototype is limited to Long.
Everything else is handled by jugging between the two types of Flags and BitMask using a combination of operators and infix functions, for example:
infix fun Flags.and(other: Long): BitMask = BitMask(bit and other)
infix fun <T: Flags> Flags.or(other: T): BitMask = BitMask(bit or other.bit)
Here’s the complete example as a gist: