swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.61k stars 10.37k forks source link

[SR-3177] Should @objc enums be bridged to Objective-C as their raw value? #45765

Open sharplet opened 8 years ago

sharplet commented 8 years ago
Previous ID SR-3177
Radar None
Original Reporter @sharplet
Type Bug
Environment Version 8.1 (8B62) Apple Swift version 3.0.1 (swiftlang-800.0.58.6 clang-800.0.42.1)
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 1 | |Component/s | Compiler | |Labels | Bug, LanguageFeatureRequest | |Assignee | None | |Priority | Medium | md5: 0529ab80a3542b5c52af89b7c2335e7d

relates to:

Issue Description:

@objc enum FooType: Int {
  case foo, bar
}

class Foo: NSObject {
  var type: FooType = .foo
}

let foo = Foo()

foo.setValue(1, forKey: "type")
foo.type // FooType.bar

foo.setValue(FooType.foo, forKey: "type") // crash
belkadan commented 8 years ago

cc @jckarter

jckarter commented 8 years ago

Would be nice. I pitched this on swift-evolution a while back: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160926/027425.html

sharplet commented 8 years ago

I had a read through that thread, thanks for the link. I like the idea of getting ObjectiveCBridgeable through, but I also think that this narrower case of `@objc` and `RawRepresntable` types might be better on its own, to avoid getting bogged down with design details around arbitrary bridging.

Is there anything I can do to help move things along? I'm interested in contributing, though I'll be honest I'm not sure what exactly that would involve or how much time I'll be able to contribute.

zwaldowski commented 6 years ago

As Swift 4 continues to increase Swiftification of the SDKs and id-as-Any gets more pervasive, the side effects of this are rather insidious:

var attributes = [NSAttributedStringKey: Any]()
attributes[.underlineStyle] = NSUnderlineStyle.styleNone // ObjC-imported enum member
attributes[.textEffect] = NSAttributedString.TextEffectStyle.letterpressStyle // ObjC-imported newtype member
attributes[.link] = URL(string: "https://www.swift.org") // Swift-native type with an ObjC representation

let types = (attributes as NSDictionary).allValues.map({ type(of: $0) })

types // [_ObjC._NSCFConstantString.Type, __ObjC.NSURL.Type, __C.NSUnderlineStyle.Type]

All three assignments are valid Swift syntax and look like valid Swift syntax in code review, then will fail at runtime (once `attributes` in this context gets passed back into Cocoa) in an extremely hard-to-debug way. The importer should absolutely emit a `_SwiftNewtypeWrapper` conformance for integer enums like it does for "string enums" so as to not regress from behavior that warned developers perfectly fine all the way back in Swift 1.0.

belkadan commented 6 years ago

Nothing has changed for integer enums all the way back to Swift 1.0.

zwaldowski commented 6 years ago

But bridging has. The compiler used to prevent enum member misuse, now it doesn't.

swift-ci commented 5 years ago

Comment by Ryder Mackay (JIRA)

Just chiming in to say that this is still a real sharp edge when using the many Objective-C APIs that take options dictionaries. Even though I'm aware of the problem, I still run into it every time I use `NSAttributedString` because it feels perfectly natural to pass `[.underlineStyle: NSUnderlineStyle.single]` to Cocoa, and there's no help from the compiler.

In lieu of bridging changes, for now would it make sense to warn of a possible runtime error when an Int enum is passed as Any to an @objc method?

belkadan commented 5 years ago

There's nowhere to put the warning, unfortunately, because there's no one step that's obviously wrong.