> On Jul 13, 2016, at 9:18 AM, Karl via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> #1 - 
> 
> Currently, DispatchQueue.after() takes an absolute time as the “after” 
> parameter. This makes it hard to understand how to use it; you need to go 
> digging through generated interfaces to find out what a ‘DispatchTime’ is and 
> how you construct it (by getting the .now() and adding a DispatchTimeInterval 
> using one of the easily-missable operator overloads, if you were wondering).
> 
> Here is what DispatchQueue.after looks like now:
> 
> public func after(when: DispatchTime, qos: DispatchQoS = .unspecified, flags: 
> DispatchWorkItemFlags = [], execute work: @convention(block) () -> Void)
> 
> So to use it, you have to type:
> 
> DispatchQueue.main.after(when: DispatchTime.now() + .milliseconds(250))   { 
> /* do stuff */ }
> 
> I don’t believe this is a great fit with the Swift API Guidelines. I believe 
> the name “after” already implies that the time is relative, the argument 
> label should be dropped, and that nuances about the clock (basically, whether 
> or not it pauses during system sleep) are edge-cases which can be handled for 
> the majority of users with a sensible default value (or better yet, modelling 
> via an enum or boolean switch — see #2). Additionally, There are overloads 
> with “wallTime” parameter labels which seem only to duplicate type 
> information (the monotonic and walltime clocks are actually split at the type 
> level) and could be more concise and readable. The principle is that, 
> ultimately, you should just be able to write the above code like this:
> 
> DispatchQueue.main.after(.milliseconds(250)) { /* do stuff */ }
> 
> Or
> 
> DispatchQueue.main.at(DispatchTime.now() + .seconds(3)) { /* do stuff */ }
> 
> It’s not something you use all the time (like .sync/.async), but I find that 
> whenever I do need it I’m frustrated by how needlessly complex it is to 
> decipher and use. I would find these methods much more obvious, I could 
> figure out how to use them much more quickly, and I think I’d remember how to 
> use them more quickly.

As mentioned by Matt in the pull request you created, we’re working on a 
proposal that would look like this:

func asyncAfter(deadline:qos:flags:work:)
func asyncAfter(wallDeadline:qos:flags:work:)
As we discussed on the pull request, 

DispatchQueue.main.after(.milliseconds(250)) { /* do stuff */ }

Is ambiguous as you don’t know which clock was meant, and despite your claim, 
there’s in general no good default for the clock. If you are writing a calendar 
app, you want wallClock, but if you’re doing anything network related, you will 
want the monotonic one. Depending on which software you’re writing, you will 
have a bias for one or the other.

Also it may be a native speaker thing (which I’m not) but this reads “please 
async this closure on `q` after this deadline has expired” to me, which sounds 
like proper english:

q.asyncAfter(deadline: .now() + 1.0) { /* do stuff */ }


I thought that you would say “please meet me in 10 minutes” or “please meet me 
after 2PM”. The `asyncBy` that you suggested to the pull request reads *before* 
that deadline to me which is not good either.
`asyncAt` would probably work too however, but asyncAfter is easier for people 
coming from C who are used to dispatch_after().


> #2 - 
> 
> Actually, while writing this down it’s becoming clearer and clearer that the 
> idea to split DispatchTime (the monotonic clock) and DispatchWallTime (the 
> wall clock) at the type level is probably a bad idea.
> 
> Novice users are not going to understand what’s going on here - I expect most 
> of them to default to the more generic-sounding “DispatchTime” without any 
> idea of the implications of this. Perhaps we should look at replacing these 
> clock variations with a more descriptive enum or boolean, rather than a 
> separate type. For example:
> 
> struct DispatchTime {                       // replaces DispatchTime and 
> DispatchWallTime
>    let rawValue : dispatch_time_t
>    let clock : Clock
> 
>    enum Clock { case monotonicClock; case wallClock }
> }
> 
> This would not obsolete the discussion at the start about “after”. The name 
> “after” still implies that I want something done at some duration relative to 
> an absolute point in time (usually now).

This is what dispatch_time_t does in C and my team at Apple widely considers 
this having been a design mistake: it means that the time is not generally 
Comparable, that you can’t perform any kind of arithmetic with it, etc.

In C it’s more convenient to have a single type, but in Swift where type is 
inferred, given that most of the uses will construct the time as the argument 
to the function itself, we feel that the current proposal allows for the most 
concise use.



-Pierre
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to