Flags
flags declares a set of constants that combine bitwise. Members are physically int bits, but combinations within the same declaration keep the flags static surface, and the method surface is available directly.
Declaration and Combination
flags Perm
{
Read,
Write,
Execute = 16,
}
val p = Perm.Read | Perm.Write;
print(p);
print(p.Has(Perm.Read), p.Has(Perm.Execute));3
True FalseValueless members auto-increment by powers of two (the first member is 1, each following member doubles), and implicit members after an explicit value start from “the previous explicit value doubled”. | combines members of the same declaration into the flags static surface; Has(member) tests containment.
Set, Clear, Toggle
All three methods return a new flags value; the original is untouched:
val full = p.Set(Perm.Execute);
print(full.Has(Perm.Execute), p.Has(Perm.Execute));
val less = full.Clear(Perm.Write);
print(less, less.Toggle(Perm.Read));True False
17 16Set adds a bit, Clear removes one, Toggle flips one. less is Read | Execute (1 + 16) and prints 17; toggling Read again leaves 16.
Converting to and from int
Flags are physically int bits, and conversion is implicit in both directions:
val n: int = p;
print(n);
val q: Perm = 3;
print(q, q.Has(Perm.Read | Perm.Write));3
3 TrueFlags built from an int still carry the full method surface. Bitwise operations across different flags types are treated as int bitwise operations; the result no longer has the flags surface.
The Exact Rules for Implicit Increment
Valueless members increment by powers of two; after an explicit value, implicit members continue from “the previous explicit value doubled”:
flags Mode
{
A,
B,
C = 10,
D,
}
print(Mode.A, Mode.B, Mode.C, Mode.D);1 2 10 20A and B get 1 and 2, C is explicitly 10, and D starts at 20. Member values must be compile-time integer constants; duplicate values are legal aliasing (two names on the same bit).
Aliasing and Cross-Type Operators
int converts implicitly to flags, and the result keeps the full method surface. Bitwise operations between two different flags types degrade to int, and the result no longer has the flags surface:
flags Other
{
X,
}
val aliasF: Mode = 1;
print(aliasF.Has(Mode.A), aliasF.Has(Mode.B));
val cross = Mode.A | Other.X;
print(cross);True False
1aliasF is built from int 1 and is equivalent to Mode.A: Has(Mode.A) holds and Has(Mode.B) does not. cross is already a plain int; to get the flags surface back, annotate the type as Mode explicitly.
Notes
- Printing a flags value outputs the number directly; if you need names, decompose the bits yourself.
Hasaccepts combined bits (q.Has(Perm.Read | Perm.Write)tests that both bits are set).- All bitwise operators
& | ^ ~ << >>work; their semantics are exactly int bitwise operations. Set/Clear/Toggleall have value semantics: they return new flags values and are commonly chained for configuration.
