Caspian Pipe Operator Design GitHub issue
- Overview
- Basic Pipe Operator
- Chaining Pipes
- Example: Method Calls
- Design Principle
- Null-Safe Pipe Operator (|&)
- Syntax
- Semantics
- Execution Model
- Design Rule
- Summary
- Future Considerations (Optional)
Overview GitHub issue
vibecode
{"vibecode": { "section": "overview", "role": "introduces the Caspian pipe operator for chaining in execution order", "key_concepts": ["pipe_operator", "execution_order", "chaining", "nested_call_alternative"] }}
Caspian introduces a pipe operator to allow chaining operations in execution order, rather than nested call order.
This provides a more readable and intuitive alternative to deeply nested expressions.
Basic Pipe Operator GitHub issue
vibecode
{"vibecode": { "section": "basic_pipe_operator", "role": "defines the | operator: passes left result as first and only arg to right", "key_concepts": ["pipe_operator", "single_argument", "desugaring", "a_pipe_b"] }}
Syntax GitHub issue
a | b
Semantics GitHub issue
The pipe operator passes the result of the left-hand expression as the first positional argument to the right-hand expression. The right-hand side may also accept additional positional or named arguments at the call site; the piped value occupies the first positional slot and the rest of the arguments are bound normally.
a | b
desugars to:
b(a)
With additional arguments at the call site:
$list | sort('asc')
$list | filter(min: 5, max: 10)
desugar to:
sort($list, 'asc')
filter($list, min: 5, max: 10)
Same shape as Elixir's |>, F#'s |>, R's %>%.
Chaining Pipes GitHub issue
vibecode
{"vibecode": { "section": "chaining_pipes", "role": "shows how multiple | operators desugar to nested function calls", "key_concepts": ["pipe_chain", "sequential_execution", "nested_call_desugaring"] }}
Multiple pipes can be chained to represent sequential execution:
&a |
&b |
&c
desugars to:
&c(&b(&a))
Example: Method Calls GitHub issue
vibecode
{"vibecode": { "section": "example_method_calls", "role": "illustrates pipe chaining with method calls on objects", "key_concepts": ["method_call_piping", "execution_order_readability"] }}
Pipes work naturally with object method calls:
&baz |
&bear |
$bar.gup
desugars to:
$bar.gup(&bear(&baz))
This allows writing code in the same order as execution.
Design Principle GitHub issue
vibecode
{"vibecode": { "section": "design_principle", "role": "states the core design rule: pipes express data flow in execution order", "key_concepts": ["data_flow", "execution_order", "single_input_per_stage"] }}
Pipes express data flow in execution order, not call nesting.
Each stage receives exactly one input: the result of the previous stage.
Null-Safe Pipe Operator (|&) GitHub issue
vibecode
{"vibecode": { "section": "null_safe_pipe_operator", "role": "documents the |& operator for null propagation through a pipe chain", "key_concepts": ["|&_operator", "null_propagation_mode", "null_safe_chaining", "once_set_all_subsequent"] }}
Motivation GitHub issue
Caspian supports null-safe chaining in method calls:
$foo.bar&.gup.bear
This stops evaluation if bar returns null.
The pipe system introduces a similar concept.
Syntax GitHub issue
vibecode
{"vibecode": { "section": "null_safe_syntax", "role": "shows the |& operator syntax", "key_concepts": ["|&_syntax", "null_safe_pipe_form"] }}
a |& b
Semantics GitHub issue
vibecode
{"vibecode": { "section": "null_safe_semantics", "role": "explains that |& enables null propagation mode for all subsequent pipe stages", "key_concepts": ["null_propagation_mode", "remainder_of_chain", "sticky_null_safe"] }}
The |& operator enables null propagation mode for the remainder of the pipe chain.
Once |& is used, all subsequent pipe stages automatically become null-safe.
Example GitHub issue
&foo |&
&bar |
&gup
is equivalent to:
&foo |&
&bar |&
&gup
Execution Model GitHub issue
vibecode
{"vibecode": { "section": "execution_model", "role": "shows the desugared if-null-return expansion for null-safe pipe chains", "key_concepts": ["null_check_expansion", "return_null_early", "desugared_form"] }}
&foo |&
&bar |
&gup
desugars to:
let x = &foo
if x == null
return null
let y = &bar(x)
if y == null
return null
return &gup(y)
Design Rule GitHub issue
vibecode
{"vibecode": { "section": "null_safe_design_rule", "role": "states the rule that |& once used propagates null through all subsequent stages", "key_concepts": ["once_propagates_all", "no_repetition_needed", "clear_intent"] }}
Once |& appears in a pipe chain, all subsequent pipes propagate nulls. This avoids repetition while keeping intent clear.
Summary GitHub issue
vibecode
{"vibecode": { "section": "summary", "role": "quick reference table for pipe operator meanings", "key_concepts": ["pipe_operator_table", "|", "|&"] }}
| Operator | Meaning |
|---|---|
| ` | ` |
| ` | &` |
Future Considerations (Optional) GitHub issue
vibecode
{"vibecode": { "section": "future_considerations", "role": "lists intentionally deferred pipe features for possible future design", "key_concepts": ["placeholder_arguments", "multi-argument_pipe", "pipe_grouping", "deferred_design"] }}
- Placeholder arguments (e.g.
_) for more flexible piping - Multi-argument pipe expansion
- Explicit pipe grouping or scoping