Compiler should disallow @objc extension on Swift-only class

If you take a class that cannot be visible to Obj-c:

public final class SwiftOnlyClass <T> {
    // ...
}

and add an extension marked @objc, its static extension methods are still not visible to Obj-c:

@objc
public extension SwiftOnlyClass {
    @objc 
    static var helloWorld: String {  // no way to call this from Obj-c code, e.g. [SwiftOnlyClass helloWorld];
        return "Hello world"
    }
}

I guess this makes since, since SwiftOnlyClass isn't visible for Obj-c to actually call any static methods on it. Should the compiler disallow this to avoid confusion?

Seems reasonable. I can't think of any reasons why this shouldn't be a compiler warning / error :slight_smile:

In Xcode Version 10.2 (10E125) it produces an error already
Members of extensions of generic classes cannot be declared @objc

If you remove <T> you can call that static method, for example:

swift file:

import Foundation

public class Foo: NSObject {
    @objc class func otherClass() -> Any {
        return SwiftOnlyClass.self
    }
}
public final class SwiftOnlyClass {
}

@objc
public extension SwiftOnlyClass {
    @objc
    static var helloWorld: String {
        return "Hello world"
    }
}

main.m

#import <Foundation/Foundation.h>
#import "MixedTest-Swift.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        id ccc = [Foo otherClass];
        NSLog(@" %@", [ccc performSelector:NSSelectorFromString(@"helloWorld")]);
    }
    return 0;
}

will print

2019-10-28 10:42:42.466745+0100 MixedTest[4654:77593]  Hello world
Program ended with exit code: 0

Ah you're right, I was actually working with a non-generic Swift class, but added the <T> to be clear it was Swift-only. I'd think either Xcode should allow me to call [SwiftOnlyClass helloWorld]; without performSelector, or have the compiler throw an error. It's strange that neither happen.

Calling helloWorld without performSelector:

public class Foo: NSObject {
    @objc class func otherClass() -> Blah.Type {
        return SwiftOnlyClass.self
    }
}

@objc protocol Blah {
    @objc static var helloWorld: String { get }
}

public final class SwiftOnlyClass {
}

@objc
public extension SwiftOnlyClass {
    @objc
    static var helloWorld: String {
        return "Hello world"
    }
}
extension SwiftOnlyClass: Blah {}
        id<Blah> ccc = [Foo otherClass];
        NSLog(@" %@", [ccc helloWorld]);
2 Likes