Skip to content

Improve Foundation overlay to handle bridging subscripts and dictionary literals. #3945

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 4, 2016

Conversation

jckarter
Copy link
Contributor

@jckarter jckarter commented Aug 2, 2016

SE-0072 took implicit bridging conversions away, which regressed the ability to express NSDictionaries as dictionary literals and index them using literal keys. Address this by changing the signature of init(dictionaryLiteral:) to use Hashable and Any, and by replacing the subscript from Objective-C with one using _Hashable that does the bridging on the user's behalf. This largely restores the QoI of working with NS collections.

@jckarter
Copy link
Contributor Author

jckarter commented Aug 2, 2016

@swift-ci Please smoke test

@jckarter
Copy link
Contributor Author

jckarter commented Aug 2, 2016

@parkera @phausler What do you think of these changes? There's a bit of an unfortunate tradeoff in our type system now between enforcing NSCopying conformance for classes and admitting Hashable value types that are naturally copyable and bridge to NSCopying objects.

extension NSMutableDictionary {
// Bridging subscript.
@nonobjc
final public subscript(key: _Hashable) -> Any? {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a FIXME(ABI) with a note that it should become a generic subscript.

@phausler
Copy link
Contributor

phausler commented Aug 2, 2016

Does this cause any poor interaction with CoreData or other subclassers of NSDictionary? I think the subscript accessors being clean are more important than enforcement of NSCopying (that already is a buyer be aware contract in swift as it is).

Also does this properly work for subclasses of NSDictionary made in Swift being handed off into ObjC (subscript is very often accessed in frameworks)

@jckarter
Copy link
Contributor Author

jckarter commented Aug 2, 2016

@phausler Do any of those clients override objectForKeyedSubscript: or setObject:forKeyedSubscript:? As long as subclassers override objectForKey: and setObject:forKey: (which is the right thing to do AIUI), there shouldn't be a bad interaction.

@jrose-apple
Copy link
Contributor

jrose-apple commented Aug 2, 2016

I'm not especially happy with Swift subclassers not being allowed to override the subscript, but as Philippe points out they probably shouldn't be using that as the override point anyway.

@jckarter jckarter force-pushed the foundation-overlay-post-0072 branch from 3271f8b to 9fa724d Compare August 3, 2016 19:40
@jckarter
Copy link
Contributor Author

jckarter commented Aug 3, 2016

@swift-ci Please smoke test

@jckarter
Copy link
Contributor Author

jckarter commented Aug 3, 2016

@jrose-apple @gribozavr @phausler I tried a different approach that doesn't rely on final, _Hashable, or hiding the native objectForKeyedSubscript: implementation (since doing so also broke AnyObject dynamic lookup for subscripts). How does this look?

@jckarter
Copy link
Contributor Author

jckarter commented Aug 3, 2016

@rudkx @DougGregor Somehow, the overlay changes here trigger a change in behavior in Swift.Dictionary that causes the subscript operator to become ambiguous in validation-test/stdlib/Dictionary:

/Users/jgroff/src/s/swift/validation-test/stdlib/Dictionary.swift:3203:4: error: ambiguous reference to member 'subscript'
  d["hello"] = 17
  ~^~~~~~~~~
Swift.Dictionary:261:12: note: found this candidate
    public subscript(position: DictionaryIndex<Key, Value>) -> (key: Key, value: Value) { get }
           ^
Swift.Dictionary:306:12: note: found this candidate
    public subscript(key: Key) -> Value? { get set }
           ^
<unknown>:0: note: found this candidate
Swift.Dictionary<Key, Value>:3:12: note: found this candidate
    public subscript(key: _Hashable) -> Value? { get set }
           ^
Swift.Collection:25:12: note: found this candidate
    public subscript(bounds: Range<Self.Index>) -> Slice<Self> { get }
           ^
Swift.Indexable:23:12: note: found this candidate
    public subscript(bounds: ClosedRange<Self.Index>) -> Self.SubSequence { get }
           ^
Swift.Indexable:23:12: note: found this candidate
    public subscript(bounds: CountableRange<Self.Index>) -> Self.SubSequence { get }
           ^
Swift.Indexable:45:12: note: found this candidate
    public subscript(bounds: CountableClosedRange<Self.Index>) -> Self.SubSequence { get }
           ^

@@ -976,6 +977,18 @@ extension NSDictionary : Sequence {
}
}

// Bridging subscript.
@objc
public subscript(key: Any) -> Any? {
Copy link
Contributor

@jrose-apple jrose-apple Aug 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be @objc at all?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…oh, for overriding purposes in Swift today.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the only way we get overrideable methods in extensions right now. Without the custom selectors this would collide with the subscript methods from Cocoa.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a FIXME, then?

@jrose-apple
Copy link
Contributor

What's the advantage of using Any over _Hashable in the new approach? Ambiguity with NSCopying?

@jckarter
Copy link
Contributor Author

jckarter commented Aug 3, 2016

That's one reason. _Hashable also (a) isn't @objc-representable, (b) isn't meant to be long-term API or ABI. Since it's not providing much real static safety for these operations (and NSDictionary's objectForKey: accepts id in ObjC anyway) Any seems like a more practical choice.

@rudkx
Copy link
Contributor

rudkx commented Aug 3, 2016

@jckarter I'll try to look at this next.

…ry literals.

SE-0072 took implicit bridging conversions away, which regressed the ability to express NSDictionaries as dictionary literals and index them using literal keys. Address this by changing the signature of init(dictionaryLiteral:) to use Hashable and Any, and by replacing the subscript from Objective-C with one using _Hashable that does the bridging on the user's behalf. This largely restores the QoI of working with NS collections.
@jckarter jckarter force-pushed the foundation-overlay-post-0072 branch from 9fa724d to 62afa03 Compare August 4, 2016 15:42
@jckarter
Copy link
Contributor Author

jckarter commented Aug 4, 2016

@swift-ci Please smoke test and merge

@swift-ci swift-ci merged commit 47fe3bd into swiftlang:master Aug 4, 2016
@jckarter jckarter deleted the foundation-overlay-post-0072 branch August 4, 2016 16:50
kateinoigakukun pushed a commit that referenced this pull request Aug 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants