It should error if it times out, like waitforchild
I thought WaitForChild with timeout just returned nil?
I thought of that too.
Sometimes nil is a valid argument that could be passed into the event signal (or returned, in our case).
On *Value
objects such as ObjectValues
, the Changed
event actually fires only when the Value
property changes, and fires with only one argument, the new value of the Value
property. This means that an ObjectValue
can fire with a single argument of nil
when its Value
is set to nil
. This is one example of how returning nil
for timeout would not be reliable.
If you manually specify a timeout, that’s the case. If you don’t specify a timeout and WaitForChild times out at the default interval, it throws a warning and kills the script. Edit: It doesn’t kill the script – it just infinitely yields.
there are some situations where you wouldn’t want it to error. i made this thread after i was trying to program some behavior for when a button is held down for a certain amount of time. i didn’t want to use coroutines (this would still have to use coroutines, oops) or loops, so this is what i thought of, using bindable events, and this hypothetical feature:
key.Pressed:connect(function()
local KeyRaised = key.Raised:Wait(2) -- time key needs to be held
if not KeyRaised then
HeldEvent:Fire()
end
end
Honestly, given the complaints other have raised, I’d have it just be a timeout option as opposed to a return value. Yes, it makes it slightly less functional, but it’d be less annoying for developers.
i realized the timeout return value is obsolete. if anything in your code relies on the return of that event, you can just check if it exists or not. if you need to know whether something like a bindable event timed out or not, you can just pass ‘true’ to it through Fire():
event:Fire(true)
-- other script
fired = event:Wait(3)
if fired then
-- do stuff
else
end
No, because returning nil means that the event did fire. If it is possible to return without firing then the wait function becomes useless.
i just showed you an example where it could be useful
There are built-in events that don’t have parameters, so your suggestion doesn’t work there. So implementing that would mean you have pretty inconsistent behaviour based on what APIs you use, which doesn’t seem good. As you point out, you’d have to add a dummy parameter to BindableEvent as well if there are no arguments to begin with. Really hacky!
Throwing an error when timing out would (seem to) be the only option to both provide backwards compatibility for all cases and also implement your feature in a clean way.
anyone using :Wait() on events that have no return values… wouldn’t need any return values anyways?
what i think i’m really asking for here is a yield that we can cancel early with an event, not an event yield we can cancel early with a timeout
If you click on this part of a post you can see which post is being replied to:
I was replying to your code sample just above where you suggest to return the parameters when the event fired within the timeout interval, or otherwise nil if it did not fire within the interval. In my previous post I explain why it won’t work out well.
Dumb but relevant example (since I can’t think of another event without parameters right now), what if I wanted to check if a user focuses the window in the next 3 seconds with your suggestion?
local result = game.UserInputService.WindowFocused:Wait(3)
if result then
-- ...
end
This actually won’t work at all, because WindowFocused doesn’t have any event parameters. So this suggestion, where you return nil instead of event parameters (which may also be nil) when the timeout has expired, does not work.
Instead think something like this:
local status = pcall(
function()
return game.UserInputService.WindowFocused:Wait(3)
end
)
if status then
-- fired within 3 seconds
else
-- did not fire
end
And something similar for an event with parameters where you also use the rest of the output of pcall.
The fact that one would have to wrap the Wait
call in a new function in a pcall (as above) bothered me a bit…
Then I noticed that if it were implemented as timeout = error one could actually do this:
local status, hit = pcall(Workspace.part.Touched.Wait, Workspace.part.Touched, 3)
if status then
print(hit,"touched; did not timeout.")
else
print("nothing touched in 3 seconds; timed out.")
end
For those not aware, pcall can return in one of two ways:
- false, error string
- true, return values of inner function, …
In addition, its parameters are pcall(function to run, parameter 1 to function, parameter 2 to function, …)
It doesn’t look the cleanest in this case, but having minimal new wrapper functions generally bothers me more. For me, realizing the ability to get rid of the new wrapper function means that I don’t mind if this is implemented such that Wait
errors when it reaches timeout. Just thought it was worth mentioning, maybe others think alike and this will sway them in their opinion.
There’s no good way to change Event:Wait() without breaking a lot of code. Either create a new method, or just implement in Lua (using :connect() for efficiency and no memory leak):
-- Default timeout is 30 cuz WaitForChild
local function WaitEvent(ev,t)
local res,con
con = ev:connect(function(...)
res = {n=select("#",...),...}
con:disconnect()
end) t = tick() + (t or 30)
repeat wait() until res or tick() > t
if not res then return false,con:disconnect() end
return true,unpack(res,1,res.n)
end
local fired,hit = WaitEvent(part.Touched,3)
if fired then
print(part,"got touched by",hit,"in less than 3 seconds!")
else
print("pff,",part,"failed again")
end
But yeah, something like Event:TimedWait(seconds)
would be nice.
Surely having :Wait( ) continue to be infinite then no previous code would break?
Well, if you want it to wait infinitely, you wouldn’t use WaitEvent() but just event:wait() instead.
If you mean for adding the timeout parameter: that could work
I actually write it out deliberately because I am confident it is easier to read and understand than calling the method directly like that for some people, so forgive me for that notation. It’s just to illustrate the idea and confusing as little people as possible at the same time. (And I just notice you point it out yourself too “it doesn’t look the cleanest in this case”)
I meant the latter, adding the parameter to :wait( )
That could work with the error approach. If it times out, it errors. It isn’t as clean as returning true/false,...
but otherwise what’s returned by :wait() and :wait(t) would be different, which would be very weird.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.