Building on the previous work of using a Flag interface, this PR changes all the XFlags type aliases from being Int to being Flag<XFlags>. That, combined with a private value class Flags and a value class FlagArray, allows using type-safe flag combinations everywhere, while still having the ever-useful and, or, wo, has, etc methods.
While implementing this, I genuinely found multiple places where the code was using the wrong enum type of Flag or was checking if flags of totally separate types were equal. It was hence helpful in catching those bugs and remedying them quickly. This also removed a lot of unnecessary range checks we were doing on ints.
The only downside of using this PR is that checking flags for equality using == and != is broken. This is because you can't override equals in enums nor in value classes. For now, I added infix fun eq/notEq to mitigate that problem. However, a more intrusive solution (that will fix == checks) is to convert all the Flag enums to sealed classes (This is simply an IDE intention and so it's very automatic) with a base class that has equals overridden, and change value class Flags to a non-value class. Note that in Kotlin 1.9.0 value classes willbe able to override equals. I'm not sure whether the current eq/notEq approach is too finicky, but it surely is less error-prone than comparing raw Ints.
Finally, this PR also introduces a useful MutableReference type that extends KMutableProperty0. That type might be the beginning of relying less on global mutable vars like _b and friends, and instead created MutableReferences locally., but that shall come in another PR.
This is quite a big refactoring...
Building on the previous work of using a
Flag
interface, this PR changes all theXFlags
type aliases from beingInt
to beingFlag<XFlags>
. That, combined with aprivate value class Flags
and avalue class FlagArray
, allows using type-safe flag combinations everywhere, while still having the ever-usefuland
,or
,wo
,has
, etc methods.While implementing this, I genuinely found multiple places where the code was using the wrong enum type of Flag or was checking if flags of totally separate types were equal. It was hence helpful in catching those bugs and remedying them quickly. This also removed a lot of unnecessary range checks we were doing on ints.
The only downside of using this PR is that checking flags for equality using
==
and!=
is broken. This is because you can't overrideequals
in enums nor invalue class
es. For now, I addedinfix fun eq/notEq
to mitigate that problem. However, a more intrusive solution (that will fix==
checks) is to convert all the Flag enums tosealed class
es (This is simply an IDE intention and so it's very automatic) with a base class that hasequals
overridden, and changevalue class Flags
to a non-value class. Note that in Kotlin 1.9.0value class
es will be able to overrideequals
. I'm not sure whether the currenteq/notEq
approach is too finicky, but it surely is less error-prone than comparing rawInt
s.Finally, this PR also introduces a useful
MutableReference
type that extends KMutableProperty0. That type might be the beginning of relying less on global mutable vars like_b
and friends, and instead createdMutableReference
s locally., but that shall come in another PR.