Then, from another script, when I access that variables from that module, and I create variables for those variables so that I don’t have to type the full path, like so:
Then, say a circumstance happens that I want to change those values, the only way to change the actual values the module holds is to type out the full path, “settings.ship.laser.speed = 100”, because laserSpeed is a variable of its own that was set to the value which “settings.ship.laser.speed” contained at the time it was created. The same thing will be true when creating variables based off of properties of objects in the game, or even when creating a variable of another regular variable.
Is there any way in Lua to create a variable “reference”, that would reference the same location in memory of the original module variable or object property, so that i could directly manipulate the module variable without having to type the full path?
With Modules everything just gets replicated over to where you require it from. There’s none of that fancy memory allocation stuff you can do with other languages like C#.
This isn’t the case, either. A module that returns a table will return the pointer to the same table on every time it’s required, because of how Roblox caches it. This, in turn, makes the table possible to edit at runtime.
Well perhaps I worded that poorly. Likewise, requiring from a module doesn’t give you the actual information stored in that module, it just replicates it over in a new table. Data modified from a required module doesn’t actually update within the module?
It does. If you require a module that returns a table it should return that same table every time without any copy mechanics; that’s how it’s worked at least.
I’ve done some C# and C++, and a few other languages in the past and vaguely remember being able to do this sort of thing with variable references in at least one of them. Sometimes I like Lua for its simplicity, but other times I hate it because it means you have to go a longer more tedious route to achieve the same thing. One of the shorthands that I love that I really wish existed in Lua is those simple ones with adding, subtracting, division, and multiplication, like number++ instead of number = number + 1 or number -= 5 instead of number = number - 5, etc.
It works perfectly fine and can be used for cross-script communication for example:
--module script
local module = {count = 0}
return module
--Script1
local counter = require(workspace.ModuleScript)
counter.count = counter.count + 1
print("I counted to ".. counter.count)
--will print "I counted to 1"
--Script2
wait()
local counter = require(workspace.ModuleScript)
counter.count = counter.count + 1
print("I counted to ".. counter.count)
--will print "I counted to 2"
If you want to be fancy you can also do something like this:
--module script
local module = {}
return module
--Script1
local module = require(workspace.ModuleScript)
local name = "Bob"
function giveName()
return name
end
module.giveMeYourName = giveName
--Script2
local module = require(workspace.ModuleScript)
local name = "John"
wait()
local otherGuysName = module.giveMeYourName()
print("Hi "..otherGuysName..", my name is "..name)
--will print "Hi Bob, my name is John"
Here is a pointer implementation. As long as all variables use this pointer, they will all refer to the same value. Since indexing something with nil usually throws an error, I’ve taken over this functionality for pointer de-referencing. Enjoy!
Proxy Module
local data = setmetatable({}, {__mode = 'k'})
local proxy = {
__metatable = 'Proxy metatables are locked';
}
function proxy:__index(key)
if key == nil then
-- dereference
return data[self]
else
return data[self][key]
end
end
function proxy:__newindex(key, value)
if key == nil then
data[self] = value
else
data[self][key] = value
end
end
function proxy:__call(...)
return data[self](...)
end
function proxy:__concat(value)
return data[self] .. value
end
function proxy:__add(value)
return data[self] + value
end
function proxy:__sub(value)
return data[self] - value
end
function proxy:__mul(value)
return data[self] * value
end
function proxy:__div(value)
return data[self] / value
end
function proxy:__mod(value)
return data[self] % value
end
function proxy:__pow(value)
return data[self] ^ value
end
function proxy:__tostring(value)
return '*' .. tostring(data[self])
end
function proxy:__eq(value)
return data[self] == value
end
function proxy:__lt(value)
return data[self] < value
end
function proxy:__le(value)
return data[self] <= value
end
function proxy:__len()
return #data[self]
end
local function newProxy(value)
local new = newproxy(true)
data[new] = value
local metatable = getmetatable(new)
for key, value in next, proxy do
metatable[key] = value
end
return new
end
return newProxy
Example Usage
local Proxy = require(script.Parent.Proxy)
local function mutate(num)
-- dereference and change
num[nil] = num + 1
end
local ptr = Proxy(5)
print(ptr) --> "*5"
mutate(ptr)
print(ptr) --> "*6"
(note that rawset, rawget, getmetatable, setmetatable and type work differently on pointers. You’ll need to de-reference the pointer before calling these functions. Natural operations like + and - don’t make sense on Lua pointers, to I made it act more like a reference in these cases.)
There’s a simple pattern you can use to get behavior like this - getters and setters.
local function getLaserSpeed()
return settings.ship.laser.speed
end
local function setLaserSpeed(value)
settings.ship.laser.speed = value
end
setLaserSpeed(getLaserSpeed() + 1)
Doesn’t require any metatables, straightforward to read/understand/maintain/debug. They’re very common in many languages, I use them both in C++ and Lua daily.
One nice thing about getters/setters is that the actual source of the value can come from anywhere - not just a variable containing it. You can also put code in the setter that does special things whenever the value is changed.
Yeah I’ve actually done a lot of those in other languages. Didn’t really think about that for lua. That’s not bad actually. It’s a few extra lines of code to write for each variable but if you’re going to be getting/setting the variable many times in many places than it’s probably worth it.