Dynamic variant construction (wrap) #149

Closed
opened 2025-12-30 19:13:25 +00:00 by navicore · 1 comment
navicore commented 2025-12-30 19:13:25 +00:00 (Migrated from github.com)

Context

SON (Seq Object Notation) needs to construct variants dynamically from symbols:

:some 42 wrap     # Creates Some(42)
:none wrap        # Creates None
:ok "success" wrap

Currently, variants require static constructors generated from union definitions:

Make-Some 42      # Works, but requires union to be in scope

Proposed Words

: wrap ( ...values Symbol -- Variant )
  # Creates a variant with the given tag and values from stack
  ;

# Or more explicit:
: wrap-0 ( Symbol -- Variant )           # No fields
: wrap-1 ( v1 Symbol -- Variant )        # One field  
: wrap-2 ( v1 v2 Symbol -- Variant )     # Two fields

Design Questions

1. Tag Resolution

How does :some become tag 1?

Option A: Global tag registry

  • First use of :some assigns it tag 1, memoized
  • Pros: Simple, works without union definitions
  • Cons: Tag numbers vary by program, can't interop

Option B: Union-based lookup

  • wrap searches defined unions for matching variant name
  • Pros: Type-safe, consistent tags
  • Cons: Requires union in scope, slower

Option C: Structural/untyped

  • Variants carry their symbol, not integer tag
  • Pros: Truly dynamic, self-describing
  • Cons: Breaking change to variant representation

2. Type System Impact

What type does wrap return?

: wrap ( ...values Symbol -- ??? )

Options:

  • Variant (opaque, loses type info)
  • Existential type ∃T. T
  • Union with the symbol's variant (requires type-level symbols)

3. Arity

How does wrap know how many values to consume?

  • Fixed arity words: wrap-0, wrap-1, wrap-2, etc.
  • Symbol carries arity: :some/1 (like Erlang atoms)
  • Explicit count: 42 :some 1 wrap

Relation to SON

This is the key feature that makes SON expressive:

[
  :user
  [:name "Alice" :age 30 2 kv-map]
  wrap
]

Without wrap, SON files must import union definitions, defeating portability.


Part of the SON implementation roadmap.
Depends on: #148 (symbol syntax)

## Context SON (Seq Object Notation) needs to construct variants dynamically from symbols: ```seq :some 42 wrap # Creates Some(42) :none wrap # Creates None :ok "success" wrap ``` Currently, variants require static constructors generated from union definitions: ```seq Make-Some 42 # Works, but requires union to be in scope ``` ## Proposed Words ```seq : wrap ( ...values Symbol -- Variant ) # Creates a variant with the given tag and values from stack ; # Or more explicit: : wrap-0 ( Symbol -- Variant ) # No fields : wrap-1 ( v1 Symbol -- Variant ) # One field : wrap-2 ( v1 v2 Symbol -- Variant ) # Two fields ``` ## Design Questions ### 1. Tag Resolution How does `:some` become tag `1`? **Option A: Global tag registry** - First use of `:some` assigns it tag `1`, memoized - Pros: Simple, works without union definitions - Cons: Tag numbers vary by program, can't interop **Option B: Union-based lookup** - `wrap` searches defined unions for matching variant name - Pros: Type-safe, consistent tags - Cons: Requires union in scope, slower **Option C: Structural/untyped** - Variants carry their symbol, not integer tag - Pros: Truly dynamic, self-describing - Cons: Breaking change to variant representation ### 2. Type System Impact What type does `wrap` return? ```seq : wrap ( ...values Symbol -- ??? ) ``` Options: - `Variant` (opaque, loses type info) - Existential type `∃T. T` - Union with the symbol's variant (requires type-level symbols) ### 3. Arity How does `wrap` know how many values to consume? - Fixed arity words: `wrap-0`, `wrap-1`, `wrap-2`, etc. - Symbol carries arity: `:some/1` (like Erlang atoms) - Explicit count: `42 :some 1 wrap` ## Relation to SON This is the key feature that makes SON expressive: ```seq [ :user [:name "Alice" :age 30 2 kv-map] wrap ] ``` Without `wrap`, SON files must import union definitions, defeating portability. --- Part of the SON implementation roadmap. Depends on: #148 (symbol syntax)
navicore commented 2026-01-03 15:31:37 +00:00 (Migrated from github.com)
https://github.com/navicore/patch-seq/pull/168
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
navicore/patch-seq#149
No description provided.