goldenstein64 / Copy

A Luau-specialized module for copying any value with state.
https://goldenstein64.github.io/Copy
MIT License
0 stars 0 forks source link

__copy metatable field #15

Open goldenstein64 opened 3 years ago

goldenstein64 commented 3 years ago

It might be more ergonomic to use metatables to describe how table sub-values are copied instead of Copy:CreateContext or Copy:BehaveAs. It would be exactly what a metatable is used for, it would have exactly the same functionality as Copy:BehaveAs, it would stay connected to the normal table (or multiple tables), and it would stay out of the way very easily.

it("can use the '__copy' metatable field", function()
  local sub = {
    key = "some value"
  }

  local some = {
    owned = sub,
    shared = sub
  }

  local mt = {}

  -- __copy represents a mapping of keys to behaviors/symbols for sub-values
  -- omitted keys are treated as default
  mt.__copy = {
    shared = "set"
  }

  setmetatable(some, mt)

  local new = Copy(some)

  expect(new).to.never.equal(owned)
  expect(new.shared).to.equal(some.shared)
  expect(new.owned).to.never.equal(new.owned)
end)

It might also make classes easier to implement?

local someClass = {}

local prototype = {
  owned = {},
  shared = {},
  key = "value"
}

function prototype:Method(name)
  return self.owned[name] or self.shared[name]
end

local mt = {}

mt.__copy = {
  shared = "set"
}

setmetatable(prototype, mt)

someClass.prototype = prototype

function someClass.new()
  return Copy(someClass.prototype)
end

return someClass
goldenstein64 commented 3 years ago

What should happen when Copy.GlobalContext.Keys > {}? Should keys in the metatable be copied and reassigned too?

I suppose Copy.GlobalContext.Keys > {} if and only if Copy.GlobalContext.Meta > {}, and both preferably contain "transform". This wouldn't make any sense at all to implement though. I guess I would just tell the end-user to only use it with keys that are uncopyable, like with a symbol.

goldenstein64 commented 3 years ago

A function counterpart might also be useful:

it("can use '__copy' as a metamethod", function()
  local some = {
    _private_property = "value",
    _private_method = nil,
    public_property = "other value"
  }

  local mt = {}

  function mt.__copy(self, key)
    if key:sub(1, 1) == "_" then
      return "pass"
    else
      return "default"
    end
  end

  setmetatable(some, mt)

  local new = Copy(some)

  expect(new._private_property).to.equal(nil)
  expect(new._private_method).to.equal(nil)
  expect(new.public_property).to.equal("other value")
end)