Search code examples
swifttypesstaticswift-extensions

Can I directly access a default static var from the type of a protocol extension?


For Swift fun, I thought I'd build out some alternate reified APIs to GCD. So I threw this in a Playground:

import Foundation

typealias DispatchQueue = dispatch_queue_t

extension DispatchQueue {
    static var main:DispatchQueue {
        return dispatch_get_main_queue()
    }
}

let main = DispatchQueue.main

But this yields an error in the last line:

Static member 'main' cannot be used on instance of type 'DispatchQueue.Protocol' (aka 'OS_dispatch_queue.Protocol')

I'm not sure what this is telling me. I mean, I read it. But I don't see the real problem. I looked at how Double has type vars for things like NaN, and I'm not sure why I can't extend another type with a similar sort of accessor.

(I did try an alternate without the typealias, no difference)

UPDATE: @Kametrixom's answer didn't help right away, but it contributed probably in the end. Here's what I had to do for the light bulb to go on.

class Foo {
    static var Bar:Int {
        return 42
    }
}
Foo.Bar --> 42

Ok, that worked, now a struct.

struct Yik {
    static var Yak:Int {
        return 13
    }
}
Yik.Yak --> 13

That too worked. Now a protocol with an extended default implementation:

protocol Humble { }
extension Humble {
    static var Pie:Int {
        return 23
    }
}
Humble.Pie --> DOES NOT WORK

BUT, extend either the class or the struct with the protocol:

extension Foo: Humble { }
Foo.Pie --> 23

And that works. The mistake I was making (I think?) was in supposing that there was a first class instance of the Humble type running around with that behavior attached to it, which I could invoke, ala composition style. Rather, it's just a template of behavior to be added on to the struct/class types.

I have changed the title of the question. And the answer is No.


Solution

  • If you go to the definition of dispatch_queue_t, you'll find that it's a protocol:

    public typealias dispatch_queue_t = OS_dispatch_queue
    public protocol OS_dispatch_queue : OS_dispatch_object {}
    

    That means that you aren't actually extending the protocol itself, but rather the types that conform to it. This means to get it to work, you need to get an instance of the protocol of somewhere, get the dynamicType of it and then you can call main:

    let DispatchQueueT = (dispatch_queue_create("", DISPATCH_QUEUE_SERIAL) as dispatch_queue_t).dynamicType
    
    DispatchQueueT.main