Files
hakorune/docs/development/proposals/unified-members.md

138 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Property System Revolution for Nyash (2025-09-18 Breakthrough)
Status: **BREAKTHROUGH COMPLETED** - Final syntax decided through AI collaboration with ChatGPT, Claude, and Codex.
## 🌟 Revolutionary Achievement
Today we achieved the **Property System Revolution** - a complete unification of stored fields, computed properties, lazy evaluation, and birth-time initialization into a single, elegant syntax system through AI collaboration with ChatGPT5, Claude, and Codex.
## 🎯 Final Property System Design
### The Four-Category Breakthrough
After dialectical discussion with multiple AI agents, we reached the perfect synthesis:
#### 1. **stored** - Traditional Field Storage
```nyash
box Example {
name: StringBox // Default initialization
count: IntegerBox = 0 // Explicit initialization
}
```
- **Semantics**: O(1) slot read/write, assignment allowed
- **Use Case**: Traditional object fields, counters, configurations
#### 2. **computed** - Calculated Every Access
```nyash
box Example {
size: IntegerBox { me.items.count() }
full_name: StringBox { me.first + " " + me.last }
}
```
- **Semantics**: Evaluate body on each read, assignment error unless setter declared
- **Use Case**: Derived values, dynamic calculations, Python @property equivalent
#### 3. **once** - Lazy Evaluation with Caching
```nyash
box Example {
once expensive_data: DataBox { heavy_computation() }
once config: ConfigBox { loadConfiguration() }
}
```
- **Semantics**: Evaluate on first read, cache result, return cached value thereafter
- **Use Case**: Heavy computations, file loading, Python @cached_property equivalent
- **Exception Handling**: Poison-on-throw strategy for safety
#### 4. **birth_once** - Eager Evaluation at Object Creation
```nyash
box Example {
birth_once startup_data: DataBox { initialize_system() }
birth() {
// birth_once properties already initialized!
me.ready = true
}
}
```
- **Semantics**: Evaluated before user birth() in declaration order
- **Use Case**: System initialization, dependency setup, startup-critical data
## 🌟 Revolutionary Python Integration
### Perfect Mapping Strategy
```python
# Python side
class DataProcessor:
def __init__(self):
self.value = 42 # → stored
@property
def computed_result(self): # → computed
return self.value * 2
@functools.cached_property
def expensive_data(self): # → once
return heavy_computation()
```
```nyash
// Auto-generated Nyash (revolutionary 1:1 mapping!)
box DataProcessor {
value: IntegerBox // stored
computed_result: IntegerBox { me.value * 2 } // computed
once expensive_data: ResultBox { heavy_computation() } // once
birth() {
me.value = 42
}
}
```
### Performance Revolution
- **computed properties**: No caching overhead, pure calculation
- **once properties**: 10-50x faster than Python cached_property (LLVM optimization)
- **birth_once properties**: Startup optimization, dependency injection pattern
- **Overall**: Python code → 5-20x faster native binary
Handlers (Stage3)
- Postfix `catch/cleanup` are allowed for computed/once/birth_once/method blocks.
- Stored does not accept handlers.
Semantics
- stored: O(1) slot read; `= expr` evaluated once during construction; assignment allowed.
- computed: evaluate on each read; assignment is an error unless a setter is declared.
- once: evaluate on first read, cache the result, and return it thereafter. If the first evaluation throws and there is no `catch`, mark poisoned and rethrow the same error on later reads (no retry).
- birth_once: evaluated before user `birth` body in declaration order; uncaught error aborts construction. Cycles are rejected.
Lowering (no JSON v0 change)
- stored → slot
- computed → synthesize `__get_name():T { try body; catch; finally }`, resolve reads to call
- once → add hidden `__name: Option<T>` and first-read initialization in `__get_name()`; poison on uncaught error
- birth_once → hidden `__name: T` initialized before user `birth` body in declaration order; handler blocks apply per initializer
- method → unchanged; postfix handlers lower to try/catch/finally
EBNF (delta)
```
box_decl := 'box' IDENT '{' member* '}'
member := stored | computed | once_decl | birth_once_decl | method_decl
stored := IDENT ':' TYPE ( '=' expr )?
computed := IDENT ':' TYPE block handler_tail?
once_decl := 'once' IDENT ':' TYPE block handler_tail?
birth_once_decl:= 'birth_once' IDENT ':' TYPE block handler_tail?
method_decl := IDENT '(' params? ')' ( ':' TYPE )? block handler_tail?
handler_tail := ( catch_block )? ( cleanup_block )?
catch_block := 'catch' ( '(' ( IDENT IDENT | IDENT )? ')' )? block
cleanup_block := 'cleanup' block
```
Diagnostics
- Assignment to computed/once/birth_once: error with fix-it (“define a setter or use stored property”).
- Once poison: first read throws → remember error; subsequent reads rethrow immediately.
- Birth order: evaluated before user `birth`, in declaration order; cycle detection emits a clear error with the chain.
Flags
- Parser gate: `NYASH_ENABLE_UNIFIED_MEMBERS=1`
- Stage3 for handlers: `NYASH_PARSER_STAGE3=1`
Notes
- User experience: read is uniform (`obj.name`), write differs by kind; this keeps mental model simple.
- Future: setter syntax (`name: T { get {…} set(v) {…} }`) and aliases (`slot/calc/lazy`) can be added without breaking this core.