While there is no doubt my method has more allocations, they are all completely optional. If squeezing out that extra bit of performance is necessary, you can merge all 3 tables together (like the standard idiom). But that defeats the purpose of this idiom, which was to rid developers of the code smells that came with the standard method. Merging the tables together would bring back issue #1 and issue #2, which there is no other alternative to solve. But if in the name of performance you must, feel free to do it. Lastly, if you must make such micro-optimizations, I advise you to ditch OOP entirely.
Would you mind explaining what the benefits of this are? The only place I see it being used is inside the constructor, which leads me to my next question. Why predefine the properties of your object to then redefine them in the constructor? I think it’s better to let the constructor serve as your “prototype” and if you must separate the prototype from your schematic, use a function that returns the prototype only. You can use that function to construct your “prototype type” and inside of the constructor to be less redunant. But still, it’s not obvious to me why you would want to do this.
I’m not sure where I would have to use assertions in the constructor. What do you mean by this?
Perhaps it would be better if you shared your experiment. Here is mine, which proves inheritence is entirely possible with this idiom without the undesired effects you’ve described:
local superClass = {}
superClass.interface = {}
superClass.schema = {}
superClass.metatable = {__index = superClass.schema}
function superClass.interface.new(x: number, y: number)
local self = setmetatable({}, superClass.metatable)
self.x = x
self.y = y
self.z = 5
return self
end
function superClass.schema.addXY(self: superClass)
return self.x + self.y
end
type superClass = typeof(superClass.interface.new(table.unpack(...)))
return superClass
local parentClass = require(script.Parent)
local subClass = {}
subClass.interface = {}
subClass.schema = {}
subClass.metatable = {__index = subClass.schema}
setmetatable(subClass.schema, parentClass.metatable)
function subClass.interface.new(x: number, y: number)
local self = setmetatable(parentClass.interface.new(x, y), subClass.metatable)
self.a = 9
return self
end
function subClass.schema.addZA(self: subClass)
return self.z + self.a
end
type subClass = typeof(subClass.interface.new(table.unpack(...)))
return subClass.interface
I’ve just noticed Roblox script editor is not inferring the subclass types only the super class types. Roblox LSP handles this just fine. Going to look into this more and see if I can get it to work for both. However, the code is running properly, it’s just the type suggestions are slightly incorrect.