@rcrsr/rill 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/introspection-data.d.ts +1 -1
- package/dist/generated/introspection-data.d.ts.map +1 -1
- package/dist/generated/introspection-data.js +107 -186
- package/dist/generated/introspection-data.js.map +1 -1
- package/dist/generated/version-data.d.ts +1 -1
- package/dist/generated/version-data.js +3 -3
- package/dist/generated/version-data.js.map +1 -1
- package/dist/highlight-map.d.ts +4 -0
- package/dist/highlight-map.d.ts.map +1 -0
- package/dist/highlight-map.js +71 -0
- package/dist/highlight-map.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lexer/errors.d.ts.map +1 -1
- package/dist/lexer/errors.js +9 -3
- package/dist/lexer/errors.js.map +1 -1
- package/dist/lexer/operators.js +1 -1
- package/dist/lexer/tokenizer.d.ts.map +1 -1
- package/dist/lexer/tokenizer.js +0 -14
- package/dist/lexer/tokenizer.js.map +1 -1
- package/dist/parser/helpers.d.ts +8 -0
- package/dist/parser/helpers.d.ts.map +1 -1
- package/dist/parser/helpers.js +4 -4
- package/dist/parser/helpers.js.map +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +1 -1
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/parser-collect.js +1 -1
- package/dist/parser/parser-collect.js.map +1 -1
- package/dist/parser/parser-control.js +4 -4
- package/dist/parser/parser-control.js.map +1 -1
- package/dist/parser/parser-expr.js +32 -10
- package/dist/parser/parser-expr.js.map +1 -1
- package/dist/parser/parser-extract.js +7 -3
- package/dist/parser/parser-extract.js.map +1 -1
- package/dist/parser/parser-functions.d.ts.map +1 -1
- package/dist/parser/parser-functions.js +7 -18
- package/dist/parser/parser-functions.js.map +1 -1
- package/dist/parser/parser-literals.js +15 -15
- package/dist/parser/parser-literals.js.map +1 -1
- package/dist/parser/parser-script.js +3 -3
- package/dist/parser/parser-script.js.map +1 -1
- package/dist/parser/parser-variables.js +4 -4
- package/dist/parser/parser-variables.js.map +1 -1
- package/dist/parser/state.d.ts +1 -1
- package/dist/parser/state.d.ts.map +1 -1
- package/dist/parser/state.js +2 -2
- package/dist/parser/state.js.map +1 -1
- package/dist/runtime/core/callable.d.ts +20 -0
- package/dist/runtime/core/callable.d.ts.map +1 -1
- package/dist/runtime/core/callable.js +30 -7
- package/dist/runtime/core/callable.js.map +1 -1
- package/dist/runtime/core/context.d.ts +21 -0
- package/dist/runtime/core/context.d.ts.map +1 -1
- package/dist/runtime/core/context.js +75 -4
- package/dist/runtime/core/context.js.map +1 -1
- package/dist/runtime/core/eval/base.d.ts.map +1 -1
- package/dist/runtime/core/eval/base.js +3 -3
- package/dist/runtime/core/eval/base.js.map +1 -1
- package/dist/runtime/core/eval/index.d.ts.map +1 -1
- package/dist/runtime/core/eval/index.js +2 -0
- package/dist/runtime/core/eval/index.js.map +1 -1
- package/dist/runtime/core/eval/mixins/annotations.js +3 -3
- package/dist/runtime/core/eval/mixins/annotations.js.map +1 -1
- package/dist/runtime/core/eval/mixins/closures.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/closures.js +69 -40
- package/dist/runtime/core/eval/mixins/closures.js.map +1 -1
- package/dist/runtime/core/eval/mixins/collections.js +15 -15
- package/dist/runtime/core/eval/mixins/collections.js.map +1 -1
- package/dist/runtime/core/eval/mixins/control-flow.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/control-flow.js +12 -12
- package/dist/runtime/core/eval/mixins/control-flow.js.map +1 -1
- package/dist/runtime/core/eval/mixins/core.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/core.js +12 -13
- package/dist/runtime/core/eval/mixins/core.js.map +1 -1
- package/dist/runtime/core/eval/mixins/expressions.js +9 -9
- package/dist/runtime/core/eval/mixins/expressions.js.map +1 -1
- package/dist/runtime/core/eval/mixins/extraction.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/extraction.js +15 -15
- package/dist/runtime/core/eval/mixins/extraction.js.map +1 -1
- package/dist/runtime/core/eval/mixins/literals.js +22 -22
- package/dist/runtime/core/eval/mixins/literals.js.map +1 -1
- package/dist/runtime/core/eval/mixins/types.js +4 -4
- package/dist/runtime/core/eval/mixins/types.js.map +1 -1
- package/dist/runtime/core/eval/mixins/variables.js +34 -34
- package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
- package/dist/runtime/core/execute.js +3 -3
- package/dist/runtime/core/execute.js.map +1 -1
- package/dist/runtime/core/introspection.d.ts +30 -1
- package/dist/runtime/core/introspection.d.ts.map +1 -1
- package/dist/runtime/core/introspection.js +47 -1
- package/dist/runtime/core/introspection.js.map +1 -1
- package/dist/runtime/core/types.d.ts +11 -0
- package/dist/runtime/core/types.d.ts.map +1 -1
- package/dist/runtime/core/types.js.map +1 -1
- package/dist/runtime/ext/builtins.js +22 -22
- package/dist/runtime/ext/builtins.js.map +1 -1
- package/dist/runtime/ext/extensions.d.ts +1 -1
- package/dist/runtime/ext/extensions.d.ts.map +1 -1
- package/dist/runtime/ext/extensions.js +4 -5
- package/dist/runtime/ext/extensions.js.map +1 -1
- package/dist/runtime/index.d.ts +6 -4
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +3 -2
- package/dist/runtime/index.js.map +1 -1
- package/dist/types.d.ts +36 -37
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +440 -120
- package/dist/types.js.map +1 -1
- package/package.json +7 -66
- package/README.md +0 -223
- package/dist/check/config.d.ts +0 -20
- package/dist/check/config.d.ts.map +0 -1
- package/dist/check/config.js +0 -151
- package/dist/check/config.js.map +0 -1
- package/dist/check/fixer.d.ts +0 -39
- package/dist/check/fixer.d.ts.map +0 -1
- package/dist/check/fixer.js +0 -119
- package/dist/check/fixer.js.map +0 -1
- package/dist/check/index.d.ts +0 -10
- package/dist/check/index.d.ts.map +0 -1
- package/dist/check/index.js +0 -21
- package/dist/check/index.js.map +0 -1
- package/dist/check/rules/anti-patterns.d.ts +0 -65
- package/dist/check/rules/anti-patterns.d.ts.map +0 -1
- package/dist/check/rules/anti-patterns.js +0 -481
- package/dist/check/rules/anti-patterns.js.map +0 -1
- package/dist/check/rules/closures.d.ts +0 -66
- package/dist/check/rules/closures.d.ts.map +0 -1
- package/dist/check/rules/closures.js +0 -370
- package/dist/check/rules/closures.js.map +0 -1
- package/dist/check/rules/collections.d.ts +0 -90
- package/dist/check/rules/collections.d.ts.map +0 -1
- package/dist/check/rules/collections.js +0 -373
- package/dist/check/rules/collections.js.map +0 -1
- package/dist/check/rules/conditionals.d.ts +0 -41
- package/dist/check/rules/conditionals.d.ts.map +0 -1
- package/dist/check/rules/conditionals.js +0 -134
- package/dist/check/rules/conditionals.js.map +0 -1
- package/dist/check/rules/flow.d.ts +0 -46
- package/dist/check/rules/flow.d.ts.map +0 -1
- package/dist/check/rules/flow.js +0 -206
- package/dist/check/rules/flow.js.map +0 -1
- package/dist/check/rules/formatting.d.ts +0 -133
- package/dist/check/rules/formatting.d.ts.map +0 -1
- package/dist/check/rules/formatting.js +0 -648
- package/dist/check/rules/formatting.js.map +0 -1
- package/dist/check/rules/helpers.d.ts +0 -26
- package/dist/check/rules/helpers.d.ts.map +0 -1
- package/dist/check/rules/helpers.js +0 -66
- package/dist/check/rules/helpers.js.map +0 -1
- package/dist/check/rules/index.d.ts +0 -21
- package/dist/check/rules/index.d.ts.map +0 -1
- package/dist/check/rules/index.js +0 -78
- package/dist/check/rules/index.js.map +0 -1
- package/dist/check/rules/loops.d.ts +0 -77
- package/dist/check/rules/loops.d.ts.map +0 -1
- package/dist/check/rules/loops.js +0 -310
- package/dist/check/rules/loops.js.map +0 -1
- package/dist/check/rules/naming.d.ts +0 -21
- package/dist/check/rules/naming.d.ts.map +0 -1
- package/dist/check/rules/naming.js +0 -174
- package/dist/check/rules/naming.js.map +0 -1
- package/dist/check/rules/strings.d.ts +0 -28
- package/dist/check/rules/strings.d.ts.map +0 -1
- package/dist/check/rules/strings.js +0 -79
- package/dist/check/rules/strings.js.map +0 -1
- package/dist/check/rules/types.d.ts +0 -41
- package/dist/check/rules/types.d.ts.map +0 -1
- package/dist/check/rules/types.js +0 -167
- package/dist/check/rules/types.js.map +0 -1
- package/dist/check/types.d.ts +0 -112
- package/dist/check/types.d.ts.map +0 -1
- package/dist/check/types.js +0 -6
- package/dist/check/types.js.map +0 -1
- package/dist/check/validator.d.ts +0 -18
- package/dist/check/validator.d.ts.map +0 -1
- package/dist/check/validator.js +0 -110
- package/dist/check/validator.js.map +0 -1
- package/dist/check/visitor.d.ts +0 -33
- package/dist/check/visitor.d.ts.map +0 -1
- package/dist/check/visitor.js +0 -259
- package/dist/check/visitor.js.map +0 -1
- package/dist/cli-check.d.ts +0 -43
- package/dist/cli-check.d.ts.map +0 -1
- package/dist/cli-check.js +0 -368
- package/dist/cli-check.js.map +0 -1
- package/dist/cli-eval.d.ts +0 -15
- package/dist/cli-eval.d.ts.map +0 -1
- package/dist/cli-eval.js +0 -116
- package/dist/cli-eval.js.map +0 -1
- package/dist/cli-exec.d.ts +0 -49
- package/dist/cli-exec.d.ts.map +0 -1
- package/dist/cli-exec.js +0 -183
- package/dist/cli-exec.js.map +0 -1
- package/dist/cli-module-loader.d.ts +0 -19
- package/dist/cli-module-loader.d.ts.map +0 -1
- package/dist/cli-module-loader.js +0 -83
- package/dist/cli-module-loader.js.map +0 -1
- package/dist/cli-shared.d.ts +0 -44
- package/dist/cli-shared.d.ts.map +0 -1
- package/dist/cli-shared.js +0 -108
- package/dist/cli-shared.js.map +0 -1
- package/dist/cli.d.ts +0 -13
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -62
- package/dist/cli.js.map +0 -1
- package/dist/runtime/core/introspection-data.d.ts +0 -2
- package/dist/runtime/core/introspection-data.d.ts.map +0 -1
- package/dist/runtime/core/introspection-data.js +0 -618
- package/dist/runtime/core/introspection-data.js.map +0 -1
- package/dist/runtime/core/version-data.d.ts +0 -18
- package/dist/runtime/core/version-data.d.ts.map +0 -1
- package/dist/runtime/core/version-data.js +0 -16
- package/dist/runtime/core/version-data.js.map +0 -1
- package/docs/00_INDEX.md +0 -67
- package/docs/01_guide.md +0 -390
- package/docs/02_types.md +0 -504
- package/docs/03_variables.md +0 -324
- package/docs/04_operators.md +0 -629
- package/docs/05_control-flow.md +0 -692
- package/docs/06_closures.md +0 -787
- package/docs/07_collections.md +0 -688
- package/docs/08_iterators.md +0 -330
- package/docs/09_strings.md +0 -205
- package/docs/10_parsing.md +0 -366
- package/docs/11_reference.md +0 -600
- package/docs/12_examples.md +0 -748
- package/docs/13_modules.md +0 -519
- package/docs/14_host-integration.md +0 -985
- package/docs/15_grammar.ebnf +0 -773
- package/docs/16_conventions.md +0 -695
- package/docs/17_cli-tools.md +0 -184
- package/docs/18_design-principles.md +0 -247
- package/docs/19_cookbook.md +0 -628
- package/docs/88_errors.md +0 -902
- package/docs/99_llm-reference.txt +0 -614
- package/docs/assets/logo.png +0 -0
package/docs/06_closures.md
DELETED
|
@@ -1,787 +0,0 @@
|
|
|
1
|
-
# Closures
|
|
2
|
-
|
|
3
|
-
Closures are first-class values that capture their defining scope. This document covers closure semantics, binding behavior, and common patterns.
|
|
4
|
-
|
|
5
|
-
## Expression Delimiters
|
|
6
|
-
|
|
7
|
-
rill has two expression delimiters with deterministic behavior:
|
|
8
|
-
|
|
9
|
-
| Delimiter | Semantics | Produces |
|
|
10
|
-
|-----------|-----------|----------|
|
|
11
|
-
| `{ body }` | Deferred (closure creation) | `ScriptCallable` |
|
|
12
|
-
| `( expr )` | Eager (immediate evaluation) | Result value |
|
|
13
|
-
|
|
14
|
-
**Key distinction:**
|
|
15
|
-
- **Parentheses `( )`** evaluate immediately and return the result
|
|
16
|
-
- **Braces `{ }`** create a closure for later invocation (deferred execution)
|
|
17
|
-
|
|
18
|
-
### Pipe Target Exception
|
|
19
|
-
|
|
20
|
-
When `{ }` appears as a pipe target, it creates a closure and **immediately invokes** it:
|
|
21
|
-
|
|
22
|
-
```rill
|
|
23
|
-
5 -> { $ + 1 } # 6 (same observable result as eager evaluation)
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
This is conceptually two steps happening in sequence:
|
|
27
|
-
|
|
28
|
-
```text
|
|
29
|
-
5 -> { $ + 1 }
|
|
30
|
-
↓
|
|
31
|
-
Step 1: Create closure with implicit $ parameter
|
|
32
|
-
Step 2: Invoke closure with piped value (5) as argument
|
|
33
|
-
↓
|
|
34
|
-
Result: 6
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
The observable result matches eager evaluation, but the mechanism differs. This matters when understanding error messages or debugging—the closure exists momentarily before invocation.
|
|
38
|
-
|
|
39
|
-
**Comparison:**
|
|
40
|
-
|
|
41
|
-
| Expression | Mechanism | Result |
|
|
42
|
-
|------------|-----------|--------|
|
|
43
|
-
| `5 -> { $ + 1 }` | Create closure, invoke with 5 | 6 |
|
|
44
|
-
| `5 -> ($ + 1)` | Evaluate expression with $ = 5 | 6 |
|
|
45
|
-
| `{ $ + 1 } :> $fn` | Create closure, store it | closure |
|
|
46
|
-
| `($ + 1) :> $x` | Error: $ undefined outside pipe | — |
|
|
47
|
-
|
|
48
|
-
The last row shows the key difference: `( )` requires `$` to already be defined, while `{ }` captures `$` as a parameter for later binding.
|
|
49
|
-
|
|
50
|
-
## Closure Syntax
|
|
51
|
-
|
|
52
|
-
```text
|
|
53
|
-
# Block-closure (implicit $ parameter)
|
|
54
|
-
{ body }
|
|
55
|
-
|
|
56
|
-
# Zero-parameter closure (property-style, no parameters)
|
|
57
|
-
|| { body }
|
|
58
|
-
||body # shorthand for simple expressions
|
|
59
|
-
|
|
60
|
-
# With parameters
|
|
61
|
-
|x| { body }
|
|
62
|
-
|x|body # shorthand
|
|
63
|
-
|x, y| { body } # multiple parameters
|
|
64
|
-
|x: string| { body } # typed parameter
|
|
65
|
-
|x: number = 10| { body } # default value (type inferred)
|
|
66
|
-
|x: string = "hi"| { body } # default with explicit type
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Block-Closures
|
|
70
|
-
|
|
71
|
-
Block syntax `{ body }` creates a closure with an implicit `$` parameter. This enables deferred execution and reusable transformations.
|
|
72
|
-
|
|
73
|
-
### Basic Block-Closure
|
|
74
|
-
|
|
75
|
-
```rill
|
|
76
|
-
{ $ + 1 } :> $increment
|
|
77
|
-
|
|
78
|
-
5 -> $increment # 6
|
|
79
|
-
10 -> $increment # 11
|
|
80
|
-
$increment(7) # 8 (direct call also works)
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
The block `{ $ + 1 }` produces a closure. When invoked, `$` is bound to the argument.
|
|
84
|
-
|
|
85
|
-
### Block-Closures vs Zero-Param Closures
|
|
86
|
-
|
|
87
|
-
| Form | Params | `isProperty` | Behavior |
|
|
88
|
-
|------|--------|-------------|----------|
|
|
89
|
-
| `{ body }` (block-closure) | `[{ name: "$" }]` | `false` | Requires argument |
|
|
90
|
-
| `\|\|{ body }` (zero-param) | `[]` | `true` | Auto-invokes on dict access |
|
|
91
|
-
|
|
92
|
-
```rill
|
|
93
|
-
{ $ * 2 } :> $double
|
|
94
|
-
|| { 42 } :> $constant
|
|
95
|
-
|
|
96
|
-
5 -> $double # 10 (requires argument)
|
|
97
|
-
$constant() # 42 (no argument needed)
|
|
98
|
-
|
|
99
|
-
# In dicts
|
|
100
|
-
[
|
|
101
|
-
double: { $ * 2 },
|
|
102
|
-
constant: || { 42 }
|
|
103
|
-
] :> $obj
|
|
104
|
-
|
|
105
|
-
$obj.double(5) # 10 (explicit call required)
|
|
106
|
-
$obj.constant # 42 (auto-invoked on access)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
Block-closures require an argument; zero-param closures do not.
|
|
110
|
-
|
|
111
|
-
### Type Checking
|
|
112
|
-
|
|
113
|
-
Block-closures check type at runtime:
|
|
114
|
-
|
|
115
|
-
```rill
|
|
116
|
-
{ $ + 1 } :> $fn
|
|
117
|
-
|
|
118
|
-
type($fn) # "closure"
|
|
119
|
-
$fn(5) # 6
|
|
120
|
-
$fn("text") # Error: Cannot add string and number
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### Multi-Statement Block-Closures
|
|
124
|
-
|
|
125
|
-
Block-closures can contain multiple statements:
|
|
126
|
-
|
|
127
|
-
```rill
|
|
128
|
-
{
|
|
129
|
-
($ * 2) :> $doubled
|
|
130
|
-
"{$}: doubled is {$doubled}"
|
|
131
|
-
} :> $describe
|
|
132
|
-
|
|
133
|
-
5 -> $describe # "5: doubled is 10"
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### Collection Operations
|
|
137
|
-
|
|
138
|
-
Block-closures integrate with collection operators:
|
|
139
|
-
|
|
140
|
-
```rill
|
|
141
|
-
[1, 2, 3] -> map { $ * 2 } # [2, 4, 6]
|
|
142
|
-
[1, 2, 3] -> filter { $ > 1 } # [2, 3]
|
|
143
|
-
[1, 2, 3] -> fold(0) { $@ + $ } # 6 ($@ is accumulator)
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Eager vs Deferred Evaluation
|
|
147
|
-
|
|
148
|
-
The choice between `( )` and `{ }` determines when code executes:
|
|
149
|
-
|
|
150
|
-
```rill
|
|
151
|
-
# Eager: parentheses evaluate immediately
|
|
152
|
-
5 -> ($ + 1) :> $result
|
|
153
|
-
$result # 6 (number, already computed)
|
|
154
|
-
|
|
155
|
-
# Deferred: braces create closure
|
|
156
|
-
{ $ + 1 } :> $addOne
|
|
157
|
-
type($addOne) # "closure"
|
|
158
|
-
5 -> $addOne # 6
|
|
159
|
-
10 -> $addOne # 11 (invoked later with different value)
|
|
160
|
-
|
|
161
|
-
# Practical difference
|
|
162
|
-
(5 + 1) :> $six # 6 (immediate)
|
|
163
|
-
{ $ + 1 } :> $fn # closure (deferred)
|
|
164
|
-
|
|
165
|
-
$six # 6
|
|
166
|
-
10 -> $fn # 11
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
Use `( )` when you want the result now. Use `{ }` when you want reusable logic.
|
|
170
|
-
|
|
171
|
-
## Late Binding
|
|
172
|
-
|
|
173
|
-
Closures resolve captured variables at **call time**, not definition time. This enables recursive patterns and forward references.
|
|
174
|
-
|
|
175
|
-
### Basic Example
|
|
176
|
-
|
|
177
|
-
```rill
|
|
178
|
-
10 :> $x
|
|
179
|
-
||($x + 5) :> $fn
|
|
180
|
-
20 :> $x
|
|
181
|
-
$fn() # 25 (sees current $x=20, not $x=10 at definition)
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### Recursive Closures
|
|
185
|
-
|
|
186
|
-
```rill
|
|
187
|
-
|n| { ($n < 1) ? 1 ! ($n * $factorial($n - 1)) } :> $factorial
|
|
188
|
-
$factorial(5) # 120
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
The closure references `$factorial` before it exists. Late binding resolves `$factorial` when the closure executes.
|
|
192
|
-
|
|
193
|
-
### Mutual Recursion
|
|
194
|
-
|
|
195
|
-
```rill
|
|
196
|
-
|n| { ($n == 0) ? true ! $odd($n - 1) } :> $even
|
|
197
|
-
|n| { ($n == 0) ? false ! $even($n - 1) } :> $odd
|
|
198
|
-
$even(4) # true
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### Forward References
|
|
202
|
-
|
|
203
|
-
```rill
|
|
204
|
-
[
|
|
205
|
-
|| { $helper(1) },
|
|
206
|
-
|| { $helper(2) }
|
|
207
|
-
] :> $handlers
|
|
208
|
-
|
|
209
|
-
|n| { $n * 10 } :> $helper # defined after closures
|
|
210
|
-
|
|
211
|
-
$handlers[0]() # 10
|
|
212
|
-
$handlers[1]() # 20
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### Variable Mutation Visibility
|
|
216
|
-
|
|
217
|
-
Closures see the current value of captured variables:
|
|
218
|
-
|
|
219
|
-
```rill
|
|
220
|
-
0 :> $counter
|
|
221
|
-
|| { $counter } :> $get
|
|
222
|
-
|| { $counter + 1 } :> $getPlus1
|
|
223
|
-
|
|
224
|
-
5 :> $counter
|
|
225
|
-
|
|
226
|
-
[$get(), $getPlus1()] # [5, 6]
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
## Dict-Bound Closures
|
|
230
|
-
|
|
231
|
-
Closures stored in dicts have `$` late-bound to the containing dict at invocation (like `this` in other languages).
|
|
232
|
-
|
|
233
|
-
### Zero-Arg Closures Auto-Invoke
|
|
234
|
-
|
|
235
|
-
```rill
|
|
236
|
-
[
|
|
237
|
-
name: "toolkit",
|
|
238
|
-
count: 3,
|
|
239
|
-
summary: || { "{$.name}: {$.count} items" }
|
|
240
|
-
] :> $obj
|
|
241
|
-
|
|
242
|
-
$obj.summary # "toolkit: 3 items" (auto-invoked on access)
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
### Accessing Sibling Fields
|
|
246
|
-
|
|
247
|
-
```rill
|
|
248
|
-
[
|
|
249
|
-
width: 10,
|
|
250
|
-
height: 5,
|
|
251
|
-
area: || { $.width * $.height }
|
|
252
|
-
] :> $rect
|
|
253
|
-
|
|
254
|
-
$rect.area # 50
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
### Parameterized Dict Closures
|
|
258
|
-
|
|
259
|
-
```rill
|
|
260
|
-
[
|
|
261
|
-
name: "tools",
|
|
262
|
-
greet: |x| { "{$.name} says: {$x}" }
|
|
263
|
-
] :> $obj
|
|
264
|
-
|
|
265
|
-
$obj.greet("hello") # "tools says: hello"
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Reusable Closures Across Dicts
|
|
269
|
-
|
|
270
|
-
```rill
|
|
271
|
-
|| { "{$.name}: {$.count} items" } :> $describer
|
|
272
|
-
|
|
273
|
-
[name: "tools", count: 3, str: $describer] :> $obj1
|
|
274
|
-
[name: "actions", count: 5, str: $describer] :> $obj2
|
|
275
|
-
|
|
276
|
-
$obj1.str # "tools: 3 items"
|
|
277
|
-
$obj2.str # "actions: 5 items"
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
### Calling Sibling Methods
|
|
281
|
-
|
|
282
|
-
```rill
|
|
283
|
-
[
|
|
284
|
-
double: |n| { $n * 2 },
|
|
285
|
-
quad: |n| { $.double($.double($n)) }
|
|
286
|
-
] :> $math
|
|
287
|
-
|
|
288
|
-
$math.quad(3) # 12
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
## List-Stored Closures
|
|
292
|
-
|
|
293
|
-
Closures in lists maintain their defining scope. Invoke via bracket access:
|
|
294
|
-
|
|
295
|
-
```rill
|
|
296
|
-
[
|
|
297
|
-
|x| { $x + 1 },
|
|
298
|
-
|x| { $x * 2 },
|
|
299
|
-
|x| { $x * $x }
|
|
300
|
-
] :> $transforms
|
|
301
|
-
|
|
302
|
-
$transforms[0](5) # 6
|
|
303
|
-
$transforms[1](5) # 10
|
|
304
|
-
$transforms[2](5) # 25
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
### Chaining List Closures
|
|
308
|
-
|
|
309
|
-
```rill
|
|
310
|
-
|n| { $n + 1 } :> $inc
|
|
311
|
-
|n| { $n * 2 } :> $double
|
|
312
|
-
|
|
313
|
-
5 -> @[$inc, $double, $inc] # 13: (5+1)*2+1
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
## Inline Closures
|
|
317
|
-
|
|
318
|
-
Closures can appear inline in expressions:
|
|
319
|
-
|
|
320
|
-
```rill
|
|
321
|
-
[1, 2, 3] -> map |x| { $x * 2 } # [2, 4, 6]
|
|
322
|
-
|
|
323
|
-
[1, 2, 3] -> filter |x| { $x > 1 } # [2, 3]
|
|
324
|
-
|
|
325
|
-
[1, 2, 3] -> fold(0) |acc, x| { $acc + $x } # 6
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
### Inline with Block Bodies
|
|
329
|
-
|
|
330
|
-
```rill
|
|
331
|
-
[1, 2, 3] -> map |x| {
|
|
332
|
-
($x * 10) :> $scaled
|
|
333
|
-
"{$x} -> {$scaled}"
|
|
334
|
-
}
|
|
335
|
-
# ["1 -> 10", "2 -> 20", "3 -> 30"]
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
## Nested Closures
|
|
339
|
-
|
|
340
|
-
Closures can contain closures. Each captures its defining scope:
|
|
341
|
-
|
|
342
|
-
```rill
|
|
343
|
-
|n| { || { $n } } :> $makeGetter
|
|
344
|
-
$makeGetter(42)() # 42
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
### Closure Factory Pattern
|
|
348
|
-
|
|
349
|
-
```rill
|
|
350
|
-
|multiplier| {
|
|
351
|
-
|x| { $x * $multiplier }
|
|
352
|
-
} :> $makeMultiplier
|
|
353
|
-
|
|
354
|
-
$makeMultiplier(3) :> $triple
|
|
355
|
-
$makeMultiplier(10) :> $tenX
|
|
356
|
-
|
|
357
|
-
$triple(5) # 15
|
|
358
|
-
$tenX(5) # 50
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### Nested Late Binding
|
|
362
|
-
|
|
363
|
-
```rill
|
|
364
|
-
1 :> $x
|
|
365
|
-
|| { || { $x } } :> $outer
|
|
366
|
-
5 :> $x
|
|
367
|
-
$outer()() # 5 (inner closure sees updated $x)
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
## Parameter Shadowing
|
|
371
|
-
|
|
372
|
-
Closure parameters shadow captured variables of the same name:
|
|
373
|
-
|
|
374
|
-
```rill
|
|
375
|
-
100 :> $x
|
|
376
|
-
|x| { $x * 2 } :> $double
|
|
377
|
-
$double(5) # 10 (parameter $x=5 shadows captured $x=100)
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
## Scope Isolation
|
|
381
|
-
|
|
382
|
-
### Loop Closures
|
|
383
|
-
|
|
384
|
-
Each loop iteration creates a new child scope. Capture variables explicitly to preserve per-iteration values:
|
|
385
|
-
|
|
386
|
-
```rill
|
|
387
|
-
# Capture $ into named variable for each iteration
|
|
388
|
-
[1, 2, 3] -> each {
|
|
389
|
-
$ :> $item
|
|
390
|
-
|| { $item }
|
|
391
|
-
} :> $closures
|
|
392
|
-
|
|
393
|
-
[$closures[0](), $closures[1](), $closures[2]()] # [1, 2, 3]
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
**Note:** `$` (pipeValue) is a context property, not a variable. Use explicit capture for closure access.
|
|
397
|
-
|
|
398
|
-
### Conditional Branch Closures
|
|
399
|
-
|
|
400
|
-
```rill
|
|
401
|
-
10 :> $x
|
|
402
|
-
true ? { || { $x } } ! { || { 0 } } :> $fn
|
|
403
|
-
20 :> $x
|
|
404
|
-
$fn() # 20 (late binding sees updated $x)
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
## Invocation Patterns
|
|
408
|
-
|
|
409
|
-
### Direct Call
|
|
410
|
-
|
|
411
|
-
```rill
|
|
412
|
-
|x| { $x + 1 } :> $inc
|
|
413
|
-
$inc(5) # 6
|
|
414
|
-
|
|
415
|
-
{ $ + 1 } :> $inc
|
|
416
|
-
$inc(5) # 6 (block-closure)
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
### Pipe Call
|
|
420
|
-
|
|
421
|
-
```rill
|
|
422
|
-
|x| { $x + 1 } :> $inc
|
|
423
|
-
5 -> $inc() # 6
|
|
424
|
-
|
|
425
|
-
{ $ + 1 } :> $inc
|
|
426
|
-
5 -> $inc # 6 (block-closure, no parens needed)
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
Block-closures work seamlessly with pipe syntax since `$` receives the piped value.
|
|
430
|
-
|
|
431
|
-
### Postfix Invocation
|
|
432
|
-
|
|
433
|
-
Call closures from bracket access or expressions:
|
|
434
|
-
|
|
435
|
-
```rill
|
|
436
|
-
[|x| { $x * 2 }] :> $fns
|
|
437
|
-
$fns[0](5) # 10
|
|
438
|
-
|
|
439
|
-
[{ $ * 2 }] :> $fns
|
|
440
|
-
$fns[0](5) # 10 (block-closure)
|
|
441
|
-
|
|
442
|
-
|| { |n| { $n * 2 } } :> $factory
|
|
443
|
-
$factory()(5) # 10 (chained invocation)
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
### Method Access After Bracket (Requires Grouping)
|
|
447
|
-
|
|
448
|
-
```rill
|
|
449
|
-
["hello", "world"] :> $list
|
|
450
|
-
|
|
451
|
-
# Use grouping to call method on bracket result
|
|
452
|
-
($list[0]).upper # "HELLO"
|
|
453
|
-
|
|
454
|
-
# Or use pipe syntax
|
|
455
|
-
$list[0] -> .upper # "HELLO"
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
Note: `$list[0].upper` parses `.upper` as field access on `$list`, not as a method call on the element. This throws an error since lists don't have an `upper` field.
|
|
459
|
-
|
|
460
|
-
## Parameter Metadata
|
|
461
|
-
|
|
462
|
-
Closures expose parameter metadata via the `.params` property. This enables runtime introspection of function signatures.
|
|
463
|
-
|
|
464
|
-
### Basic Usage
|
|
465
|
-
|
|
466
|
-
```rill
|
|
467
|
-
|x, y| { $x + $y } :> $add
|
|
468
|
-
$add.params
|
|
469
|
-
# [
|
|
470
|
-
# x: [type: ""],
|
|
471
|
-
# y: [type: ""]
|
|
472
|
-
# ]
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
### Typed Parameters
|
|
476
|
-
|
|
477
|
-
```rill
|
|
478
|
-
|name: string, age: number| { "{$name}: {$age}" } :> $format
|
|
479
|
-
$format.params
|
|
480
|
-
# [
|
|
481
|
-
# name: [type: "string"],
|
|
482
|
-
# age: [type: "number"]
|
|
483
|
-
# ]
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
### Block-Closures
|
|
487
|
-
|
|
488
|
-
Block-closures have an implicit `$` parameter:
|
|
489
|
-
|
|
490
|
-
```rill
|
|
491
|
-
{ $ * 2 } :> $double
|
|
492
|
-
$double.params
|
|
493
|
-
# [
|
|
494
|
-
# $: [type: ""]
|
|
495
|
-
# ]
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
### Zero-Parameter Closures
|
|
499
|
-
|
|
500
|
-
```rill
|
|
501
|
-
|| { 42 } :> $constant
|
|
502
|
-
$constant.params
|
|
503
|
-
# []
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
### Practical Use Cases
|
|
507
|
-
|
|
508
|
-
**Generic Function Wrapper:**
|
|
509
|
-
|
|
510
|
-
```rill
|
|
511
|
-
|fn| {
|
|
512
|
-
$fn.params -> .keys -> .len :> $count
|
|
513
|
-
"Function has {$count} parameter(s)"
|
|
514
|
-
} :> $describe
|
|
515
|
-
|
|
516
|
-
|x, y| { $x + $y } :> $add
|
|
517
|
-
$describe($add) # "Function has 2 parameter(s)"
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
**Validation:**
|
|
521
|
-
|
|
522
|
-
```text
|
|
523
|
-
|fn| {
|
|
524
|
-
$fn.params -> .entries -> each {
|
|
525
|
-
$[1].type -> .empty ? "Missing type annotation: {$[0]}" ! ""
|
|
526
|
-
} -> filter { !$ -> .empty }
|
|
527
|
-
} :> $checkTypes
|
|
528
|
-
|
|
529
|
-
|x, y: number| { $x + $y } :> $partial
|
|
530
|
-
$checkTypes($partial) # ["Missing type annotation: x"]
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
## Parameter Annotations
|
|
534
|
-
|
|
535
|
-
Parameters can have their own annotations using `^(key: value)` syntax after the parameter name. These attach metadata to individual parameters for validation, configuration, or documentation purposes.
|
|
536
|
-
|
|
537
|
-
### Syntax and Ordering
|
|
538
|
-
|
|
539
|
-
Parameter annotations appear in a specific order:
|
|
540
|
-
|
|
541
|
-
```text
|
|
542
|
-
|paramName: type ^(annotations) = default| body
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
**Ordering rules:**
|
|
546
|
-
1. Parameter name (required)
|
|
547
|
-
2. Type annotation with `:` (optional)
|
|
548
|
-
3. Parameter annotations with `^()` (optional)
|
|
549
|
-
4. Default value with `=` (optional)
|
|
550
|
-
|
|
551
|
-
```rill
|
|
552
|
-
|x: number ^(min: 0, max: 100)|($x) :> $validate
|
|
553
|
-
|name: string ^(required: true) = "guest"|($name) :> $greet
|
|
554
|
-
|count ^(cache: true) = 0|($count) :> $process
|
|
555
|
-
```
|
|
556
|
-
|
|
557
|
-
### Access Pattern
|
|
558
|
-
|
|
559
|
-
Parameter annotations are accessed via `.params.paramName.__annotations.key`:
|
|
560
|
-
|
|
561
|
-
```rill
|
|
562
|
-
|x: number ^(min: 0, max: 100), y: string|($x + $y) :> $fn
|
|
563
|
-
|
|
564
|
-
$fn.params
|
|
565
|
-
# Returns:
|
|
566
|
-
# [
|
|
567
|
-
# x: [type: "number", __annotations: [min: 0, max: 100]],
|
|
568
|
-
# y: [type: "string"]
|
|
569
|
-
# ]
|
|
570
|
-
|
|
571
|
-
$fn.params.x.__annotations.min # 0
|
|
572
|
-
$fn.params.x.__annotations.max # 100
|
|
573
|
-
$fn.params.y.?__annotations # false (no annotations on y)
|
|
574
|
-
```
|
|
575
|
-
|
|
576
|
-
### Validation Metadata
|
|
577
|
-
|
|
578
|
-
Use parameter annotations to specify constraints:
|
|
579
|
-
|
|
580
|
-
```rill
|
|
581
|
-
|value: number ^(min: 0, max: 100)|($value) :> $bounded
|
|
582
|
-
|
|
583
|
-
$bounded.params.value.__annotations.min # 0
|
|
584
|
-
$bounded.params.value.__annotations.max # 100
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
**Generic validator pattern:**
|
|
588
|
-
|
|
589
|
-
```text
|
|
590
|
-
|fn, arg| {
|
|
591
|
-
$fn.params -> .entries -> .head -> *<$name, $meta>
|
|
592
|
-
$meta.?__annotations ? {
|
|
593
|
-
($arg < $meta.__annotations.min) ? "Value {$arg} below min {$meta.__annotations.min}" !
|
|
594
|
-
($arg > $meta.__annotations.max) ? "Value {$arg} above max {$meta.__annotations.max}" !
|
|
595
|
-
""
|
|
596
|
-
} ! ""
|
|
597
|
-
} :> $validate
|
|
598
|
-
|
|
599
|
-
|x: number ^(min: 0, max: 10)|($x) :> $ranged
|
|
600
|
-
$validate($ranged, 15) # "Value 15 above max 10"
|
|
601
|
-
```
|
|
602
|
-
|
|
603
|
-
### Caching Hints
|
|
604
|
-
|
|
605
|
-
Mark parameters that should trigger caching behavior:
|
|
606
|
-
|
|
607
|
-
```rill
|
|
608
|
-
|key: string ^(cache: true)|($key) :> $fetch
|
|
609
|
-
|
|
610
|
-
$fetch.params.key.__annotations.cache # true
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
### Format Specifications
|
|
614
|
-
|
|
615
|
-
Attach formatting metadata to parameters:
|
|
616
|
-
|
|
617
|
-
```rill
|
|
618
|
-
|timestamp: string ^(format: "ISO8601")|($timestamp) :> $formatDate
|
|
619
|
-
|
|
620
|
-
$formatDate.params.timestamp.__annotations.format # "ISO8601"
|
|
621
|
-
```
|
|
622
|
-
|
|
623
|
-
### Multiple Annotations
|
|
624
|
-
|
|
625
|
-
Parameters can have multiple annotations:
|
|
626
|
-
|
|
627
|
-
```rill
|
|
628
|
-
|email: string ^(required: true, pattern: ".*@.*", maxLength: 100)|($email) :> $validateEmail
|
|
629
|
-
|
|
630
|
-
$validateEmail.params.email.__annotations.required # true
|
|
631
|
-
$validateEmail.params.email.__annotations.pattern # ".*@.*"
|
|
632
|
-
$validateEmail.params.email.__annotations.maxLength # 100
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
### Annotation-Driven Logic
|
|
636
|
-
|
|
637
|
-
Use parameter annotations to drive runtime behavior:
|
|
638
|
-
|
|
639
|
-
```text
|
|
640
|
-
|processor| {
|
|
641
|
-
$processor.params -> .entries -> each {
|
|
642
|
-
$[1].?__annotations ? {
|
|
643
|
-
$[1].__annotations.?required ? "Parameter {$[0]} is required" ! ""
|
|
644
|
-
} ! ""
|
|
645
|
-
} -> filter { !$ -> .empty }
|
|
646
|
-
} :> $getRequiredParams
|
|
647
|
-
|
|
648
|
-
|x, y: string ^(required: true), z|($x) :> $fn
|
|
649
|
-
$getRequiredParams($fn) # ["Parameter y is required"]
|
|
650
|
-
```
|
|
651
|
-
|
|
652
|
-
### Checking for Annotations
|
|
653
|
-
|
|
654
|
-
Use existence check `.?__annotations` to determine if a parameter has annotations:
|
|
655
|
-
|
|
656
|
-
```rill
|
|
657
|
-
|x: number ^(min: 0), y: string|($x + $y) :> $fn
|
|
658
|
-
|
|
659
|
-
$fn.params.x.?__annotations # true
|
|
660
|
-
$fn.params.y.?__annotations # false
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
## Annotation Reflection
|
|
664
|
-
|
|
665
|
-
Closures support annotation reflection via `.^key` syntax. Annotations attach metadata to closures for runtime introspection.
|
|
666
|
-
|
|
667
|
-
**Type Restriction:** Only closures support annotation reflection. Accessing `.^key` on primitives throws `RUNTIME_TYPE_ERROR`.
|
|
668
|
-
|
|
669
|
-
### Basic Annotation Access
|
|
670
|
-
|
|
671
|
-
```rill
|
|
672
|
-
^(min: 0, max: 100) |x|($x) :> $fn
|
|
673
|
-
|
|
674
|
-
$fn.^min # 0
|
|
675
|
-
$fn.^max # 100
|
|
676
|
-
```
|
|
677
|
-
|
|
678
|
-
### Complex Annotation Values
|
|
679
|
-
|
|
680
|
-
Annotations can hold any value type:
|
|
681
|
-
|
|
682
|
-
```rill
|
|
683
|
-
^(config: [timeout: 30, endpoints: ["a", "b"]]) |x|($x) :> $fn
|
|
684
|
-
|
|
685
|
-
$fn.^config.timeout # 30
|
|
686
|
-
$fn.^config.endpoints[0] # "a"
|
|
687
|
-
```
|
|
688
|
-
|
|
689
|
-
### Default Value Coalescing
|
|
690
|
-
|
|
691
|
-
Use the default value operator for optional annotations:
|
|
692
|
-
|
|
693
|
-
```rill
|
|
694
|
-
|x|($x) :> $fn
|
|
695
|
-
$fn.^timeout ?? 30 # 30 (uses default when annotation missing)
|
|
696
|
-
|
|
697
|
-
^(timeout: 60) |x|($x) :> $withTimeout
|
|
698
|
-
$withTimeout.^timeout ?? 30 # 60 (uses annotated value)
|
|
699
|
-
```
|
|
700
|
-
|
|
701
|
-
### Annotation-Driven Logic
|
|
702
|
-
|
|
703
|
-
```rill
|
|
704
|
-
^(enabled: true) |x|($x) :> $processor
|
|
705
|
-
|
|
706
|
-
$processor.^enabled ? "processing" ! "disabled" # "processing"
|
|
707
|
-
```
|
|
708
|
-
|
|
709
|
-
### Dynamic Annotations
|
|
710
|
-
|
|
711
|
-
Annotation values are evaluated at closure creation:
|
|
712
|
-
|
|
713
|
-
```rill
|
|
714
|
-
10 :> $base
|
|
715
|
-
^(limit: $base * 10) |x|($x) :> $fn
|
|
716
|
-
$fn.^limit # 100
|
|
717
|
-
```
|
|
718
|
-
|
|
719
|
-
### Error Cases
|
|
720
|
-
|
|
721
|
-
**Undefined Annotation Key:**
|
|
722
|
-
|
|
723
|
-
```rill
|
|
724
|
-
|x|($x) :> $fn
|
|
725
|
-
$fn.^missing # Error: RUNTIME_UNDEFINED_ANNOTATION
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
**Non-Closure Type:**
|
|
729
|
-
|
|
730
|
-
```text
|
|
731
|
-
"hello" :> $str
|
|
732
|
-
$str.^key # Error: RUNTIME_TYPE_ERROR
|
|
733
|
-
```
|
|
734
|
-
|
|
735
|
-
All primitive types (string, number, boolean, list, dict) throw `RUNTIME_TYPE_ERROR` when accessing `.^key`.
|
|
736
|
-
|
|
737
|
-
## Error Behavior
|
|
738
|
-
|
|
739
|
-
### Undefined Variables
|
|
740
|
-
|
|
741
|
-
Undefined variables throw an error at call time (rill has no null):
|
|
742
|
-
|
|
743
|
-
```text
|
|
744
|
-
|| { $undefined } :> $fn
|
|
745
|
-
$fn() # Error: Undefined variable: $undefined
|
|
746
|
-
```
|
|
747
|
-
|
|
748
|
-
### Invoking Non-Callable
|
|
749
|
-
|
|
750
|
-
```rill
|
|
751
|
-
[1, 2, 3] :> $list
|
|
752
|
-
$list[0]() # Error: Cannot invoke non-callable value (got number)
|
|
753
|
-
```
|
|
754
|
-
|
|
755
|
-
### Type Errors
|
|
756
|
-
|
|
757
|
-
```rill
|
|
758
|
-
|x: string| { $x } :> $fn
|
|
759
|
-
$fn(42) # Error: Parameter type mismatch: x expects string, got number
|
|
760
|
-
```
|
|
761
|
-
|
|
762
|
-
## Implementation Notes
|
|
763
|
-
|
|
764
|
-
### Scope Chain
|
|
765
|
-
|
|
766
|
-
Closures store a reference to their defining scope (`definingScope`). At invocation:
|
|
767
|
-
1. A child context is created with `definingScope` as parent
|
|
768
|
-
2. Parameters are bound in the child context
|
|
769
|
-
3. Variable lookups traverse: local → definingScope → parent chain
|
|
770
|
-
|
|
771
|
-
### Memory Considerations
|
|
772
|
-
|
|
773
|
-
- Closures hold references to their defining scope
|
|
774
|
-
- Scopes form a tree structure (no circular references)
|
|
775
|
-
- Scopes remain live while referenced by closures
|
|
776
|
-
|
|
777
|
-
### Performance
|
|
778
|
-
|
|
779
|
-
- Variable lookup traverses the scope chain at each access
|
|
780
|
-
- No caching (ensures mutation visibility)
|
|
781
|
-
- Closure creation is lightweight (stores reference, not copy)
|
|
782
|
-
|
|
783
|
-
## Related Documentation
|
|
784
|
-
|
|
785
|
-
- [Reference](11_reference.md) — Language specification
|
|
786
|
-
- [Collections](07_collections.md) — `each`, `map`, `filter`, `fold` with closures
|
|
787
|
-
- [Guide](01_guide.md) — Getting started tutorial
|