Surprising replacingOccurrences Results for Unicode-Unaware Developers

After importing Foundation, explicitly or implicitly, String autocompletion merges methods from the Swift Standard Library String and Foundation’s NSString.

This can lead to situations where something as simple as replacing a substring is performed using an NSString method that operates at the code-point level, instead of the modern, native Standard Library replace(_:with:) method, which operates on extended grapheme clusters. This largely happens because knowledge of Unicode and string-processing concepts, and of the differences between String and NSString, including how to identify which type a method suggested by autocompletion belongs to, is not widespread.

Example:

"🇨🇦🇺🇸".replacingOccurrences(of: "🇦🇺", with: "🇳🇮")
Result: 🇨🇳🇮🇸

At the root level, Swift’s String operates on extended grapheme clusters, while its views operate at different levels:

  • utf8 view works on UTF-8 code units ,
  • utf16 view works on UTF-16 code units ,
  • unicodeScalars view works on Unicode scalar values (code points) .

As a result, NSString root-level methods operating at different semantic levels (code units, code points, and extended grapheme clusters) are mixed into autocompletion alongside the well-designed root-level Swift Standard Library String methods, which consistently operate on extended grapheme clusters. This mixing happens not only at the logical API level but also across different underlying storage encodings: UTF-8 for String and UTF-16 for NSString.

This is not a criticism of NSString. It was designed for NeXTSTEP, shaped by early Unicode versions (1.1 and 2.0), and has continually evolved to support newer Unicode features.

Questions:

  1. Will autocompletion in the future gain configuration options that allow certain methods to be excluded from suggestions?
  2. Could String eventually stop being toll-free bridged to NSString?
  3. Alternatively, could another mechanism be introduced to restrict autocompletion to String methods from the Swift Standard Library only?
  4. Are there any functionalities missing from the Swift Standard Library String type that are currently implemented only in NSString?
6 Likes

The contains method changing behavior when importing Foundation is also surprising and good to be aware of:

2 Likes

Cool find!

Could we mark NSString methods deprecated?

FWIW:

  • same behaviour in other languages (tried Kotlin, Go, C# and Python)
  • same behaviour in Xcode and TextEdit on mac
  • works correctly in Safary and Chrome on mac
3 Likes