Create metatable type functions RFC

This commit is contained in:
ffrostfall 2024-11-05 23:26:10 -05:00
parent 03608c7519
commit 150014d99a

View file

@ -0,0 +1,77 @@
# Metatable Type Functions
## Summary
Implement type functions for `getmetatable` and `setmetatable`.
## Motivation
### `setmetatable` Type Function
There is currently no way for users to apply metatable type information to a type without the usage of `typeof()`. This isn't ideal, as it adds verbosity and boilerplate to common patterns such as object-oriented programming. For example, the following:
```lua
local clock = {}
type Identity = typeof(setmetatable({} :: { time: number }, { __index = clock }))
```
could be reduced to:
```lua
local clock = {}
type Identity = setmetatable<{ time: number }, { __index: clock }>
```
### `getmetatable` Type Function
[Issue #1435](https://github.com/luau-lang/luau/issues/1435) is caused by a lack of special behavior for `getmetatable` when the type's metatable has a `__metatable` field. This is fixable in a variety of ways, however a type function has multiple benefits and exposes more type-level expression for users. It fits in nicely with the new solver, as type functions are a cleaner alternative to magic functions.
## Design
### `setmetatable` Type Function
In the following code example, `Identity` should evaluate to `{ sound: string, @metatable: { __index: animal } }`:
```lua
local animal = {}
type Identity = setmetatable<{
sound: string
}, {
__index: animal
}>
```
### `getmetatable` Type Function
In the following code example, `ReversedIdentity` should evaluate to `{ __index: animal }`:
```lua
local animal = {}
type Identity = setmetatable<{
sound: string
}, {
__index: animal
}>
type ReversedIdentity = getmetatable<Identity>
```
Due to `__metamethod`, additional behavior needs to be met. In the following code example, `MetatableType` should evaluate to `"No metatable here!"`:
```lua
type metatable = {
__metatable: "No metatable here!"
}
type MetatableType = getmetatable<setmetatable<{}, metatable>>
```
## Drawbacks
Introducing a large library of "global" type functions can clutter naming space for users.
The name of `setmetatable` has an interpretation of implying a side effect; tables are references, and `setmetatable` is a side-effecting function. It could be argued that `setmetatable` is not a good name for a type function which has no side effects. However, consistency is desirable. A slight rename of a global function could cause confusion, and likely cause mistakes to be made. Type functions also have a precedent of not allowing side effects, so therefore a `setmetatable` type function would not have ambiguity when it comes to side effects.
## Alternatives
Do nothing. `typeof` solves the current issues with accessibility to the current object-oriented programming patterns, and the issue relating to getmetatable can be solved by overloads.