Skip to content

Commit 32eb327

Browse files
committed
__mindex
1 parent 0b51b32 commit 32eb327

File tree

3 files changed

+35
-29
lines changed

3 files changed

+35
-29
lines changed

docs/Compatibility.md

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -75,31 +75,3 @@ These are what they look like:
7575
- `pluto_export`
7676
- `pluto_try`
7777
- `pluto_catch`
78-
79-
## Default Table Metatable
80-
81-
This is [a feature in Pluto](Runtime%20Environment/Global%20&%20Base#default-metatables) that, by itself, is a benign QoL improvement for developers. However, in combination with our added standard library functions like [table.min](Runtime%20Environment/Table#tablemin), it can be an unexpected semantic change:
82-
83-
```pluto showLineNumbers
84-
local function roll(opts)
85-
return math.random(opts.min or 1, opts.max or 100)
86-
end
87-
print(roll{ max = 10 })
88-
```
89-
```
90-
pluto: test.pluto:2: bad argument #1 to 'random' (number expected, got function)
91-
stack traceback:
92-
[C]: in function 'math.rand'
93-
test.pluto:2: in local 'roll'
94-
test.pluto:4: in main chunk
95-
```
96-
97-
Integrators can disable this feature by defining the `PLUTO_NO_DEFAULT_TABLE_METATABLE` macro in their luaconf.h or build config, to aid in a smooth transition, should scripts in their ecosystem require it.
98-
99-
Scripters are advised to use `rawget` and/or `type` to better codify their expectations. For example, the example above seems to care only about providing fallback values and not at all about type-checking, so `rawget` would be an excellent fit for it:
100-
```pluto
101-
local function roll(opts)
102-
return math.random(rawget(opts, "min") or 1, rawget(opts, "max") or 100)
103-
end
104-
print(roll{ max = 10 })
105-
```
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
The `__mindex` metatable field is accessed when a method call is attempted on a nil value.
2+
3+
```pluto
4+
local t = setmetatable({}, {
5+
__mindex = {
6+
function sum()
7+
local accum = 0
8+
for self as v do
9+
accum += v
10+
end
11+
return accum
12+
end
13+
}
14+
})
15+
t:insert(1)
16+
t:insert(2)
17+
print(t.sum) --> nil
18+
print(t:sum()) --> 3
19+
```
20+
21+
Notice how the above sample uses `:insert` instead of `table.insert`, this works because:
22+
- Pluto sets a default metatable on every table with `{ __mindex = _G.table }`
23+
- `__mindex` is looked up recursively — in this case the metatable of our metatable has Pluto's default metatable.
24+
25+
Furthermore, note that `__mindex` is only checked after direct/raw access and `__index` lookups have yielded nil:
26+
27+
```pluto
28+
local t = { 1, 2 }
29+
print(t:min()) --> 1
30+
t.min = 1
31+
print(t:min()) -- attempt to call a number value
32+
```

docs/Runtime Environment/Global & Base.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ table.contains(t, 1)
4949
table.concat(t, "\n")
5050
coroutine.resume(c)
5151
```
52-
This behavior is implemented by setting the `__index` metamethod to the respective library (`_G.table` or `_G.coroutine`). If you override the metatable, you may want to replicate that.
52+
The default metatables for the types are as follows:
53+
- Table: `{ __mindex = _G.table }` (using Pluto's own [`__mindex` metamethod](<../New Features/Mindex Metamethod.md>))
54+
- Coroutine/thread: `{ __index = _G.coroutine }`
5355

5456
---
5557
### `dumpvar`

0 commit comments

Comments
 (0)