Swift 1.1 and 1.2: accessing members of protocol type value XXX.Type' is unimplemented
Originator: | gwendal.roue | ||
Number: | rdar://20119848 | Date Originated: | |
Status: | Resolved: | ||
Product: | Developer Tools | Product Version: | Xcode 6.3b2 |
Classification: | Reproducible: |
Hi, Swift 1.1 and 1.2 won't let the programmer call a class method defined in a protocol. The use case is the following: I'm developping a Swift implementation (https://github.com/groue/GRMustache.swift) of the Mustache template engine (https://mustache.github.io). Mustache is a template engine which turns "Hello {{name}}!" into "Hello Tom Selleck!" when given ["name": "Tom Selleck"]. It replaces Mustache tags with the values it extracts from its input. GRMustache.swift performs key extraction from NSObject values with the valueForKey: method. The "problem" with valueForKey: is that it can execute any method that does not take any argument, including methods that have side effects. When one renders an untrusted template, this is a security issue. To alleviate this problem, GRMustache.swift will only execute valueForKey: for "safe" keys. Those safe keys are, by default, the names of properties. However, there is a protocol, named "SafeKeyAccess", which lets a developper expose its own custom list of safe keys: @objc protocol SafeKeyAccess { static func safeKeys() -> Set<String> } The problem is that it is impossible, in Swift, to call this method, given an input of type AnyObject: func safeValueForKey(key: String, inObject object: AnyObject) -> AnyObject? { if let safe = object as? SafeKeyAccess { // error: accessing members of protocol type value 'SafeKeyAccess.Type' is unimplemented let safeKeys = safe.dynamicType.safeKeys() if find(safeKeys, key) != nil { return object.valueForKey?(key) } } return nil } Since Swift won't help, the GRMustache library has to escape to Objective-C in order to implement this "safe key-value coding". In the following lines of code, the GRMustacheKeyAccess.isSafeMustacheKey method is written in Objective-C: https://github.com/groue/GRMustache.swift/blob/ddabbcd9f0cf9e49d685141133753cdb6241e57e/Mustache/Rendering/MustacheBox.swift#L1447-L1462 Since there is an Objective-C workaround, the problem is not so big. But you know how things go: now that the library contains a mix of Swift and Objective-C, it can not be shipped as a CocoaPod (the dependency manager), because CocoaPod does not support this kind of project yet, etc. etc. So this limitation is not so nice in the end. Thanks for reading! Steps to Reproduce: Compile this Swift code: @objc protocol SafeKeyAccess { static func safeKeys() -> Set<String> } func safeValueForKey(key: String, inObject object: AnyObject) -> AnyObject? { if let safe = object as? SafeKeyAccess { // error: accessing members of protocol type value 'SafeKeyAccess.Type' is unimplemented let safeKeys = safe.dynamicType.safeKeys() if find(safeKeys, key) != nil { return object.valueForKey?(key) } } return nil } Expected Results: The above code compiles. Actual Results: The compiler fails with error "accessing members of protocol type value 'SafeKeyAccess.Type' is unimplemented". Version: Xcode Version 6.3 (6D532l)
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!