rfcs/docs/metatable-type-functions.md
2024-11-05 23:26:10 -05:00

2.7 KiB

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:

local clock = {}
type Identity = typeof(setmetatable({} :: { time: number }, { __index = clock }))

could be reduced to:

local clock = {}
type Identity = setmetatable<{ time: number }, { __index: clock }>

getmetatable Type Function

Issue #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 } }:

local animal = {}
type Identity = setmetatable<{
	sound: string
}, {
	__index: animal
}>

getmetatable Type Function

In the following code example, ReversedIdentity should evaluate to { __index: animal }:

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!":

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.