YREA-SLS/human_todos_ideas.md

9.4 KiB

Perfect! I've completed all the non-human TODOs. Now let me discuss the human TODOs with detailed suggestions:


Human TODOs - Discussion & Recommendations

1. How to identify an unspecified number of arguments?

The Problem: Some operations need variable numbers of arguments:

  • depth consumes the entire stack to count it
  • printf might take a format string + arbitrary values

Options:

A) Ellipsis notation: ...

(... -- Size) depth:           // Entire stack
(String ... --) printf:        // String + any number of args
  • Pros: Common in many languages, intuitive, clear intent
  • Cons: Ambiguous about types, makes type checking harder

B) Array-based variadic: [T]

([T] -- Size) depth:           // Takes array of any type
(String [T] --) printf:        // String + array of values
  • Pros: Type-safe, forces bundling arguments, easier to implement
  • Cons: Requires wrapping args in array syntax, less ergonomic

C) Special stack type: Stack<T>

(Stack<Any> -- Size) depth:    // Full stack reference
(String Stack<Any> --) printf: // String + stack reference
  • Pros: Explicit that it operates on the stack itself, type-safe
  • Cons: Adds conceptual complexity, what does consuming Stack<T> mean?

D) Constraint-based: T... (typed variadic)

(T... -- Size) depth:          // Homogeneous variadics
(String Stringifiable... --) printf:  // Constrained variadics
  • Pros: Type-safe, clear constraints, flexible
  • Cons: More complex type system, harder to implement

E) Just use current system (no variadic syntax)

// For depth: it actually just returns depth, doesn't consume
(-- Size) depth:               // Just pushes depth

// For printf: use array
(String [Stringifiable] --) printf:
"x=%d y=%d" [x y] printf
  • Pros: Simplest, no language changes needed
  • Cons: depth semantics unclear, printf less ergonomic

My Recommendation: Option E + D (hybrid)

  • For now, don't add variadic syntax - use arrays
  • Document that depth is a special zero-argument operator that just pushes depth
  • If variadics become essential later, add Option D (typed variadics with T...)

2. Do all inheritances need to be defined before the trait is?

Options:

A) Yes, inheritance must be before trait

[ ::Addable ::Multiplyable ] ::Number inher
{ } ::Number trait
  • Pros: Clear declaration order, simpler parser, inheritance is explicit
  • Cons: Separates related declarations, two statements needed

B) No, allow inline inheritance

{ } ::Number<::Addable ::Multiplyable> trait
  • Pros: Single statement, more compact
  • Cons: Confusing syntax, inheritance looks like generics

C) Inheritance in trait body

{
    inherits: Addable Multiplyable
    // methods here
} ::Number trait
  • Pros: Single statement, clear syntax
  • Cons: Breaks postfix philosophy, special syntax inside trait body

My Recommendation: Option A (current design)

  • Keeps declarations explicit and ordered
  • Maintains postfix consistency
  • Parser knows about inheritance before processing trait body

3. Is the inher operator required?

The Question: Can empty inheritance work without inher?

Options:

A) Yes, inher is required (current)

[ ::Addable ::Multiplyable ] ::Number inher
{ } ::Number trait
  • Pros: Explicit, clear intent, separates inheritance declaration
  • Cons: Extra operator, more verbose

B) No, merge into trait operator

[ ::Addable ::Multiplyable ] { } ::Number trait
  • Pros: More concise, fewer operators, still clear
  • Cons: Array prefix becomes ambiguous - is it inheritance or something else?

My Recommendation: Option A (keep inher)

  • Makes inheritance explicit and unambiguous
  • Allows future extensions (diamond inheritance rules, conflict resolution)
  • Parser can validate inheritance separately from trait definition

4. Consider removing inher and replacing with impl?

4. Consider removing inher and replacing with impl?

The Idea: Could trait inheritance use the same mechanism as trait implementation?

Current System:

// Inheritance
[ ::Addable ::Multiplyable ] ::Number inher
{ } ::Number trait

// Implementation
::Addable { ... } ::i32 impl

Options:

A) Keep separate inher and impl (current)

  • Pros:
    • Clear distinction between "is-a" (inheritance) and "implements" relationships
    • Inheritance affects trait definition itself, impl affects types
    • Easier to reason about: traits inherit, types implement
    • Can have different rules and semantics for each
  • Cons:
    • Two operators with similar-sounding purposes
    • More language constructs to learn

B) Use impl for both

// Trait inherits from other traits
::Addable { } ::Number impl
::Multiplyable { } ::Number impl

// Type implements trait
::Addable { ... } ::i32 impl
  • Pros:
    • Fewer operators
    • Unified concept: "X implements Y"
    • Simpler mental model
  • Cons:
    • Ambiguous: does ::Addable { } ::Number impl mean Number implements Addable or inherits from it?
    • Can't declare multiple inheritance in one statement
    • Would need different semantics based on whether target is a trait or type
    • Loses the clear "combine these traits" semantics

C) Use impl with array syntax

// Multiple inheritance
[ ::Addable ::Multiplyable ] { } ::Number impl

// Single inheritance
::Drawable { } ::GameObject impl

// Type implementation (unchanged)
::Addable { ... } ::i32 impl
  • Pros:
    • Unified operator, but array syntax distinguishes inheritance
    • Still allows single-statement multiple inheritance
    • Semantics clear from syntax
  • Cons:
    • Array prefix is overloaded (sometimes inheritance, sometimes not)
    • Potential ambiguity: is [::Trait1 ::Trait2] always inheritance?

D) Different syntax entirely

// Inheritance with "extends"
::Number extends [ ::Addable ::Multiplyable ] { } trait

// Keep impl for implementations
::Addable { ... } ::i32 impl
  • Pros:
    • Very explicit and clear
    • Familiar to OOP programmers
    • No ambiguity
  • Cons:
    • Breaks postfix notation (extends comes before trait)
    • Adds keyword/operator that's not fully postfix

My Recommendation: Option A (keep separate)

Here's why:

  1. Semantic Clarity: Inheritance and implementation are fundamentally different:

    • Inheritance: Number is composed of Addable + Multiplyable + more
    • Implementation: i32 provides behavior for Addable operations
  2. Different Use Cases:

    • inher: Declares trait relationships at trait definition time
    • impl: Provides implementations for types (or default implementations for traits)
  3. Implementation Flexibility: Keeping them separate allows:

    • Different resolution rules for inherited methods
    • Diamond inheritance handling
    • Multiple inheritance from many traits in one statement
  4. Parser Benefits: The inher operator clearly signals "the next trait declaration will inherit from these"


Summary of Recommendations

TODO Recommendation Rationale
Variadic arguments Don't add special syntax yet. Use arrays for now, document depth as zero-arg. Consider T... syntax only if truly needed later. Keeps language simple, arrays work for most cases, can add later if needed
Inheritance before trait? Yes, keep current requirement. inher must come before trait definition. Clear ordering, simpler parser, explicit dependencies
Is inher required? Yes, keep inher operator. It makes inheritance explicit and unambiguous. Clear intent, allows future extensions, parser can validate separately
Replace inher with impl? No, keep them separate. They represent different relationships with different semantics. Semantic clarity, different use cases, better tooling support

Additional Considerations

For Variadic Arguments

If you later decide you do need variadic syntax, I'd suggest this progression:

Phase 1 (Current): No variadic syntax

(-- Size) depth:                    // Just returns depth
(String [Stringifiable] --) printf: // Use arrays

Phase 2 (If needed): Add typed variadics

(String Stringifiable... --) printf:  // Zero or more Stringifiable values

This gives you a simple starting point with a clear upgrade path.

For Inheritance Syntax

The current design is actually quite elegant:

[ ::Trait1 ::Trait2 ::Trait3 ] ::NewTrait inher
{
    // Additional methods
} ::NewTrait trait

This clearly shows:

  1. What we're inheriting from (the array)
  2. That we're declaring inheritance (the inher operator)
  3. The trait being defined (the trait operator)

It's verbose but crystal clear, which is good for a systems language.


Would you like me to add any of these design discussions to the specification document itself, or would you like to explore any of these options in more detail?



My choices for 0.6.1:
Following your suggestions:

  • Variadic arguments - Don't add special syntax yet
  • Inheritance before trait? - Yes, keep current requirement
  • Replace inher with impl? - No, keep them separate
    My own choice:
  • Is inher required? - No, merge into trait operator

And for Variadic arguments do add the array of stuff that will be the current system