Refine `DispatchQueue.main` to return a `OS_dispatch_queue_main`

Hi all,

Currently DispatchQueue.main returns a DispatchQueue object.
I thought that returning a OS_dispatch_queue_main instead could allow clients to extend the class and add features specific to the main dispatch queue of their iOS apps for example.
One possible use case:

public extension OS_dispatch_queue_main {
    func asyncIfNeeded(
        group: DispatchGroup? = nil,
        qos: DispatchQoS = .unspecified,
        flags: DispatchWorkItemFlags = [],
        execute work: @escaping () -> Void)
    {
        if Thread.isMainThread {
            work()
        } else {
            self.async(group: group, qos: qos, flags: flags, execute: work)
        }
    }
}

It would fit nicely with the current design next to async and asyncAfter: DispatchQueue.main.asyncIfNeeded { ... }.

What do you think?
Maybe DispatchQueue.global(qos:) should also be updated to return a OS_dispatch_queue_global for consistency.

Thanks!

Are you asking to introduce a new type?

Sorry my meassage wasn't very clear.
Not a new type, although a typealias could be a good idea given that OS_dispatch_queue_main is not a very swifty name.

typealias DispatchQueueMain = OS_dispatch_queue_main

I'm talking about this type:
https://developer.apple.com/documentation/dispatch/os_dispatch_queue_main
It inherits from DispatchQueue so this change should be backward compatible I think.

What would the benefit be of having the alias?

Not much I guess :slightly_smiling_face:
Other than consistency with other types that I use regularly like DispatchQueue, DispatchGroup, DispatchWorkItem...

I don't understand what the type alias would do. Extending a type alias just extends the actual type.

A type alias would provide a name that's more consistent with other Swift names. That's all.

The important question is whether the declared type of DispatchQueue.main should be changed to OS_dispatch_queue_main.

The C API, dispatch_get_main_queue, returns a dispatch_queue_main_t, which is a typedef for NSObject<OS_dispatch_queue_main>. The Swift refinement, DispatchQueue.main, has type DispatchQueue. The Swift API discards type information that is available in C.

2 Likes

I was just wondering why OS_dispatch_queue_main didn't follow Swift naming conventions and then had this typealias idea.
I don't know what's happening here but it's the only reference to OS_dispatch_queue_main I found:

Let's forget the typealias idea then :innocent:
What about the return type of DispatchQueue.main? Would it be possible to refine it?

Changing the type would unfortunately be a source-breaking change, since someone might be relying on it to infer the type of a var that later gets set to DispatchQueue.global() or something.

It does seem a little weird that OS_dispatch_queue_main and OS_dispatch_queue_serial exist but weren't refined on the Swift side, but we'd need a Dispatch person in here to talk about if there's a specific reason for that.

3 Likes

I’ve seen lots of APIs that expect a DispatchQueue, and where the user chooses to pass either .main or e.g .global(qos: .utility))

Like lots of functions in Combine.

Maybe I’m misunderstanding?

The inheritance hierarchy looks like this:

OS_object (an implementation detail)
DispatchObject
DispatchQueue
OS_dispatch_queue_serial
OS_dispatch_queue_main

So if you have an API that takes a DispatchQueue, passing an OS_dispatch_queue_main instance is fine. However, if you have code that looks like this:

var queue = DispatchQueue.main
if shouldRunInBackground {
  queue = DispatchQueue.global()
}

Then that code will break, because the first line has queue getting its type from DispatchQueue.main.

2 Likes

Ok thanks.
I thought it would be a harmless change because type(of: DispatchQueue.main) returns a OS_dispatch_queue_main type, but I had not thought about this case.
I'm going to add a static method and call it like this DispatchQueue.mainAsyncIfNeeded { ... } which reads almost as my original example.

The concurrency design (coming in a few weeks, I promise!) will likely demote the importance of using this API directly; I wouldn't put work into refining it.

34 Likes

That's good to hear(read)!
Case is closed. :white_check_mark: