I have been playing around with OOP and inheritance, and as I understand it, these are the basics of it:
ModuleScript, named Block
local Block = {}
Block.__index = Block
function Block.new(Name : string) : Block
local self = setmetatable({}, Block)
self.Name = Name
return self
end
function Block:SetName(Name : string)
self.Name = Name
end
export type Block = typeof(setmetatable({}, Block)) & {
Name : string
}
return Block
ModuleScript, named Door
local Block = require(script.Parent.Block)
local Door = {}
Door.__index = Door
setmetatable(Door, Block)
function Door.new(Name : string, Open : boolean) : Door
local self = setmetatable(Block.new(Name), Door)
self.IsOpen = Open
return self
end
function Door:Open()
self.IsOpen = true
end
function Door:Close()
self.IsOpen = false
end
export type Door = typeof(setmetatable({}, Door)) & typeof(setmetatable({}, Block)) & {
IsOpen : boolean
}
return Door
Script for testing
local Door = require(script.Door)
local DoorObject = Door.new("TestDoor", false)
print(DoorObject.Name) --> TestDoor
DoorObject:SetName("Test123Door")
print(DoorObject.Name) --> Test123Door
print(DoorObject.IsOpen) --> false
DoorObject:Open()
print(DoorObject.IsOpen) --> true
It works pretty well and prints what you’d expect. My only concern about it is how the autofill looks while writing code for it:
It includes __index, as well as all the functions, which are only supposed to be usable with the object that’s returned from Door.new()
.
Likewise, the object has the new
function, as well as __index visible.
Even though none of this affects what the code does, I find it really annoying. So I started experimenting, and found this removed most parts of the problem:
ModuleScript, Block
local Block = {}
local BlockFunctions = {}
Block.Metatable = {
__index = BlockFunctions
}
function Block.new(Name : string) : Block
local self = setmetatable({}, Block.Metatable)
self.Name = Name
return self
end
function BlockFunctions:SetName(Name : string)
self.Name = Name
end
export type Block = typeof(setmetatable({}, Block.Metatable)) & {
Name : string
}
return Block
ModuleScript, Door
local Block = require(script.Parent.Block)
local Door = {}
local DoorFunctions = {}
Door.Metatable = {
__index = DoorFunctions
}
setmetatable(DoorFunctions, Block.Metatable)
function Door.new(Name : string, Open : boolean) : Door
local self = setmetatable(Block.new(Name), Door.Metatable)
self.IsOpen = Open
return self
end
function DoorFunctions:Open()
self.IsOpen = true
end
function DoorFunctions:Close()
self.IsOpen = false
end
export type Door = typeof(setmetatable({}, Door.Metatable)) & typeof(setmetatable({}, Block.Metatable)) & {
IsOpen : boolean
}
return Door
This is the result:
It reduces it down to only the Metatable field.
It looks a lot cleaner, and it’s much more clear what functions and properties are actually available.
Finally, my question is: Is this a viable way of doing this, or is there another solution to this problem? Will this negatively affect any aspects of OOP, or is it fine to use this method?