I looked and saw this hacky way of getting over cyclic dependency to get types into modules and was wondering if anyone can help me to get it working for OOP compositions???
The way to do it:
Example (signal.lua):
local package = script.Parent.Parent
local packages = package.Parent
type SignalModule = typeof(require(packages.signal))
local getModule = require(package.utilities.getModule)
local signalModule = getModule("signal")
-- i hate this
export type Connection = typeof((function()
local module = require(packages.signal)
return {} :: module.Connection
end)())
export type Signal<T...> = typeof((function()
local module = require(packages.signal)
return {} :: module.Signal<T...>
end)())
return require(signalModule) :: SignalModule
Car.lua
local Engine = require(script.Engine)
local Car = {}
Car.__index = Car
type self = {
["_Engine"]: Engine,
Speed: number
}
type Car = typeof( setmetatable({}, Car) )
export type Car = typeof( setmetatable({} :: self, Car) )
function Car.new(): Car
local self = setmetatable({} :: self, Car)
self._Engine = Engine.new()
self.Speed = 15
return self
end
function Car.Boost(self: Car): ()
self.Speed += 50
end
return Car
Engine.lua
export type Car = typeof((function()
local module = require(script.Parent)
return {} :: typeof(module.new())
end)())
local Engine = {}
Engine.__index = Engine
type self = {
Speed: number
}
type Engine = typeof( setmetatable({}, Engine) )
export type Engine = typeof( setmetatable({} :: self, Engine) )
function Engine.new(Car : Car): Engine
local self = setmetatable({} :: self, Engine)
self.Speed = 15
return self
end
return Engine
What am I missing?
Here in the parameter (Car : Car) just resolves to any type when it should resolve to Car type:
function Engine.new(Car : Car): Engine
local self = setmetatable({} :: self, Engine)
self.Speed = 15
return self
end
@MagmaBurnsV posted about this method and I wanted to adopt it so that I can compose objects inside of each other. Anyone have any ideas please? Any help is appreciated, thanks!
I am having trouble understanding what you mean. Is this possible???
Types.lua (has the types):
local module = {}
local Engine = {}
Engine.__index = Engine
type EngineSelf = {
HorsePower: number
}
type Engine = typeof(setmetatable({}, Engine))
export type Engine = typeof(setmetatable({} :: EngineSelf, Engine))
function Engine.new(): Engine
local self = setmetatable({} :: EngineSelf, Engine)
self.HorsePower = 15
return self
end
module.Engine = Engine
local Car = {}
Car.__index = Car
type CarSelf = {
_Engine: Engine,
Speed: number
}
type Car = typeof(setmetatable({}, Car))
export type Car = typeof(setmetatable({} :: CarSelf, Car))
function Car.new(): Car
local self = setmetatable({} :: CarSelf, Car)
self._Engine = Engine.new()
self.Speed = 15
return self
end
function Car.Boost(self: Car): ()
self.Speed += 50
end
module.Car = Car
return module
In Car.lua, how would I fetch the Engine type from that?
local Types = require(script.Parent.Types)
local Engine = require(script.Engine)
local Car = {}
Car.__index = Car
type self = {
["_Engine"]: Engine,
Speed: number
}
type Car = typeof( setmetatable({}, Car) )
export type Car = typeof( setmetatable({} :: self, Car) )
function Car.new(): Car
local self = setmetatable({} :: self, Car)
self._Engine = Engine.new()
self.Speed = 15
return self
end
function Car.Boost(self: Car): ()
self.Speed += 50
end
return Car
It is a bit messy but it is a proof of concept. I am looking to compose objects in objects and just did that to test if it would work but I am trying to get it to work. What do you think of the above, can we do this to get the Types or did I do it wrong? Bit sloppy but I tried.
im pretty sure the Engine type would already be inside of car.lua if you used Engine.new() because Engine.new() returns an Engine object of the Engine type.
if your asking for the literal type you could just export the engine type
-- a module that holds all the types
export type Engine = {
HorsePower: number
}
export type Car = {
_Engine: Engine
Speed: number
}
-- car module
-- if you want to fetch the engine type you could do it liike this
local types = require(--[[path to type module]])
type Engine = types.Engine
Hey, I have been busy trying to get this to work without cyclic dependency. I have bumped into brick walls but I found a viable method so far and it seems like this is one of the more legit methods. I have not been able to utilize other ways.
With your method of creating a separate Types module or manually typing it up, it will result in a maintenance nightmare over time. I have tried it!
This way is more automatic:
Car.__index = Car
function Car.new(): CarType
local self = setmetatable({}, Car)
self.Engine = Engine.new(self) :: EngineType
self.Speed = 25
return self
end
function Car.Boost(self: CarType): ()
self.Speed += 25
end
function Car.GetEngine(self: CarType): EngineType
return (self.Engine)
end
export type CarType = typeof(Car.new())
Engine.__index = Engine
function Engine.new(Car: CarType): EngineType
local self = setmetatable({}, Engine)
self.Car = Car
self.Health = 0
return self
end
function Engine.Repair(self: EngineType): ()
self.Health = self.Health + 25
end
function Engine.BoostToCar(self: EngineType): ()
local Car = self.Car
Car:Boost()
return ("BOOSTED Car.")
end
export type EngineType = typeof(Engine.new())
Having a bunch of classes in one ModuleScript and separated and then creating separate ModuleScripts to return the specific classes by table:
For example extracting Car.lua class from the MegaSetOfClassesModuleScript.lua:
local Car = (require(script.Parent.ClassesModuleScriptThatContainsAllClasses).Car)
return Car
This ensures everything updates automagically and you do not have to manually type things!
You get the benefits too and this is totally legit.
I have not found another method but I do know that a resource exists that currently is trying to get Typed working so monitoring that:
We will see what happens. LMK if you have any other suggestions though and thank you!
Looks like you opted for the functional paradigm for this instead not everything has to be OOP because it has a lot of limitations…… for future reference you should break down what your really trying to accomplish when making something and identify what you would need for that. And based off of that information you could code in procedurally, functionally, objected oriented or entity component.
What I have found in coding and scripting up to now is that there is seemingly always a limitation or drawback to a paradigm. No paradigm is really free of that so does not matter what you choose. You should just choose a paradigm that matches your thinking style.
In this case, I love thinking in objects and analogies so OOP is a great use case for me. Limitations? There can be some but atp another paradigm would just be a solution searching for a problem (there is no problem really, OOP is really flexible).
If I want to do any of the paradigms that you mentioned, well I don’t have to choose one or the other. I can choose them all.