Initially when I first submitted this bug report I thought this was exclusive to LocalScripts and the .Enabled property. But I want to clarify for readers that this works for Scripts as well and also .Parent can cause the same effect. So, I know the title is a little incorrect (not allowed to change it).
The file is linked below showcasing the bug in action. The scripts are located in ServerScriptStorage. Make sure output is open and notice how the “Looping” script is printing 21x times
@Amthu – can you please clarify what behavior you’re expecting?
Modified the “Looping” script as follows:
while true do
print(`I am looping! -- Enabled={script.Enabled} Parent={script.Parent}`)
task.wait(1)
end
I get this:
09:57:54.197 I am looping! -- Enabled=true Parent=ServerScriptService - Server - Looping:2
09:57:54.198 ▶ I am looping! -- Enabled=true Parent=Workspace (x20) - Server - Looping:2
And I don’t get disabled.
If I let it continue to run, I get 20 more executions every second.
According to the docs the script executes in a new thread immediately when it’s parented to Workspace or Enabled (and also loaded). Which means it will run 21 times because of the initial run and the 2 x 10 for loops.
Since the the loop is an infinite loop, all the threads will just keep executing every second.
To continue experimenting with it, you can print out the thread id in the for loop.
Also, note that threads and execution is not equal to script instances.
I was expecting that by changing .Enabled (or even parenting) it would disable the script when the necessary conditions for it were met.
Although it is a niche problem as I don’t think this is something that anyone will have to do often, I do find it somewhat concerning that the script gets threaded and if you try to set .Enabled to false (or even deleting the script) the threads are still running in the background.
Unless there is a way to manage the threads that I don’t know about.
Agreed, it’s can be concerning, though others might argue that execution in the documented conditions is expected and useful. If you know what to expect, you can take advantage of it: you enable a script with a certain behavior when certain conditions meet, and it executes automatically.
The assumption is that if something is documented it is well know but often it’s not the case. On the other hand, I just learned from this discussion that .Enabled starts a thread, too…
As for parenting: it’s putting under Workspace and ServerScriptService.
So yeah, task and coroutine is your friend, for example if you change the above to this
print(`I am looping! -> Enabled={script.Enabled} Parent={script.Parent}, thread={coroutine.running()}`)
it will clearly show you that it’s a different thread.
This is why it’s usually a good idea to assume full control over object lifecycle and execution by explicitly launching scripts and threads instead of copying things around and enabling / disabling scripts. But also, it’s a good idea to read the docs or look things up, when in doubt.
The moral of the story is that Script ~= thread of execution. But also, you can use the coroutine library for thread related things. There might be other tools as well, of course…