Documented the architectural decision for Nyash runtime design: 1. Core boxes (String/Integer/Array/Map/Bool) built into nyrt - Essential for self-hosting - Available at boot without plugin loader - High performance (no FFI overhead) 2. All other boxes as plugins (File/Net/User-defined) - Extensible ecosystem - Clear separation of concerns 3. Minimal ExternCall (only 5 functions) - print/error (output) - panic/exit (process control) - now (time) Key principle: Everything goes through BoxCall interface - No special fast paths - Unified architecture - "Everything is Box" philosophy maintained This design balances self-hosting requirements with architectural purity. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2.2 KiB
2.2 KiB
Box/ExternCall Architecture Design Decision
Date: 2025-09-11
Background
During LLVM backend development, confusion arose about the proper boundary between:
- ExternCall (core runtime functions)
- BoxCall (unified Box method dispatch)
- nyrt (Nyash runtime library)
Design Decision
1. nyrt Built-in Core Boxes
The following boxes are built into nyrt for self-hosting stability:
// crates/nyrt/src/core_boxes/
├── integer.rs // IntegerBox(arithmetic, comparison)
├── string.rs // StringBox(string operations)
├── array.rs // ArrayBox(array operations)
├── map.rs // MapBox(key-value storage)
└── bool.rs // BoolBox(logical operations)
Rationale:
- Essential for self-hosting (compiler needs these)
- Available at boot time (no plugin loader dependency)
- High performance (no FFI overhead)
- Environment independent
2. Plugin Boxes
All other boxes are implemented as plugins:
plugins/
├── file/ // FileBox
├── net/ // NetBox
└── custom/ // User-defined boxes
3. Minimal ExternCall
ExternCall is limited to truly external operations:
// Only these 5 functions!
extern nyash.io.print(handle: i64)
extern nyash.io.error(handle: i64)
extern nyash.runtime.panic(handle: i64)
extern nyash.runtime.exit(code: i64)
extern nyash.time.now() -> i64
Key Principle: Everything Goes Through BoxCall
local s = new StringBox("Hello") // BoxCall → nyrt built-in
local f = new FileBox() // BoxCall → plugin
s.concat(" World") // BoxCall (unified interface)
Even core boxes use the same BoxCall mechanism - no special fast paths!
Trade-offs Considered
Option 1: Everything as plugins
- ✅ Beautiful uniformity
- ❌ Complex bootstrap
- ❌ Performance overhead
- ❌ Environment dependencies
Option 2: Core boxes in nyrt (chosen)
- ✅ Simple, stable bootstrap
- ✅ Self-hosting friendly
- ✅ High performance for basics
- ❌ Slightly larger core
Conclusion
This design prioritizes self-hosting stability while maintaining the "Everything is Box" philosophy through unified BoxCall interface.