Skip to content
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

[SR-9044] Mutated CharacterSet bridges to Obj-C as NSMutableCharacterSet #3611

Open
lilyball mannequin opened this issue Oct 19, 2018 · 3 comments
Open

[SR-9044] Mutated CharacterSet bridges to Obj-C as NSMutableCharacterSet #3611

lilyball mannequin opened this issue Oct 19, 2018 · 3 comments

Comments

@lilyball
Copy link
Mannequin

lilyball mannequin commented Oct 19, 2018

Previous ID SR-9044
Radar None
Original Reporter @lilyball
Type Bug
Environment

Apple Swift version 4.2 (swiftlang-1000.11.37.1 clang-1000.11.45.1)
Target: x86_64-apple-darwin18.0.0

Additional Detail from JIRA
Votes 0
Component/s Foundation
Labels Bug
Assignee None
Priority Medium

md5: b147999c754ecf7fa2144e4177e48659

relates to:

  • SR-3006 CharacterSet should have a way of ensuring the wrapped NSCharacterSet is immutable

Issue Description:

After mutating a CharacterSet it's backed internally by an NSMutableCharacterSet. In this case, it turns out that bridging to Obj-C just returns the backing NSMutableCharacterSet without copying it, and so mutations to this returned NSMutableCharacterSet actually mutate the original CharacterSet.

import Foundation
var cs = CharacterSet(charactersIn: "foo")
cs.insert(charactersIn: "bar")
(cs as! NSMutableCharacterSet).addCharacters(in: "x")
print(cs.contains("x")) // should be false, prints true

Unfortunately, fixing this will have performance implications on any code that has to bridge it to Obj-C, especially if it does so repeatedly.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Oct 19, 2018

I think the ideal solution here would be, if the character set is mutable, to have the act of bridging actually replace the inner storage with the copied immutable NSCharacterSet, as bridged character sets are unlikely to be subsequently mutated and mutable character sets have a performance penalty (see SR-3006). But Swift has no precedent for a bridging operation actually mutating the source value.

Barring that, it might be worth actually considering the idea of changing CharacterSet to be immutable and to have a separate type as a mutable character set. This way CharacterSet can be guaranteed to be backed by an NSCharacterSet, and the separate type can be non-bridgeable and thus sidestep the issue of exposing its NSMutableCharacterSet. This separate type could be something like a CharacterSetBuilder that uses a builder pattern API to construct a CharacterSet (the idea being that character sets are generally not mutated after they're constructed, any such changes after the fact are usually done with the immutable methods that return new character sets). For backwards compatibility reasons we can keep the mutating methods on CharacterSet but deprecate them, and then fix CharacterSet's Obj-C bridging to copy the inner NSMutableCharacterSet if mutable. And finally, we can ensure that all non-deprecated CharacterSet methods result in having an immutable NSCharacterSet as the backing storage (such as the methods that return a brand new character set; I haven't checked what they do today, but hopefully the backing storage for the returned character set is already immutable).

I'm not aware of any precedent for the Swift stdlib / SDK overlay to provide a builder pattern like this, but this approach very neatly ensures that anyone constructing a CharacterSet will end up with an immutable backing storage, which is important for performance reasons.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Oct 19, 2018

I just checked and it turns out the CharacterSet methods that return new sets (e.g. union) actually return sets backed by NSMutableCharacterSet.

@belkadan
Copy link

cc @millenomi

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant