Does an @objc protocol erase type information?

A followup to my previous question. You can paste this into a macOS playground. As soon as I make the protocol @objc the check exporter.type is User.Type fails. Is there a way to retrieve the type information and get the desired result? (I guess @jrose would know?)

  import Foundation

  //@objc(Exporter)
  protocol Exporter: NSObjectProtocol {
      var type: Any { get }
      func export(item: Any)
  }

  struct User { var name: String }

  final class UserExporter: NSObject, Exporter {
      var type: Any { return User.self }
      func export(item: Any) {
          guard let u = item as? User else {
              return print("That's not a user")
          }
          print("Got user: \(u.name)")
      }
  }

  let user = User(name: "Kermit")
  let exporter: Exporter = UserExporter()

  if exporter.type is User.Type {
      print("Correct exporter")
  }
  exporter.export(item: user)

Ok, so it seems that just Metatypes are not representable in Objective-C. If I box up the type

public class TypeBox: NSObject {
    public let unbox: Any
    public init(_ type: Any) {
        unbox = type
        super.init()
    }
}

and pass that along, I can get the original type back.

That sounds like a bug. Mind filing it?

Ah I understand. Will file a bug!

On a sidenote: Is loading a type at runtime only being available to obj-c a shortcoming of the Swift runtime or only because of how Bundle is implemented (talking about casting a runtime loaded Bundle’s principalClass for example)

Having a _SwiftValue box when viewed from Objective-C is correct, but the is check should be able to look through that to see the type inside.

Filed https://bugs.swift.org/browse/SR-7432

1 Like