scala-js/scala-js-dom

setTimeout()

tindzk opened this issue · 5 comments

WindowTimers.setTimeout() has the following signature:

def setTimeout(handler: js.Any, timeout: js.Any, args: js.Any*): Int = ???

Some users (including myself) ran into a problem passing a block instead of a lambda. It would be helpful if the compiler could catch this on-the-fly. Therefore, I would advise changing it to:

def setTimeout(handler: () => Unit, timeout: Int): Int = ???

MDN also doesn't specify the additional parameters, which appear to be safe to drop.

In the unlikely event that the user wants to use the untyped version, he can just resort to js.Dynamic.global.setTimeout().

I concur, all the mess I made lately around async testing was due to the fact that I was passing a block instead of function into the setTimeout method.. It made me think that PhantomJS executes setTimeout immediately whereas it was due to this thing :-)

sjrd commented

PR welcome.
Note that

def setTimeout(handler: () => Unit, timeout: Int): Int = ???

is incorrect, it must be a js.Function0. Besides, Unit return types in callbacks should typically be Any instead, so it should be:

def setTimeout(handler: js.Function0[Any], timeout: Int): Int = ???

Besides, Unit return types in callbacks should typically be Any instead

@sjrd I have a question about this. I always thought it to be better, if we could specify the API author's intent more clearly. So, when a function argument is not expected to return a meaningful value, I've preferred to use () => Unit, rather than js.Function0[Any].

Should I change such APIs to allow return Any as you recommended? And I'd like to know if there is specific reason behind it.

sjrd commented

In general, of course, we should be as precise as possible. But in the case of a callback returning Unit, it means more that you don't care what the result will be because you're not going to use it. I would agree with conveying the api's intent, in general. But for this user case, specifying Any helps the type inference to do the right thing. Scala APIs do the same: look at definitions of foreach: they take functions returning a generic type U (which, in contravariant position, is basically the same as Any) instead of Unit.

Thanks for the explanation. I suppose I better change my sources to confirm to this, if Scala API defines the signature of foreach in such a way.