On this page

11. Enums, flags and one-of types

11.1 Enum declarations and contextual members

CS-ENUM-001. enum Name ... end enum declares named values. Explicit values may be authored with Member = value. Ordinary integral enums use a compatible CLR enum representation; richer underlying values, such as enum Status as String, require a strongly typed representation retaining the language contract. Enum values expose their declared Name, Value and Attributes through the applicable language/library projection.

enum PaymentStatus
    Draft = 0
    Submitted = 1
    Approved = 2
    Declined = 3
end enum

let status as PaymentStatus = Submitted

CS-ENUM-002. An unqualified enum member is resolved contextually only when one required enum type is unambiguous. A typed target, enum comparison, uniquely bound parameter or target-typed collection may provide that context. The compiler must not search all visible enums to guess a type for let status = Submitted. Fully qualified members remain valid. Member lookup is case-insensitive.

CS-ENUM-003. String-to-enum conversion resolves declared names case-insensitively. Numeric conversion to a non-flags enum requires a declared member with that value; an unknown value fails. Flags conversion instead accepts any bit pattern fitting its storage, preserving unknown bits. Direct imported CLR operations retain their native behavior; DirectSharp conversion checks do not rewrite every cast in a referenced library.

11.2 Flags

CS-FLAG-001. flags enum is integral-backed. Omitted ordinary flag values receive successive powers of two; a zero member is never invented. Explicit values and named combinations using bitwise operators are permitted.

flags enum Permission
    None = 0
    Read
    Write
    Approve
    ReadWrite = Read | Write
end enum

Read, Write and Approve have values 1, 2 and 4. Rich/String-valued enums do not acquire bit semantics by applying this modifier.

CS-FLAG-002. has_flag Flag tests flag presence; has_not_flag Flag negates it. A multi-flag Boolean condition requires parentheses: has_flag (Read and Write) requires both, and has_flag (Read or Write) requires either. The negative form negates the complete condition, so has_not_flag (Read and Write) means not both and has_not_flag (Read or Write) means neither.

CS-FLAG-003. set_flag, clear_flag and toggle_flag transform flags. Multiple flags use a parenthesized comma-separated list. An assignable left operand is evaluated once, updated, and yields its resulting value; a nonassignable expression yields the transformed value without changing a source location. Ordinary bitwise operations remain valid.

permissions set_flag (Read, Write)
permissions clear_flag Approve

if permissions has_flag (Read and Write) then
    SaveDraft()
end if

The fragment assumes a Permission-valued writable permissions local and an available SaveDraft action. Equivalent mask operations for independent flags are:

permissions |= Permission.Read | Permission.Write;
permissions &= ~Permission.Approve;
if ((permissions & Permission.Read) == Permission.Read
    && (permissions & Permission.Write) == Permission.Write)
    SaveDraft();

A suspicious constant mask may warrant an informational diagnostic; valid bitwise expressions are not made illegal by that suggestion. No has_any_flag/has_no_flag predicate family is defined.

11.3 One-of contracts

CS-ONEOF-001. type Name as one of ... end type lists existing alternative types. A value of a listed alternative may be returned or assigned through the one-of contract without an explicit wrapper. Type tests and narrowing use the ordinary mechanisms; no separate case-construction grammar is introduced.

data PaymentApproved
    TransactionId as String
end data

data PaymentDeclined
    Reason as String
end data

type PaymentResult as one of
    PaymentApproved
    PaymentDeclined
end type

action DecidePayment(approved as Boolean)
    returns PaymentResult

    if approved then
        return new PaymentApproved("TX-1042")
    end if
    return new PaymentDeclined("Credit limit exceeded")
end action

CS-ONEOF-002. The C# backend requires a target supporting the corresponding native union capability; it must not silently invent a proprietary union runtime when the target cannot represent it. No additional DirectSharp-specific exhaustiveness guarantee is imposed. Expression-select still requires complete normally producing paths under chapter 7.

Reject unresolved alternative types, incompatible values outside the alternatives, invalid contextual enum inference, incompatible flags backing types and out-of-storage conversions. Unsupported backend representation is a compatibility diagnostic, not permission to pretend the type is Object.


Specification contents · Previous: 10. Inheritance and interfaces · Next: 12. Contracts