See documentation comment for discussion


(Maury Markowitz) #1

I've previously used myString[0...1] to get the first character of a string. I assume that is now myString[0..<2]? In any event, the error states:

'subscript' is unavailable: cannot subscript String with a CountableClosedRange<Int>, see the documentation comment for discussion

What documentation is this referring to? There's no right-click definition available, nothing in Navigator, and Google fails to turn up anything. I suspect its referring to the changelist or maybe github checkin notes?


(Brent Royal-Gordon) #2

I've previously used myString[0...1] to get the first character of a string.

I'm not sure how, because this has never worked in Swift. Strings use opaque indices which specifically prevent you from doing this, so you have never been able to subscript a string with integers or ranges of integers. It's done this way because indexing into a Unicode string intrinsically requires walking through the data structure and counting characters one at a time; the lack of integer indices is meant to force you to explicitly write `index(after:)` or `index(_:offsetBy:)` (formerly `successor()` or `advancedBy(_:)`) in your code to make this cost obvious.

What documentation is this referring to? There's no right-click definition available, nothing in Navigator, and Google fails to turn up anything.

The standard library includes definitions of these subscripts which are meant to direct you to documentation explaining why they're not supported, but these definitions don't show up in the generated interfaces. Presumably Xcode is removing all APIs marked "unavailable". The doc comment it's trying to direct you to is here <https://github.com/apple/swift/blob/b8401e1fde52d95e5a8ce7b043a3c5a3bcf72181/stdlib/public/core/UnavailableStringAPIs.swift.gyb#L15>:

  /// Subscripting strings with integers is not available.
  ///
  /// The concept of "the `i`th character in a string" has
  /// different interpretations in different libraries and system
  /// components. The correct interpretation should be selected
  /// according to the use case and the APIs involved, so `String`
  /// cannot be subscripted with an integer.
  ///
  /// Swift provides several different ways to access the character
  /// data stored inside strings.
  ///
  /// - `String.utf8` is a collection of UTF-8 code units in the
  /// string. Use this API when converting the string to UTF-8.
  /// Most POSIX APIs process strings in terms of UTF-8 code units.
  ///
  /// - `String.utf16` is a collection of UTF-16 code units in
  /// string. Most Cocoa and Cocoa touch APIs process strings in
  /// terms of UTF-16 code units. For example, instances of
  /// `NSRange` used with `NSAttributedString` and
  /// `NSRegularExpression` store substring offsets and lengths in
  /// terms of UTF-16 code units.
  ///
  /// - `String.unicodeScalars` is a collection of Unicode scalars.
  /// Use this API when you are performing low-level manipulation
  /// of character data.
  ///
  /// - `String.characters` is a collection of extended grapheme
  /// clusters, which are an approximation of user-perceived
  /// characters.
  ///
  /// Note that when processing strings that contain human-readable
  /// text, character-by-character processing should be avoided to
  /// the largest extent possible. Use high-level locale-sensitive
  /// Unicode algorithms instead, for example,
  /// `String.localizedStandardCompare()`,
  /// `String.localizedLowercaseString`,
  /// `String.localizedStandardRangeOfString()` etc.

···

--
Brent Royal-Gordon
Architechies


(Svein Halvor Halvorsen) #3

let firstLetter = myString.characters.first

···

lør. 18. jun. 2016 kl. 04.38 skrev Brent Royal-Gordon via swift-users < swift-users@swift.org>:

> I've previously used myString[0...1] to get the first character of a
string.

I'm not sure how, because this has never worked in Swift. Strings use
opaque indices which specifically prevent you from doing this, so you have
never been able to subscript a string with integers or ranges of integers.
It's done this way because indexing into a Unicode string intrinsically
requires walking through the data structure and counting characters one at
a time; the lack of integer indices is meant to force you to explicitly
write `index(after:)` or `index(_:offsetBy:)` (formerly `successor()` or
`advancedBy(_:)`) in your code to make this cost obvious.

> What documentation is this referring to? There's no right-click
definition available, nothing in Navigator, and Google fails to turn up
anything.

The standard library includes definitions of these subscripts which are
meant to direct you to documentation explaining why they're not supported,
but these definitions don't show up in the generated interfaces. Presumably
Xcode is removing all APIs marked "unavailable". The doc comment it's
trying to direct you to is here <
https://github.com/apple/swift/blob/b8401e1fde52d95e5a8ce7b043a3c5a3bcf72181/stdlib/public/core/UnavailableStringAPIs.swift.gyb#L15
>:

  /// Subscripting strings with integers is not available.
  ///
  /// The concept of "the `i`th character in a string" has
  /// different interpretations in different libraries and system
  /// components. The correct interpretation should be selected
  /// according to the use case and the APIs involved, so `String`
  /// cannot be subscripted with an integer.
  ///
  /// Swift provides several different ways to access the character
  /// data stored inside strings.
  ///
  /// - `String.utf8` is a collection of UTF-8 code units in the
  /// string. Use this API when converting the string to UTF-8.
  /// Most POSIX APIs process strings in terms of UTF-8 code units.
  ///
  /// - `String.utf16` is a collection of UTF-16 code units in
  /// string. Most Cocoa and Cocoa touch APIs process strings in
  /// terms of UTF-16 code units. For example, instances of
  /// `NSRange` used with `NSAttributedString` and
  /// `NSRegularExpression` store substring offsets and lengths in
  /// terms of UTF-16 code units.
  ///
  /// - `String.unicodeScalars` is a collection of Unicode scalars.
  /// Use this API when you are performing low-level manipulation
  /// of character data.
  ///
  /// - `String.characters` is a collection of extended grapheme
  /// clusters, which are an approximation of user-perceived
  /// characters.
  ///
  /// Note that when processing strings that contain human-readable
  /// text, character-by-character processing should be avoided to
  /// the largest extent possible. Use high-level locale-sensitive
  /// Unicode algorithms instead, for example,
  /// `String.localizedStandardCompare()`,
  /// `String.localizedLowercaseString`,
  /// `String.localizedStandardRangeOfString()` etc.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Maury Markowitz) #4

The standard library includes definitions of these subscripts

But how would one select those in the Xcode UI? The documentation doesn't link off the error (AFAIK) itself, only the code. So one could select, say, the var the error is related to, but not the []'s themselves, no?

/// components. The correct interpretation should be selected
/// according to the use case and the APIs involved, so `String`
/// cannot be subscripted with an integer.

All true, except, of course, when one is working with strings that really do work perfectly weel qwith 1...2, like the strings I'm processing, which came from 80-column punch cards originally used with LLNL's CDC 6600 (serial #2 IIRC). I had totally forgotten I had written this:

subscript (r: Range<Int>) -> String {
    get {
        let subStart = self.characters.index(self.startIndex, offsetBy: r.lowerBound, limitedBy: self.endIndex)
  let subEnd = self.characters.index(subStart!, offsetBy: r.upperBound - r.lowerBound, limitedBy: self.endIndex)
  return self.substring(with: subStart!..<subEnd!)
    }
}

Anyone have any ideas why this is suddenly throwing an error, not within this extension, but in the code calling it? It's as if it doesn't see the extension.

p.s. Actually that is NOT the code I wrote. The 2.2->3.0b translator mangled the second let, so I'm not 100% sure what it originally said.

···

On Jun 17, 2016, at 10:38 PM, Brent Royal-Gordon <brent@architechies.com> wrote:


(Marco S Hyman) #5

I’d claim those are not strings, they are arrays of Uint8.

As for your subscript... in the code "mystring[0...1]” [0...1] is not a Range<Int>, it is a CountableClosedRange<Int>. The error message told you that. If you change your subscript to use CountableClosedRange<Int> instead of Range<Int> it works -- but it’s not something I think I’d do.

Marc

···

On Jun 19, 2016, at 6:35 PM, Maury Markowitz via swift-users <swift-users@swift.org> wrote:

All true, except, of course, when one is working with strings that really do work perfectly weel qwith 1...2, like the strings I'm processing, which came from 80-column punch cards originally used with LLNL's CDC 6600 (serial #2 IIRC). I had totally forgotten I had written this:


(Maury Markowitz) #6

But that doesn't explain why it works fine under Swift 2.2, which is the basis of the question.

The change does not appear to be to string itself, but to either 'subscript' or perhaps the method signatures so Range no longer accepts closed ranges?

···

On Jun 19, 2016, at 10:45 PM, Marco S Hyman <marc@snafu.org> wrote:

As for your subscript... in the code "mystring[0...1]” [0...1] is not a Range<Int>, it is a CountableClosedRange<Int>.