Remove the " Something unexpectedly tried to set the parent of X to NULL while trying to set the parent of X"

This happens if you’re trying to remove something immediately after it has been created.
You can work around it by just adding the object to the debris with a delay of 0.

45 Likes

Or trying to change the parent of it from another thread when it just had its parent changed

wait(0) and delay(0) don’t really make sense since you can’t pause 0 seconds, so I prefer to use spawn which gives the same results

5 Likes

wait(0) makes perfect sense. It means you want to resume on the next Lua task scheduler resume (as soon as possible.) Which is exactly the same thing as spawn().

If you don’t want to wait until the next Lua resume, you can probably get away with doing game:GetService(“RunService”).Heartbeat:wait().

3 Likes

No it doesn’t because waiting 0 seconds isn’t waiting at all which is the same thing as not having the wait there in the first place. Except that’s not what really happens in Lua, so you’re building code that relies on the program not doing what it’s told to do. Waiting 0 seconds to resume the next scheduler resume is not what wait was designed for, and relying on a side effect instead of what was specifically designed for resuming on the next scheduler resume only makes your code less readable and more confusing.

2 Likes

Didn’t John say something along the lines of anything that can be fixed with a simple wait(0) is doing something wrong?

1 Like


< source >

14 Likes

This concept doesn’t exist in Lua, it’s a feature of ROBLOX. ROBLOX was designed with this task scheduler as an integral part of the engine. If you’re writing code for ROBLOX, then you should be expected to know that the task scheduler runs at a set rate. All wait() was designed to do is yield the current thread and resume it on the next tick that occurs after the duration desired has elapsed. Thus, wait(0) is entirely valid because the next tick is going to be >0 seconds after the last.

3 Likes

That’s how wait() was implemented – not what it was designed to do.

No. You’re relying on the way it was implemented rather than what the API is meant to provide.

What? You’re trying to be too pedantic and it’s not working; the task scheduler absolutely was designed to do exactly that because it was designed for a game that ran at 30 FPS.

Using wait(0) to yield until the next resume because the implementation of wait allowed it instead of using spawn (which was specifically designed for that) is as bad as using the Lighting as ReplicatedStorage just because the implementation of Lighting allowed it to function like that.

3 Likes

No it’s not? I don’t know what to tell you at this point. You’re just arguing for the sake of it.

I don’t know what to tell you at this point either after you tell me I’m wrong and then when I respond with content about what we’re discussing I’m given ad hominem in return in subsequent replies to me.

1 Like

Because you are wrong, sorry. Even if your premise that wait() was designed to do something is correct, you’re still wrong because wait() was designed to yield. If it didn’t yield when you gave it 0, that would be unexpected behavior.

1 Like

waiting 0 seconds (0 seconds = no time) not yielding for an amount of time is unexpected behavior
what

2 Likes

Well then I expect wait(0.1) to wait exactly 0.1 seconds. Why doesn’t it.

local x = calculateSomething()
wait(x)

So you’re telling me that this code should change behavior entirely if x is 0?

1 Like

Because of hardware, internal workings of software, etc that’s not possible.

No. The current behavior should stay the same – the current behavior is like it is because of hardware, internal, etc restrictions. But what you shouldn’t do is rely on that obscure implementation quirk (unless there isn’t another option) – that’s bad design.

If I want to play a ROBLOX sound multiple times, I have to clone it and play the clone because if I played the original multiple times the previously playing instances would get stopped as soon as I played the next one. For the sake of example, let’s say I use a cleaner that loops through all the cloned sounds, checks if they’re stopped, and deletes them if they are. For whatever reason, I need to trigger the cleaner manually. I can do this by cloning a random sound and immediately stopping it, or I can write and use a method for the cleaner that triggers it manually. Which code should I use?

...
local clone = reloadSound:Clone()
clone:Play()
clone:Stop()
...
...
SoundCleaner:Run()
...

With the way the cleaner is implemented, I can certainly trigger it manually by cloning an arbitrary sound and stopping it, but is that good code? If someone was reading that besides me, they would have no idea what it was for unlike if I made a method for the cleaner. I’m no expert, but I thought the general consensus of programmers was that good code is inherently understandable and that needing to follow a trail of method sources and observing what each one does just so you can find out what the top level is doing is bad.

1 Like

When scripters use wait() they are intending for their code to pause for that amount of seconds. The name of the function being “wait” implies this…to pause or wait that time.

This is the implementation. Usually when you want something to be done, the implementation isn’t always as simple, but it was designed to let you force your code to wait a period of time given in seconds. Of course this isn’t decimal perfect simply because thats extremely hard to achieve due to technical reasons, but its pretty damn close. The expected behavior of wait(0) is to wait 0 seconds or no time. This makes no sense. So obviously the behavior it gives is unexpected.

ROBLOX’s default wait-time is ‘0.029999999999999999’ wait(0) is the same thing as wait() and last I checked ROBLOX discouraged from using wait(). wait() was intended to yield but when you give it a number that makes no sense and ROBLOX has to instead resort to the default wait-time then thats just bad practice.

4 Likes

Oh, completely forgot about that. wait(0) isn’t even possible because the minimum wait time is 0.03:

start = tick() wait(0) print(tick()-start)
→ 0.031400680541992

So yeah, you should definitely be using spawn to resume at the next scheduler resume instead of using wait(0) and picking back up at the next resume after 0.03 seconds.

2 Likes

t=tick()spawn(function()print(tick()-t)end)
0.01389741897583