I want to add a conditional to my oop .new function to make it warn with context rather than just erroring.
local Ball = {}
Ball.__index = Ball
local BallSize = Vector3.new(1,1,1)
function Ball.new(Name)
if not Name then warn("Name not provided") return end--Important part!!!!
local NewBall = {}
NewBall.Ball = Instance.new("Part")
NewBall.Ball.Size = BallSize
NewBall.Ball.Parent = game.Workspace
NewBall.Ball.Position = Vector3.new(0,5,0)
NewBall.Ball.Shape = "Ball"
NewBall.Ball.Anchored = true
NewBall.Ball.TopSurface = Enum.SurfaceType.Smooth
NewBall.Ball.BottomSurface = Enum.SurfaceType.Smooth
NewBall.Ball.Name = Name
local BillboardGui = Instance.new("BillboardGui")
BillboardGui.Parent = NewBall.Ball
BillboardGui.AlwaysOnTop = true
BillboardGui.MaxDistance = 50
BillboardGui.Size = UDim2.new(4,0,1,0)
local TextBox = Instance.new("TextLabel")
TextBox.Parent = BillboardGui
TextBox.TextScaled = true
TextBox.Text = Name
TextBox.Size = UDim2.new(1,0,1,0)
TextBox.BackgroundTransparency = 1
NewBall.Connections = {}
local self = setmetatable(NewBall, Ball)
return self
end
function Ball:Connect(BallToConnectTo)
print(self)
self.Connections[BallToConnectTo.Ball.Name] = BallToConnectTo
print(self)
end
return Ball
When I do this, the type annotations go away, which makes it very frustrating to try and write the code using this module.
With the condition commented out:
I’d argue that this is an error that does not need to be handled. Trust the developer (yourself) to fill out the function properly, and allow the script to error if not. Otherwise, assign a default value for Name if it is nil.
I might be missunderstanding you here, but changing
local Ball = {}
Ball.__index = Ball
local BallSize = Vector3.new(1,1,1)
function Ball.new(Name: string)
to
local Ball = {}
Ball.__index = Ball
local BallSize = Vector3.new(1,1,1)
type Ball = {}
function Ball.new(Name: string): Ball
Removes the type anotations even if the condition is commented out. Commenting out the : ball on the .new line fixes it again though.
This does not appear to work:
I believe it doesn’t work because Luau sees that there is a possibility of the function terminating early, so it can’t guarantee it returns a Ball. You fix that by annotating the return type. You said doing that is “tangential” but it’s not. It’s needed.
It is not “weird.” It makes perfect sense why it doesn’t work. Luau has no way of knowing what it will return when you add that conditional, so while the function may WORK, the autocomplete does not.
Setting the conditional to return the class does seem to fix the autocomplete not showing up.
local Ball = {}
Ball.__index = Ball
local BallSize = Vector3.new(1,1,1)
function Ball.new(Name: string)
if not Name then warn("Name not provided") return Ball end
This fixes my original problem but does result in the side effect that the Ball the BallMaker and self is nil (as the metatable was never set) This is the solution and I just need to add a break line of code if the object == the class.
Given that I need to put that break line of code in the local script, I probably will just set the name to something like “unnamed” as @dostakek says or just let it error.
I am new to OOP and type checking so if returning the class is unorthodox, then that is why. But it works for now, I probably would need to find a better solution If I pursue this. It also explains why I think this behavior is “weird”
Or, you could define a type alias and annotate the return type. That way, your early return doesn’t need to return the class. Lmk if you need help with that!
By the time you need to put any conditionals in the constructor, you should probably make a new inherited class instead. Notice how none of the Roblox API constructors ever fail to create an object under normal conditions. (other than type checks, but that is a topic for another time)
For trivial stuff like a name, you could simply do something like this:
I have decided to simply use @Sleazel’s suggestion as it is simpler and easier to switch out, This is very early in my project, so I don’t know exactly how I want to structure it and set up a bunch of types that might not be used later. Thank you for everything though!
It’s great to get in the habit of defining types, even if you don’t know if you’ll use them in the future.
You should also use --!strict. It might feel like a pain at first, and…it is a pain, but the benefits outweigh the consequences. Look at this code (It’s not ugly, but strict Luau needs you to do stuff you wouldn’t do otherwise)
function getConfigFromGui(gui: ScreenGui): ScreenConfig
local config: { [string]: any } do
local module = gui:WaitForChild("Config", 3)
if module ~= nil and module:IsA("ModuleScript") then
config = require(module) :: { [string]: any }
else
config = {}
end
end
return {
enabledAtStart = if config.enabledAtStart ~= nil then config.enabledAtStart else false,
transitionIn = config.transitionIn or emptyPlaceholder,
transitionOut = config.transitionOut or emptyPlaceholder,
ignoreGuiManager = if config.ignoreGuiManager ~= nil then config.ignoreGuiManager else false,
}
end
But it’s a lot harder for there to be runtime errors when using --!strict.