add a time parameter for event:Wait(), a thread will only wait on that event for that many seconds before continuing. will return true or false based on whether the event was called before the waiting limit was reached
local WasTouched = part.Touched:Wait(3) -- waits for .Touched up to 3 seconds
if WasTouched then
--part was touched before 3 seconds
else
--wait timed out before part was touched
end
:Wait() already returns the arguments that would normally be passed into the event signal made with :Connect()
For example, this works:
local hit = part.Touched:Wait()
-- hit is the BasePart that touched part.
print("Part that touched is",tostring(hit))
Given this presumably new information, how would you solve the âcheck if the event timed out or firedâ situation? Your current suggestion would replace existing functionality and would break existing uses.
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
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.
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â)