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!");
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
|
Jac Grammar Snippet
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
- Use enums for fixed sets: Status codes, priorities, states, types
- String values for external APIs: Use string enums when values leave the system
- Integer values for internal logic: Use int enums for comparisons and ordering
- Add methods for complex logic: Encapsulate enum-specific behavior in methods
- Type annotations: Use enum types in function signatures for type safety
- 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