Skip to content

Enumerations#

Code Example

Runnable Example in Jac and JacLib

# Enumerations - Type-safe named constants

import from enum { unique }

# ===== Basic Enums with Integer and String Values =====
enum Color {
    RED = 1,
    GREEN = 2,
    BLUE = 3
}

enum Role {
    ADMIN = 'admin',
    USER = 'user',
    GUEST = 'guest',  # Trailing comma supported
}

with entry {
    print("=== 1. Basic Enums (Integer & String Values) ===");
    print(f"  Color.RED: {Color.RED.value}, Role.ADMIN: {Role.ADMIN.value}");
}

# ===== Forward Declaration with Impl and Decorator =====
@unique
enum Priority;

impl Priority {
    LOW = 1,
    MEDIUM = 2,
    HIGH = 3
}

with entry {
    print("\n=== 2. Forward Declaration with @unique Decorator ===");
    print(f"  Priority.HIGH: {Priority.HIGH.value}");
}

# ===== Enum with Access Modifier =====
enum :protect Permission {
    READ = 'read',
    WRITE = 'write',
    EXECUTE = 'execute'
}

with entry {
    print("\n=== 3. Enum with Access Modifier ===");
    print(f"  Permission.WRITE: {Permission.WRITE.value}");
}

# ===== Enum with Python Code Block and Methods =====
enum HttpStatus {
    OK = 200,
    BAD_REQUEST = 400,
    SERVER_ERROR = 500

    ::py::
    def is_success(self):
        return 200 <= self.value < 300

    def get_category(self):
        if self.value < 300:
            return "success"
        elif self.value < 500:
            return "client_error"
        return "server_error"
    ::py::
}

with entry {
    print("\n=== 4. Enum with Python Code Block (Methods) ===");
    print(f"  {HttpStatus.OK.name}: {HttpStatus.OK.get_category()}, is_success: {HttpStatus.OK.is_success()}");
    print(f"  {HttpStatus.BAD_REQUEST.name}: {HttpStatus.BAD_REQUEST.get_category()}");
}

# ===== Enum Comparison and Functions =====
enum Status {
    PENDING = 0,
    ACTIVE = 1,
    INACTIVE = 2
}

def get_status_message(status: Status) -> str {
    if status == Status.PENDING {
        return "Waiting for approval";
    } elif status == Status.ACTIVE {
        return "Currently active";
    } else {
        return "No longer active";
    }
}

with entry {
    print("\n=== 5. Enum Comparison and Type Safety ===");
    s1 = Status.ACTIVE;
    s2 = Status.ACTIVE;
    print(f"  Status.ACTIVE == Status.ACTIVE: {s1 == s2}");
    print(f"  Status message: {get_status_message(Status.PENDING)}");
}

# ===== Enum Iteration and Lookup =====
with entry {
    print("\n=== 6. Enum Iteration and Lookup ===");
    # Iteration
    print("  Iterating Priority:");
    for p in Priority {
        print(f"    {p.name} = {p.value}");
    }
    # Access by value and name
    print(f"  Color(2): {Color(2).name}, Role['ADMIN']: {Role['ADMIN'].value}");
}

# ===== Enum in Data Structures =====
with entry {
    print("\n=== 7. Enum in Data Structures ===");
    # List and dict with enums
    colors = [Color.RED, Color.GREEN, Color.BLUE];
    print(f"  List: {[c.name for c in colors]}");

    role_perms = {Role.ADMIN: "Full", Role.USER: "Limited", Role.GUEST: "Read"};
    for item in role_perms.items() {
        print(f"  Dict: {item[0].name} = {item[1]}");
    }
}

# ===== OSP Integration: Enum in Node Attributes =====
node Task {
    has title: str = "Task";
    has priority: Priority = Priority.MEDIUM;
    has status: Status = Status.PENDING;
}

with entry {
    print("\n=== 8. Enum in Node Attributes (OSP) ===");
    task = Task(title="Build feature", priority=Priority.HIGH, status=Status.ACTIVE);
    print(f"  Task: {task.title}");
    print(f"  Priority: {task.priority.name} ({task.priority.value})");
    print(f"  Status: {task.status.name}");
}

# ===== OSP Integration: Enum in Walker Logic =====
walker TaskFilter {
    has target_priority: Priority = Priority.HIGH;
    has matched: list = [];

    can traverse with `root entry {
        visit [-->];
    }

    can filter with Task entry {
        print(f"    Checking task: {here.title}, priority={here.priority.name}");
        if here.priority == self.target_priority {
            self.matched.append(here.title);
            print(f"      Matched!");
        }
        visit [-->];
    }

    can report with exit {
        print(f"  Found {len(self.matched)} tasks: {self.matched}");
    }
}

with entry {
    print("\n=== 9. Enum in Walker Logic (OSP) ===");
    task1 = Task(title="Critical Bug", priority=Priority.HIGH);
    task2 = Task(title="Documentation", priority=Priority.LOW);
    task3 = Task(title="Security Patch", priority=Priority.HIGH);

    root ++> task1;
    root ++> task2;
    root ++> task3;

    root spawn TaskFilter(target_priority=Priority.HIGH);
}

with entry {
    print("\n✓ Enumerations demonstrated!");
}
# Enumerations - Type-safe named constants

import from enum { unique }

# ===== Basic Enums with Integer and String Values =====
enum Color {
    RED = 1,
    GREEN = 2,
    BLUE = 3
}

enum Role {
    ADMIN = 'admin',
    USER = 'user',
    GUEST = 'guest',  # Trailing comma supported
}

with entry {
    print("=== 1. Basic Enums (Integer & String Values) ===");
    print(f"  Color.RED: {Color.RED.value}, Role.ADMIN: {Role.ADMIN.value}");
}

# ===== Forward Declaration with Impl and Decorator =====
@unique
enum Priority;

impl Priority {
    LOW = 1,
    MEDIUM = 2,
    HIGH = 3
}

with entry {
    print("\n=== 2. Forward Declaration with @unique Decorator ===");
    print(f"  Priority.HIGH: {Priority.HIGH.value}");
}

# ===== Enum with Access Modifier =====
enum :protect Permission {
    READ = 'read',
    WRITE = 'write',
    EXECUTE = 'execute'
}

with entry {
    print("\n=== 3. Enum with Access Modifier ===");
    print(f"  Permission.WRITE: {Permission.WRITE.value}");
}

# ===== Enum with Python Code Block and Methods =====
enum HttpStatus {
    OK = 200,
    BAD_REQUEST = 400,
    SERVER_ERROR = 500

    ::py::
    def is_success(self):
        return 200 <= self.value < 300

    def get_category(self):
        if self.value < 300:
            return "success"
        elif self.value < 500:
            return "client_error"
        return "server_error"
    ::py::
}

with entry {
    print("\n=== 4. Enum with Python Code Block (Methods) ===");
    print(f"  {HttpStatus.OK.name}: {HttpStatus.OK.get_category()}, is_success: {HttpStatus.OK.is_success()}");
    print(f"  {HttpStatus.BAD_REQUEST.name}: {HttpStatus.BAD_REQUEST.get_category()}");
}

# ===== Enum Comparison and Functions =====
enum Status {
    PENDING = 0,
    ACTIVE = 1,
    INACTIVE = 2
}

def get_status_message(status: Status) -> str {
    if status == Status.PENDING {
        return "Waiting for approval";
    } elif status == Status.ACTIVE {
        return "Currently active";
    } else {
        return "No longer active";
    }
}

with entry {
    print("\n=== 5. Enum Comparison and Type Safety ===");
    s1 = Status.ACTIVE;
    s2 = Status.ACTIVE;
    print(f"  Status.ACTIVE == Status.ACTIVE: {s1 == s2}");
    print(f"  Status message: {get_status_message(Status.PENDING)}");
}

# ===== Enum Iteration and Lookup =====
with entry {
    print("\n=== 6. Enum Iteration and Lookup ===");
    # Iteration
    print("  Iterating Priority:");
    for p in Priority {
        print(f"    {p.name} = {p.value}");
    }
    # Access by value and name
    print(f"  Color(2): {Color(2).name}, Role['ADMIN']: {Role['ADMIN'].value}");
}

# ===== Enum in Data Structures =====
with entry {
    print("\n=== 7. Enum in Data Structures ===");
    # List and dict with enums
    colors = [Color.RED, Color.GREEN, Color.BLUE];
    print(f"  List: {[c.name for c in colors]}");

    role_perms = {Role.ADMIN: "Full", Role.USER: "Limited", Role.GUEST: "Read"};
    for item in role_perms.items() {
        print(f"  Dict: {item[0].name} = {item[1]}");
    }
}

# ===== OSP Integration: Enum in Node Attributes =====
node Task {
    has title: str = "Task";
    has priority: Priority = Priority.MEDIUM;
    has status: Status = Status.PENDING;
}

with entry {
    print("\n=== 8. Enum in Node Attributes (OSP) ===");
    task = Task(title="Build feature", priority=Priority.HIGH, status=Status.ACTIVE);
    print(f"  Task: {task.title}");
    print(f"  Priority: {task.priority.name} ({task.priority.value})");
    print(f"  Status: {task.status.name}");
}

# ===== OSP Integration: Enum in Walker Logic =====
walker TaskFilter {
    has target_priority: Priority = Priority.HIGH;
    has matched: list = [];

    can traverse with `root entry {
        visit [-->];
    }

    can filter with Task entry {
        print(f"    Checking task: {here.title}, priority={here.priority.name}");
        if here.priority == self.target_priority {
            self.matched.append(here.title);
            print(f"      Matched!");
        }
        visit [-->];
    }

    can report with exit {
        print(f"  Found {len(self.matched)} tasks: {self.matched}");
    }
}

with entry {
    print("\n=== 9. Enum in Walker Logic (OSP) ===");
    task1 = Task(title="Critical Bug", priority=Priority.HIGH);
    task2 = Task(title="Documentation", priority=Priority.LOW);
    task3 = Task(title="Security Patch", priority=Priority.HIGH);

    root ++> task1;
    root ++> task2;
    root ++> task3;

    root spawn TaskFilter(target_priority=Priority.HIGH);
}

with entry {
    print("\n✓ Enumerations demonstrated!");
}
from __future__ import annotations
from jaclang.runtimelib.builtin import *
from enum import Enum, auto
from jaclang import JacMachineInterface as _jl
from enum import unique

@_jl.sem('', {'RED': '', 'GREEN': '', 'BLUE': ''})
class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

@_jl.sem('', {'ADMIN': '', 'USER': '', 'GUEST': ''})
class Role(Enum):
    ADMIN = 'admin'
    USER = 'user'
    GUEST = 'guest'
print('=== 1. Basic Enums (Integer & String Values) ===')
print(f'  Color.RED: {Color.RED.value}, Role.ADMIN: {Role.ADMIN.value}')

@unique
@_jl.sem('', {'LOW': '', 'MEDIUM': '', 'HIGH': ''})
class Priority(Enum):
    LOW = 1
    MEDIUM = 2
    HIGH = 3
print('\n=== 2. Forward Declaration with @unique Decorator ===')
print(f'  Priority.HIGH: {Priority.HIGH.value}')

@_jl.sem('', {'READ': '', 'WRITE': '', 'EXECUTE': ''})
class Permission(Enum):
    READ = 'read'
    WRITE = 'write'
    EXECUTE = 'execute'
print('\n=== 3. Enum with Access Modifier ===')
print(f'  Permission.WRITE: {Permission.WRITE.value}')

@_jl.sem('', {'OK': '', 'BAD_REQUEST': '', 'SERVER_ERROR': ''})
class HttpStatus(Enum):
    OK = 200
    BAD_REQUEST = 400
    SERVER_ERROR = 500

    def is_success(self):
        return 200 <= self.value < 300

    def get_category(self):
        if self.value < 300:
            return 'success'
        elif self.value < 500:
            return 'client_error'
        return 'server_error'
print('\n=== 4. Enum with Python Code Block (Methods) ===')
print(f'  {HttpStatus.OK.name}: {HttpStatus.OK.get_category()}, is_success: {HttpStatus.OK.is_success()}')
print(f'  {HttpStatus.BAD_REQUEST.name}: {HttpStatus.BAD_REQUEST.get_category()}')

@_jl.sem('', {'PENDING': '', 'ACTIVE': '', 'INACTIVE': ''})
class Status(Enum):
    PENDING = 0
    ACTIVE = 1
    INACTIVE = 2

def get_status_message(status: Status) -> str:
    if status == Status.PENDING:
        return 'Waiting for approval'
    elif status == Status.ACTIVE:
        return 'Currently active'
    else:
        return 'No longer active'
print('\n=== 5. Enum Comparison and Type Safety ===')
s1 = Status.ACTIVE
s2 = Status.ACTIVE
print(f'  Status.ACTIVE == Status.ACTIVE: {s1 == s2}')
print(f'  Status message: {get_status_message(Status.PENDING)}')
print('\n=== 6. Enum Iteration and Lookup ===')
print('  Iterating Priority:')
for p in Priority:
    print(f'    {p.name} = {p.value}')
print(f"  Color(2): {Color(2).name}, Role['ADMIN']: {Role['ADMIN'].value}")
print('\n=== 7. Enum in Data Structures ===')
colors = [Color.RED, Color.GREEN, Color.BLUE]
print(f'  List: {[c.name for c in colors]}')
role_perms = {Role.ADMIN: 'Full', Role.USER: 'Limited', Role.GUEST: 'Read'}
for item in role_perms.items():
    print(f'  Dict: {item[0].name} = {item[1]}')

class Task(_jl.Node):
    title: str = 'Task'
    priority: Priority = _jl.field(factory=lambda: Priority.MEDIUM)
    status: Status = _jl.field(factory=lambda: Status.PENDING)
print('\n=== 8. Enum in Node Attributes (OSP) ===')
task = Task(title='Build feature', priority=Priority.HIGH, status=Status.ACTIVE)
print(f'  Task: {task.title}')
print(f'  Priority: {task.priority.name} ({task.priority.value})')
print(f'  Status: {task.status.name}')

class TaskFilter(_jl.Walker):
    target_priority: Priority = _jl.field(factory=lambda: Priority.HIGH)
    matched: list = _jl.field(factory=lambda: [])

    @_jl.entry
    def traverse(self, here: _jl.Root) -> None:
        _jl.visit(self, _jl.refs(_jl.Path(here)._out().visit()))

    @_jl.entry
    def filter(self, here: Task) -> None:
        print(f'    Checking task: {here.title}, priority={here.priority.name}')
        if here.priority == self.target_priority:
            self.matched.append(here.title)
            print('      Matched!')
        _jl.visit(self, _jl.refs(_jl.Path(here)._out().visit()))

    @_jl.exit
    def report(self, here) -> None:
        print(f'  Found {len(self.matched)} tasks: {self.matched}')
print('\n=== 9. Enum in Walker Logic (OSP) ===')
task1 = Task(title='Critical Bug', priority=Priority.HIGH)
task2 = Task(title='Documentation', priority=Priority.LOW)
task3 = Task(title='Security Patch', priority=Priority.HIGH)
_jl.connect(left=_jl.root(), right=task1)
_jl.connect(left=_jl.root(), right=task2)
_jl.connect(left=_jl.root(), right=task3)
_jl.spawn(_jl.root(), TaskFilter(target_priority=Priority.HIGH))
print('\n✓ Enumerations demonstrated!')
Jac Grammar Snippet
enum: decorators? enum_decl
enum_decl: KW_ENUM access_tag? NAME inherited_archs? (enum_block | SEMI)
enum_block: LBRACE assignment_list (py_code_block | free_code)* RBRACE

Description

Enumerations in Jac

Enumerations provide type-safe named constants with associated values. Jac enums support integer and string values, Python code blocks for methods, iteration, and seamless integration with Object-Spatial Programming.

Basic Enum Syntax (Lines 6-16)

Lines 6-10 define an integer enum: - Members are named constants with explicit values - Access via Color.RED, Color.GREEN, etc. - Trailing commas are allowed and recommended

Lines 12-16 define a string enum: - Values can be strings instead of integers - String enums useful for API constants and configuration

Enum Value Types

Type Example Use Case
Integer RED = 1 Numeric codes, priorities
String ADMIN = 'admin' API values, database fields
Float PI = 3.14159 Constants with decimals
Tuple RGB = (255, 0, 0) Composite values

Accessing Enum Members (Lines 18-21)

Line 20: print(f"Color.RED: {Color.RED.value}, Role.ADMIN: {Role.ADMIN.value}"); - .value retrieves the enum member's value - .name retrieves the member's name as a string - Color.RED.value returns 1 - Color.RED.name returns "RED"

Forward Declaration with Decorator (Lines 23-36)

Lines 24-25 show forward declaration: - Declares enum without defining members - Allows applying decorators before implementation - @unique decorator ensures all values are unique (from Python's enum module)

Lines 27-31 implement the enum: - impl block provides the member definitions - Separates declaration from implementation

Enum with Access Modifier (Lines 38-48)

Lines 39-43: - Access modifiers: :pub, :protect, :priv - Controls enum visibility across modules - :protect makes it accessible to submodules

Python Code Blocks in Enums (Lines 50-73)

Lines 51-67 define an enum with methods:

Method features: - Lines 56-67: Python code between ::py:: delimiters - Methods have access to self.value and self.name - Can contain any Python logic - Called on enum members: HttpStatus.OK.is_success()

Enum Method Flow

graph TD
    A[HttpStatus.OK] --> B{is_success?}
    B --> C[Check: 200 <= 200 < 300]
    C --> D[Returns True]

    E[HttpStatus.BAD_REQUEST] --> F{get_category?}
    F --> G{value < 300?}
    G -->|No| H{value < 500?}
    H -->|Yes| I[Returns 'client_error']

    style D fill:#2e7d32,stroke:#fff,color:#fff
    style I fill:#e65100,stroke:#fff,color:#fff

Enum Comparison (Lines 75-98)

Lines 82-90 define a function using enum comparison: - Line 83: Enum members compared with == - Type-safe comparison prevents invalid values - Line 94: s1 == s2 compares enum instances

Enum Iteration and Lookup (Lines 100-110)

Iteration (Lines 105-107): - Enums are iterable - Iterates in definition order - Each iteration yields an enum member

Lookup methods (Line 109): - Color(2) - lookup by value, returns Color.GREEN - Role['ADMIN'] - lookup by name, returns Role.ADMIN - Raises ValueError if value not found - Raises KeyError if name not found

Lookup Patterns

Method Syntax Returns Error
By value Color(2) Enum member ValueError
By name Role['ADMIN'] Enum member KeyError
Attribute access Color.RED Enum member AttributeError

Enums in Data Structures (Lines 112-123)

Lines 116-117 show enums in lists: - Enum members can be list elements - List comprehension accesses .name attribute

Lines 119-122 show enums as dictionary keys: - Enum members make excellent dict keys (hashable, unique) - Provides type-safe mapping

Enums in Node Attributes (Lines 125-138)

Lines 126-130 define a node with enum attributes: - Node attributes can be enum-typed - Provides type safety for node state - Default values from enum members

Lines 134-137 show usage: - Initialize with enum members - Access both name and value

Enum State Machine

stateDiagram-v2
    [*] --> PENDING
    PENDING --> ACTIVE: approve
    ACTIVE --> INACTIVE: deactivate
    INACTIVE --> ACTIVE: reactivate
    ACTIVE --> [*]

    note right of PENDING: Status.PENDING (0)
    note right of ACTIVE: Status.ACTIVE (1)
    note right of INACTIVE: Status.INACTIVE (2)

Enums in Walker Logic (Lines 140-174)

Lines 141-161 define a walker that filters by enum: - Line 142: Walker has enum-typed attribute - Line 151: Compares node's enum attribute to walker's - Enables type-safe filtering during graph traversal

Lines 165-173 demonstrate usage: - Creates tasks with different priorities - Spawns walker that filters for HIGH priority - Walker collects matching tasks in self.matched

Enum Integration Flow

graph TD
    A[Define Enum] --> B[Create Node with Enum attribute]
    B --> C[Instantiate Nodes]
    C --> D[Create Walker with Enum filter]
    D --> E[Spawn Walker]
    E --> F[Walker visits nodes]
    F --> G{Enum matches?}
    G -->|Yes| H[Collect result]
    G -->|No| I[Skip]
    H --> J[Return results]
    I --> J

    style A fill:#1565c0,stroke:#fff,color:#fff
    style G fill:#e65100,stroke:#fff,color:#fff
    style H fill:#2e7d32,stroke:#fff,color:#fff

Common Enum Patterns

State management:

Priority levels:

Feature flags:

API constants:

Best Practices

  1. Use enums for fixed sets: Status codes, priorities, states, types
  2. String values for external APIs: Use string enums when values leave the system
  3. Integer values for internal logic: Use int enums for comparisons and ordering
  4. Add methods for complex logic: Encapsulate enum-specific behavior in methods
  5. Type annotations: Use enum types in function signatures for type safety
  6. Avoid magic values: Replace hardcoded strings/numbers with enums

Enum vs Constants

Feature Enum Constants
Type safety Yes No
Grouping Built-in Manual
Iteration Yes No
Reverse lookup Yes No
Methods Yes No
Namespace Automatic Manual

When to Use Enums

Use enums when: - Values form a fixed, known set - Need type safety and validation - Want reverse lookup (value to name) - Implementing state machines - Defining API or database constants - Comparing priority or severity levels

Avoid enums when: - Values are dynamic or user-defined - Set changes frequently - Need arbitrary value types - Simple boolean flag suffices