Files
hakorune/docs/development/architecture/box-externcall-design.md
Selfhosting Dev 0ac22427e5 docs: Architecture decision - Box/ExternCall boundary design
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>
2025-09-11 20:58:18 +09:00

2.2 KiB
Raw Permalink Blame History

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  // IntegerBoxarithmetic, comparison
├── string.rs   // StringBoxstring operations
├── array.rs    // ArrayBoxarray operations
├── map.rs      // MapBoxkey-value storage
└── bool.rs     // BoolBoxlogical 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.