How to reference self.var outside of module.new()

Considering the following example code

local module = {}


module.__index = module 
function module.new(area: Frame)
	
	local self = setmetatable({}, module)
	
	self.bounds = {}
	
	self.bounds.x1 = area.Position.X.Offset
	self.bounds.y1 = area.Position.Y.Offset
	self.bounds.x2 = area.Position.X.Offset + area.Size.Y.Offset
	self.bounds.y2 = area.Position.Y.Offset + area.Size.Y.Offset
	
	self.MouseEnter = Instance.new("BindableEvent").Event
	self.MouseExit = Instance.new("BindableEvent").Event
	self.MouseHover = Instance.new("BindableEvent").Event
	--We DON'T parent these as they are only referenced here and in scripts that require them.
	
	area:Destroy() --scary! we've stored the UDim2 data of the frame and no longer need it (the frame).
	
	return self
end

mouse.Move:Connect(function()
	--print(mouse.X, mouse.Y)	--DEBUG ONLY
	
	--somehow ref self.bounds and the self.RBXScriptConnection(s) here?
end)

return module

How do I reference the self.bounds object and self.Mouse... instances outside of the module.new() function without setting both as globals?

You can’t

But moral of the story, you need to pass self into that somehow. Since the function you are trying to use doesn’t have it by default you either have to subscribe to it inside your functions where you keep a local reference of self, or create a self.new() and have its return in a scope (or data structure) visible to your connection.

If you want it to run once, then you would put the module.New in the highest scope (and maybe even directly return that if you are basically doing a Singleton pattern.

But if move needs to effect many things differently, giving each their own move connection inside your .new() is a solid strategy (just make sure you clean them up). Or have a table that holds all the module.new() you make that your connection loops through (still make sure you clean that reference up)

I believe events need to be on scripts not modules.

Examples:

Singleton
local Module = {}
Module.__index = Module

function Module.new()
    local self = setmetatable({}, Module)
    self.Value = 5
    return self
end

local singleton = Module.new()
mouse.Move:Connect(function()
	local self = singleton -- obviously not necessary if you directly use singleton

      --blah blah blah code code code
end)
return singleton -- now everything that requests this module has direct access to singleton
--note that this technically still gives me access to self.new(), so it might be better to have new not a part of the Module table if you really are following a singleton pattern.
Internal connection
local Module = {}
Module.__index = Module

function Module.new()
    local self = setmetatable({}, Module)
    self.Value = 5
    self.ConnectionReference = mouse.Move:Connect(function() self:Move() end) -- keep a reference to disconnect in :Destroy().
    return self
end

function Module:Move() -- this function has access to self if called, gets hooked up in .new()
    print(self.Value) --yay!!!
end

function Module:Destroy()
    self.ConnectionReference:Disconnect() -- let us prevent memory leaks
end

return Module
External list (less clean than Internal connection imo, but gets the job done)
local Module = {}
Module.__index = Module

local modules = {} --hold a reference to all active Modules

function Module.new()
    local self = setmetatable({}, Module)
    self.Value = 5

    modules[self] = true --add module as a dictionary key so that the external function can see it's there
    return self
end

function Module:Destroy()
    modules[self] = nil --removes the dictionary key so as to stop processing it when it no longer exists
end

mouse.Move:Connect(function()
    for self, _ in pairs(modules) do
        --handle each case, might be best to pcall here to make it so an error in one doesn't stop all of them depending on use case
    end
end)

return Module

You can of course slightly mash those together to fit your needs. a move(self) function might be nice instead of directly attaching it to the module if it’s meant to be private for example

Modules are basically functions called inside another script. They can do anything a normal script can do including handle events.

i suppose i could also commit a programmer war crime and insert the mouse listener function into the .new() function… not going to be pretty though… I’ll mark your answer as correct and try implementing it your way. Thanks for the help!

So if you reference the module correctly in a script or local script, all the events and listeners can be in modules? Interesting.