- Fixed deadlock in FileBox plugin copyFrom implementation (single lock) - Added TLV Handle (tag=8) parsing in calls.rs for returned BoxRefs - Improved plugin loader with config path consistency and detailed logging - Fixed loader routing for proper Handle type_id/fini_method_id resolution - Added detailed logging for TLV encoding/decoding in plugin_loader_v2 Test docs/examples/plugin_boxref_return.nyash now works correctly: - cloneSelf() returns FileBox Handle properly - copyFrom(Box) accepts plugin Box arguments - Both FileBox instances close and fini correctly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
100 lines
3.9 KiB
Plaintext
100 lines
3.9 KiB
Plaintext
Nyash Programming Language - Weak Reference Architecture Critical Decision
|
|
|
|
I need expert advice on a fundamental architectural decision for weak reference implementation. This is a foundational component that will impact native compilation plans.
|
|
|
|
【Current Situation】
|
|
Copilot has completed 99% of weak reference implementation with excellent quality. Only the final invalidation mechanism remains.
|
|
|
|
【Two Competing Approaches】
|
|
|
|
## Approach A: Copilot's "Proper" Global Tracking
|
|
```rust
|
|
pub struct SharedState {
|
|
// Existing fields...
|
|
pub instance_registry: Arc<Mutex<Vec<Weak<Mutex<InstanceBox>>>>>,
|
|
}
|
|
|
|
fn invalidate_weak_references(&mut self, target_info: &str) {
|
|
// Linear search through ALL instances in the system
|
|
for weak_instance in &self.instance_registry {
|
|
if let Some(instance) = weak_instance.upgrade() {
|
|
instance.lock().unwrap().invalidate_weak_references_to(target_info);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Pros**: Architecturally correct, immediate invalidation, theoretically perfect
|
|
**Cons**: O(n) linear search, complex state management, heavyweight
|
|
|
|
## Approach B: Gemini's "On-Access" Lazy Invalidation
|
|
```rust
|
|
pub struct Interpreter {
|
|
pub invalidated_ids: Arc<Mutex<HashSet<u64>>>, // Simple ID set
|
|
}
|
|
|
|
fn trigger_weak_reference_invalidation(&mut self, target_info: &str) {
|
|
if let Ok(id) = target_info.parse::<u64>() {
|
|
self.invalidated_ids.lock().unwrap().insert(id); // O(1) operation
|
|
}
|
|
}
|
|
|
|
fn get_weak_field(&self, name: &str) -> Option<...> {
|
|
if invalidated_ids.contains(&id) { // O(1) lookup
|
|
return None; // Auto-nil on access
|
|
}
|
|
}
|
|
```
|
|
|
|
**Pros**: O(1) operations, minimal changes, leverages 99% existing implementation
|
|
**Cons**: Delayed invalidation (only on access), not "immediate"
|
|
|
|
【Critical Considerations】
|
|
|
|
## 1. Native Compilation Impact
|
|
This weak reference system will be compiled to native code. Performance characteristics matter significantly:
|
|
- Approach A: O(n) linear search in native code = potential bottleneck
|
|
- Approach B: O(1) HashSet operations = predictable performance
|
|
|
|
## 2. Foundation Quality vs Pragmatism
|
|
- This is foundational memory safety infrastructure
|
|
- Must balance correctness with performance
|
|
- Real-world usage patterns matter more than theoretical perfection
|
|
|
|
## 3. Scaling Characteristics
|
|
In applications with 1000+ objects:
|
|
- Approach A: 1000+ instance traversal on each drop
|
|
- Approach B: Single hash table insertion/lookup
|
|
|
|
## 4. Maintenance Complexity
|
|
- Approach A: Complex global state, threading issues, lifecycle management
|
|
- Approach B: Simple addition to existing interpreter state
|
|
|
|
【Specific Technical Questions】
|
|
|
|
1. **Performance Reality Check**: In a native-compiled language, is O(n) weak reference invalidation acceptable for real applications?
|
|
|
|
2. **Lazy vs Eager Trade-off**: Is "on-access invalidation" a viable pattern for systems programming? What are the hidden costs?
|
|
|
|
3. **Native Compilation Compatibility**: Which approach translates better to efficient native code generation?
|
|
|
|
4. **Memory Safety Guarantee**: Do both approaches provide equivalent memory safety guarantees?
|
|
|
|
5. **Industry Best Practices**: How do modern systems languages (Rust, Swift, etc.) handle this problem?
|
|
|
|
【Nyash Context】
|
|
- Everything is Box philosophy (unified object model)
|
|
- Target: P2P networking applications (performance-sensitive)
|
|
- Native compilation planned (MIR → LLVM/Cranelift)
|
|
- Developer experience priority (simplicity over theoretical perfection)
|
|
|
|
【Request】
|
|
Please provide expert analysis focusing on:
|
|
1. Real-world performance implications for native compilation
|
|
2. Hidden complexity costs of each approach
|
|
3. Recommendation for foundational language infrastructure
|
|
4. Risk assessment for future scaling
|
|
|
|
This decision affects the entire language's memory management foundation. I need the most technically sound recommendation that balances correctness, performance, and maintainability.
|
|
|
|
Thank you for your expertise! |