```suspend fun delay(time: Long, unit: TimeUnit = ...
# coroutines
u
Copy code
suspend fun delay(time: Long, unit: TimeUnit = TimeUnit.MILLISECONDS) {
        require(time >= 0) { "Delay time $time cannot be negative" }
        if (time <= 0) return // don't delay
Wouldn't it be more comfortable to not have require(time >= 0) Especially, as the implementation for time < 0 follwos right on the next line
e
What is your use-case for that?
u
implementing a timer that fires at a givven time
now, if the time is already over, I'd have to special case that. But most likely it is ok to just fire imediately
What is the use case where you would want an exception?
e
It is just defensive programming. Usually, when you wait for a time you have a loop like this:
Copy code
val deadline = System.currentTimeMillis() + timeout
// later  
while (true) {
    val current = System.currentTimeMillis()
    if (current >= deadline) break
    delay(deadline - current)
}
It is easy to accidentally mess this loop (mess break condition for example). In this case, delay throwing exception "saves you" (without exception you may end up with a loop that just eats 100% CPU).
u
Makes sense. I guess you are not just delaying for the value of 'timeout' because it is an example? Why do you need that loop at all? Isn't delay supposed to suspend for at least the given time?
This is exactly the use case i was thinking about. Is there any thing wrong with this:
Copy code
val deadline = System.currentTimeMillis() + timeout
// later 
    val current = System.currentTimeMillis()
    delay(deadline - current)
e
Hm... I was thinking about slightly different case, where you also doing something in a loop until a deadline
So, it would actually be:
Copy code
while (true) {
    // do something
    val current = System.currentTimeMillis()
    if (current >= deadline) break
    delay(deadline - current) // not really -- does not make sense
}
Not really, does not work either with delay.
Interesting.... I need to think more about the way you'd use
delay
(in particular) with a computed time.
What your original use-case was? What was the larger picture of what you were doing?
u
I was just toying around, experimenting how things would look, if implemented with coroutines and while debugging I stepped into the 'delay' implementation and was surprised.
I was thinking that in code like the example above:
Copy code
val deadline = System.currentTimeMillis() + timeout
// do some work here 
    val current = System.currentTimeMillis()
    delay(deadline - current)
I'd rather have high CPU load then an exception which would most likely crash as kotlin does not enforce exception handling. Especially, as the 'some work' might be done before timeout expires on my machine. But not on some random production machine.
So, here comes a potential use case. Polling a server. Let's say you want to poll a server for fixed interval updates like this;
Copy code
while (true) {
    val deadline = System.currentTimeMillis() + pollInterval
    // poll server and process result (e.g. update ui)
    val current = System.currentTimeMillis()
    delay(deadline - current)
}
If the server happens to be slow at a time, this would cause a crash or require special case handling. If delay(t) for t <= 0 would just return instead of throwing an exception it would just work. Or even better, if it would queue the continuation but without delay, it would just work, still be cancelable and not starve other coroutines.