I’m not sure if this fully qualifies as a bug, as this behavior was said to be somewhat intentional in this Luau GitHub issue from 2022, but I thought it’d be interesting to see if maybe this is something worth revisiting.
I’m sure that this issue is very niche and only affects very few people — probably just me — so it’s not exactly important. It just would be nice quality of life if this was allowed.
Anyway, on with the actual bug report…
In one of my projects, I have a prototype-based object system. You call something like:
local prototype = require("path/to/prototype")
local obj = Object.create(prototype, {
veryCoolState = true
})
…and it returns a new ‘object’ of prototype with the passed state.
more irrelevant info on how my object system works
If prototype contained methods like sayHello() and doACoolFlip() then the returned object obj would also contain those methods.
State is the second parameter passed into the Object.create function, it just applies the fields to the object.
So if you passed a state like:
{
isCool = true,
isAwesome = false,
}
…then indexing obj.isCool and obj.isAwesome would return true and false respectively.
This is useful for if you want to set some properties of an object before it gets fully initialized.
Initialization is basically just if a prototype has a New() method, then it is called before returning to the user.
Prototypes are created using a constructor function called Prototype (real creative, i know), which just takes in an info table that contains fields/methods it should contain. It’s also responsible for “compiling” (really need to come up with a better term) any components the prototype may use.
I was going to have a whole example on how this works, but it’s really not important to the bug report so I’ll refrain for now…
Now this works fine on it’s own, but I want the Prototype objects to be completely immutable. Purely read only, just so that you don’t end up accidently modifying the Prototype when you meant to modify an object.
I’m using the __metatable metamethod as a sort of type indicator, which you can retrieve with getmetatable, but you can’t do that with table.freeze.
I suppose that having a type field would also work just fine, but it’s not as elegant. I also know there’s other ways to implement table.freeze using purely metamethods and proxies, but it feels kind of redundant when we have a perfectly fine built-in function that already does that.
Another thing that bugs me is that the documentation for table.freeze and the __metatable metamethod don’t mention anything about how they aren’t compatible with eachother. This seems like a nitpick, as this issue is already super edge-casey, but I feel that it might be worth adding even a small note about how they don’t work together.