Okay so Let's say I had code like this:
game.Workspace.ChildAdded:Connect(function(added) -- some code end) added.Transparency = 1* -- if I tried to run this it would say (unknown global "added") or something
I'm not asking about that code in specific I'm more of asking if I wanted for whatever reason to use "added" which was defined in the event in a different scope, how would I do that if possible?
also do variables defined in that line like "added" have an actual name for them or is it just variable.
Let me know if that's hard to understand, and thank you!
If you want to access the parameter values of callback functions outside of the callback function (which is what you're doing in your example code), you can simply declare a local variable outside of the callback and assign it to whatever the function argument is within the callback:
local added workspace.ChildAdded:Connect(function(_added) added = _added end)
However, there is a big problem with using this as a solution to your problem and you should not do it this way.
The flow of your program is incompatible with a solution like this because events execute code in their own threads which are asynchronous and separate from the main thread. Other threads will only have a chance to execute once the main thread is done executing, or while the main thread is yielding (waiting) for other threads to finish executing. You can think of a thread as a chunk of code that is scheduled to run some time in the future, instead of immediately. In other words, the time of execution for any given thread is unknown at runtime.
This is a problem because our main thread is executing top to bottom, and if we have some code near the bottom that relies on some code near the top (and it's running in another thread), we cannot guarantee that we will have that data by the time we need it.
For example, in your sample code you're using the ChildAdded
event. This means the handler function for that event won't execute until a new instance is added to the workspace, which means we will not have access to that instance until it is added.
Ex. 1: So, consider the ramifications of the solution:
-- declare local variable local added -- create event listener (a new thread) workspace.ChildAdded:Connect(function(_added) -- assign local variable added = _added end) -- use local variable print(added)
The event listener thread won't have a chance to execute until the main thread has finished executing, or until we manually wait for a response from the ChildAdded
event. Therefore, the added
variable will never be assigned by the time we try to print it to the output console.
One solution to this could be to wait for the event to fire before executing the rest of the main thread, like this:
Ex. 2:
local added workspace.ChildAdded:Connect(function(_added) added = _added end) -- hault main thread execution until a ChildAdded event fires workspace.ChildAdded:Wait() print(added) -- now it prints the instance
But this is at best, only a conditionally good solution. Most of the time haulting your main thread execution while waiting for some kind of response or event in your program yields a bad user experience due to continously waiting for things to happen. This is called code blocking, or synchronous code.
This solution will also clutter namespaces. You should aim to minimize the amount of globally-scoped variables in your code as much as possible. This isn't as big of an issue as the first one mentioned, because you can fix this by creating your own namespaces with tables or do-end blocks for local variables. However, this will only result in cluttering your program with new tables and scopes which leaves you with the same problem as before.
For example, you could create a table which stores variables whos values are generated from event callbacks, like such:
local eventVariables = {} workspace.ChildAdded:Connect(function(_added) eventVariables.added = added end) game.Players.PlayerAdded:Connect(function(newestPlayer) eventVariables.newestPlayer = newestPlayer end) -- first prints nil print(eventVariables.added) print(eventVariables.newestPlayer) -- wait for event handler threads workspace.ChildAdded:Wait() game.Players.PlayerAdded:Wait() -- now print the instances print(eventVariables.added) print(eventVariables.newestPlayer)
Note that this is just a more organized version of the same solution in Flow-Ex. 2 by getting rid of the namespace problem, but this is still just as bad as the original solution.
Finally, the good solution is just to use functions to pass around data to wherever you deem necessary. You can think of a function as a passageway, or a tunnel between threads and other code execution contexts for communicating.
If you need to use added
outside of your event handler, then create a function that reads or mutates that value in some way and pass it to that function as an argument.
For example:
local function printAdded(added) print(added) end workspace.ChildAdded:Connect(function(added) printAdded(added) end)
This may seem like a redundant example since you could also just do the following:
local function printAdded(added) print(added) end workspace.ChildAdded:Connect(printAdded)
However, the first example implies that you can create multiple functions of which you can pass the same argument to, if you need to use the variable in different places for different reasons.
For example:
local function printAdded(added) print(added) end local function renameAdded(added, newName) added.Name = newName end workspace.ChildAdded:Connect(function(added) printAdded(added) renameAdded(added, "NewName") printAdded(added) end)
Now, whenever a new instance is added to the workspace you will get the following output:
(Original Name)
"NewName"
Let me know if this helped. If you have any questions, feel free to ask.