So I was making some combat system and I want to keep the script simple as I can. I wonder If you can create a function without passing an arguement. It’s kinda unsimple adding a variable and pass them into function’s arguement. Here’s an example.
local function callSomething()
print(a,b,c) -- Expecting to print out "1 hi true"
end
game.Players.PlayerAdded:Connect(function()
local a = 1
local b = "hi"
local c = true
callSomething() -- Expecting to call "callSomething" function without an error
end)
That is not gonna work unless the variables are not local to the PlayerAdded listener or you don’t have any perimeters.
local a = 1
local b = "hi"
local c = true
local function callSomething()
print(a,b,c)
end
game.Players.PlayerAdded:Connect(function()
callSomething()
end)
Parameters are necessary for a function if some data is needed to pass into the function, unless there are already global variables that are directly accessible in the function.
Arguments & parameters are in no way complicated; you should not try to work around them. This is the most efficient and practical method for providing information to a function at runtime. For more information on this, you can read my reply to another post
local function callSomething()
print(a,b,c) -- Expecting to print out "1 hi true"
end
game.Players.PlayerAdded:Connect(function()
local a = 1
local b = "hi"
local c = true
callSomething(a, b, c) -- Expecting to call "callSomething" function without an error
end)
or
local a = 1
local b = "hi"
local c = true
local function callSomething()
print(a,b,c) -- Expecting to print out "1 hi true"
end
game.Players.PlayerAdded:Connect(function()
callSomething() -- Expecting to call "callSomething" function without an error
end)
This is known as using upvals, its generally not a good idea because it creates messy state relationships.
Another potential idea is using a closure by capturing the variables beforehand, this effectively gives you a similar approach but encloses the state to that function.
local function capture(a, b, c)
return function()
print(a, b, c) --> a, b, c from capture call
end
end
Though, if you know the arguments ahead of time, just pass them into the function.
I understand that It won’t work for some reason. But the fact that it’s annoying to make alot of arguments and makes the script more messier. And those arguments are something that I need for using in event,signal, or if statements. Something like
local function (Char : Model,EnemyChar : Model,Block : BoolValue,Parry : BoolValue,Hit : BoolValue,Sprint : BoolValue, ...)
end
and I have to set the variables into the function’s parameter in order
You can mitigate long-winded function signatures by removing unnecessary whitespace, new-lining, or packaging parameters into a dictionary, similar to how RaycastParams is used. You can see an example of that in my KillsService module with the “DamageParameters” type
You can declare the variables without the keyword “local”, in this case:
local function callSomething()
print(a,b,c) -- Expecting to print out "1 hi true"
end
game.Players.PlayerAdded:Connect(function()
a = 1
b = "hi"
c = true
callSomething() -- Expecting to call "callSomething" function without an error
end)
This way they are declared as global variables and can be used anywhere within the script. I don’t recommend doing this often though.
“but it’s almost always better to create them with local scope because Luau accesses local variables faster than global ones”
Generally, you should never be writing global variables. The above is a statement from Roblox against them. If you want to make a global variable, forward-declare or initialize that variable at the top of your script. You can justify this practice further as it provides insight into all the globally-accessed variables that will appear and be utilized throughout the script. Allowing yourself to declare global variables at any point in your script makes it hard to track down their origins and know what information is available
You don’t need to use Typechecking if it is a private system that won’t be used by anyone else than yourself, or if theses arguments are guaranteed to be either nil or the expected type/object.
In your case, using a Table to send a bunch of informations between functions, events and scripts would be easier as it require a single argument and no table order is required to do whatever you need to do.
local FightDatas = {}
FightData.Char = --Model
FightData.EnemyChar = --Model
FightData.Block = --BoolValue
FightData.Parry = --BoolValue
FightData.Hit = --BoolValue
FightData.Sprint = --BoolValue
local function Something(DataTable)
if DataTable.Char and DataTable.EnemyChar then
--Example
end
end
Something(FightDatas)
Typechecking is not restricted to code that is localized. Its advantages should be used at every opportunity. You can create a type for the parameter table to preserve what OP had before without continuing to lengthen the function signature beyond reasonable limits
I think it mostly comes down to a personal preference. Personally, I don’t see the point of using type checking when the variables, arguments, or whatever else are guaranteed to be either nil or the expected type/instance. It just increases the code length and, in some cases, makes the code less readable without providing real benefits.
Type analysis grants you greater control over how your code is read and interpreted by the Script Editor since you define what each variable should be read as, and can directly enforce what functions should return.
Not to mention it gives you the gift of autocomplete since variables and parameters are defaulted to “any” which doesn’t describe what the variable is supposed to be.
Examples:
-- Type analyzer
type T = { bar: number, key: "value" }
local function foo(t: T)
t.ba --> 'bar' autocompletes with the given correct type
end
-- No type analyzer
local function foo(t)
t.ba --> 't' is read as 'any' so it doesn't give you any information about the variable, forcing you to remember what it is
end
Another example:
-- string autocomplete
type Modules = "ProfileService" | "DataStore2" | "TopbarPlus"
local function loadModule(name: Modules)
--...
end
loadModule(" --> gives you autocomplete options for each of the defined modules, similar to how typing game:GetService() gives you names for every service
It’s true that you don’t need type analysis, but there’s a reason why languages like TypeScript exist
Yeah, I know that it provides autocomplete, but it’s more of a quality-of-life improvement for coding than something else. It would be much more necessary when working in a team compared to working alone, where you already know what is what and what should be there.
The point is that you can’t guarantee that; at some point, yourself, or someone, will make make a mistake with yours or Roblox’s API. Luau still lacks real type enforcement, and some of these mistakes can go unnoticed with potential polymorphic relationships with the faulty data and the code. These mistakes can cause deep-rooted bugs which are difficult to tedious to resolve. Typechecking can catch this nature of mistake prematurely. Even if the mistakes are trivial, it still saves you and others time.
Types can be complex, by they don’t make the code they’re used in any less readable. Roblox has strong inference as well, so not everything needs to be explicitly typed, allowing the additional code length to be negligible. Furthermore, the annotations used can enable extremely powerful technologies like IntelliSense
Annotations can help say more with less code, which is very powerful in team and solo contexts
local function callSomething(...)
print(a,b,c) -- Expecting to print out "1 hi true"
end
game.Players.PlayerAdded:Connect(function()
a = 1
b = "hi"
c = true
callSomething() -- Expecting to call "callSomething" function without an error
end)