Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
3

Why should you use newproxy(true) over setmetatable({}, mt)?

Asked by 6 years ago

So I was curious and started to inspect code from Freya which is a framework for Roblox. I was reading the code for Arbiters and saw this code:

--code
Controller.new = Hybrid(function(f)
  local newobs = newproxy(true)
  local omt = getmetatable(newobs)
  for k, v in pairs(ObserverMt) do
    omt[k] = v
  end
  ObserverCallbacks[newobs] = f
  ObserverEmitters[newobs] = Event.new()
  ObserverRules[newobs] = { }
end)
--more code

The part that I'm curious about is

local omt = getmetatable(newobs)
for k, v in pairs(ObserverMt) do
  omt[k] = v
end

I searched up on the wiki about newproxy and all it does is create a blank userdata.


Why not just do local omt = setmetatable({}, ObserverMt)?

What does newproxy(true) really do?

Does it have an effect on metatables? If so, what is it?

2 answers

Log in to vote
4
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
6 years ago
Edited 6 years ago

newproxy(true) produces a value of type "userdata", which means it is not a table.

Beyond having a different type(obj), this is significant because Lua distinguishes values by their type in a few inconvenient places.

The most noticeable distinction is that the __len metamethod only applies to userdata which means if you want to override the behavior of the # operator you must use newproxy(true) to create the object.

(This was evidently seen as a mistake and is not the case in Lua 5.2)

As another minor example, a userdata object cannot be equal to (==) a table object, since they have different types, even if they have the same __eq metamethod.

Ad
Log in to vote
3
Answered by 6 years ago
Edited 6 years ago

Userdata has stronger protections
No, don't touch that

Even though Freya has this whole fundamental concept of open data, a lot of the objects rely on being locked down. Why, you ask? Two reasons:

  • If it comes from Freya it should behave predictably
  • It reduces the surface for attacks which target Freya as a vulnerability.

Overall, the newproxy method can have a slightly larger memory footprint, but proper structure optimizations can nullify this and even present advantages over tables. Userdata also can't have any metamethod invocations bypassed through use of the rawset and rawget functions.


Back to the real question

The metatable must be set using getmetatable because setmetatable only works on tables. It's a small price to pay, given Roblox's modification of newproxy to remove userdata templating.

Answer this question