Proposal: Add StaticString.UnicodeScalarView


(Lily Ballard) #1

There's no way to create a substring of `StaticString` that's still
typed as `StaticString`. This is occasionally desirable, for example if
you want to extract the filename from `__FILE__` to pass to another API
that requires a `StaticString`.

I believe the best solution to this is to add a type
`StaticString.UnicodeScalarView`, similar to `String.UnicodeScalarView`.
`StaticString` would also be extended with a property `unicodeScalars`
and two initializers to construct a `StaticString` from a
`String.UnicodeScalarView`. The full proposed API looks like:

extension StaticString { /// The value of `self` as a collection of
[Unicode scalar values]
(http://www.unicode.org/glossary/#unicode_scalar_value). public var
unicodeScalars: UnicodeScalarView

/// Construct the `StaticString` corresponding to the given ///
`UnicodeScalarView`. public init(_: UnicodeScalarView)

/// Construct the `StaticString` corresponding to the given ///
`UnicodeScalarView` slice. public init(_: Slice<UnicodeScalarView>)

/// A collection of [Unicode scalar values]
(http://www.unicode.org/glossary/#unicode_scalar_value) that /// encode
a `StaticString`. public struct UnicodeScalarView : CollectionType {

init(_: StaticString)

/// A position in a `StaticString.UnicodeScalarView`. public struct
Index : BidirectionalIndexType, Comparable { /// Returns the next
consecutive value after `self`. /// /// - Requires: The next
value is representable. @warn_unused_result public func
successor() -> Index

/// Returns the previous consecutive value before `self`. ///
/// - Requires: The previous value is representable.
@warn_unused_result public func predecessor() -> Index }

/// The position of the first `UnicodeScalar` if the `StaticString` is
/// non-empty; identical to `endIndex` otherwise. public var
startIndex: Index

/// The "past the end" position. /// /// `endIndex` is not a valid
argument to `subscript`, and is always /// reachable from
`startIndex` by zero or more applications of /// `successor()`.
public var endIndex: Index

/// Returns `true` iff `self` is empty. public var isEmpty: Bool

public subscript(position: Index) -> UnicodeScalar } }

An alternative would be to make StaticString itself conform to
CollectionType, but this is a bad idea for the same reasons that String
doesn't conform to CollectionType.

-Kevin Ballard


(Lily Ballard) #2

I've submitted a proposal for this as

https://github.com/apple/swift-evolution/pull/32

I also have an implementation written as

https://github.com/apple/swift/pull/277

-Kevin Ballard

···

On Sun, Dec 6, 2015, at 01:21 AM, Kevin Ballard wrote:

There's no way to create a substring of `StaticString` that's still
typed as `StaticString`. This is occasionally desirable, for example
if you want to extract the filename from `__FILE__` to pass to another
API that requires a `StaticString`.

I believe the best solution to this is to add a type
`StaticString.UnicodeScalarView`, similar to
`String.UnicodeScalarView`. `StaticString` would also be extended with
a property `unicodeScalars` and two initializers to construct a
`StaticString` from a `String.UnicodeScalarView`. The full proposed
API looks like:

extension StaticString { /// The value of `self` as a collection of
[Unicode scalar values]
(http://www.unicode.org/glossary/#unicode_scalar_value). public var
unicodeScalars: UnicodeScalarView

/// Construct the `StaticString` corresponding to the given ///
`UnicodeScalarView`. public init(_: UnicodeScalarView)

/// Construct the `StaticString` corresponding to the given ///
`UnicodeScalarView` slice. public init(_: Slice<UnicodeScalarView>)

/// A collection of [Unicode scalar values]
(http://www.unicode.org/glossary/#unicode_scalar_value) that ///
encode a `StaticString`. public struct UnicodeScalarView :
CollectionType {

init(_: StaticString)

/// A position in a `StaticString.UnicodeScalarView`. public struct
Index : BidirectionalIndexType, Comparable { /// Returns the next
consecutive value after `self`. /// /// - Requires: The next
value is representable. @warn_unused_result public func
successor() -> Index

/// Returns the previous consecutive value before `self`. ///
/// - Requires: The previous value is representable.
@warn_unused_result public func predecessor() -> Index }

/// The position of the first `UnicodeScalar` if the `StaticString` is
/// non-empty; identical to `endIndex` otherwise. public var
startIndex: Index

/// The "past the end" position. /// /// `endIndex` is not a
valid argument to `subscript`, and is always /// reachable from
`startIndex` by zero or more applications of /// `successor()`.
public var endIndex: Index

/// Returns `true` iff `self` is empty. public var isEmpty: Bool

public subscript(position: Index) -> UnicodeScalar } }

An alternative would be to make StaticString itself conform to
CollectionType, but this is a bad idea for the same reasons that
String doesn't conform to CollectionType.

-Kevin Ballard


(Dmitri Gribenko) #3

Hi Kevin,

Thank you for the proposal. This is in line with the current design of
String. One of the Swift 3 goals is a redesign of String, to make the API
easier to use. I don't think that should block this improvement, since
whatever the new design is, it should provide the UnicodeScalar view
functionality for String, and the same API should be exposed on
StaticString.

There's no way to create a substring of `StaticString` that's still typed
as `StaticString`. This is occasionally desirable, for example if you want
to extract the filename from `__FILE__` to pass to another API that
requires a `StaticString`.

I believe the best solution to this is to add a type
`StaticString.UnicodeScalarView`, similar to `String.UnicodeScalarView`.
`StaticString` would also be extended with a property `unicodeScalars` and
two initializers to construct a `StaticString` from a
`String.UnicodeScalarView`. The full proposed API looks like:

extension StaticString {
  /// The value of `self` as a collection of [Unicode scalar values](
http://www.unicode.org/glossary/#unicode_scalar_value).
  public var unicodeScalars: UnicodeScalarView

  /// Construct the `StaticString` corresponding to the given
  /// `UnicodeScalarView`.
  public init(_: UnicodeScalarView)

  /// Construct the `StaticString` corresponding to the given
  /// `UnicodeScalarView` slice.
  public init(_: Slice<UnicodeScalarView>)

  /// A collection of [Unicode scalar values](
http://www.unicode.org/glossary/#unicode_scalar_value) that
  /// encode a `StaticString`.
  public struct UnicodeScalarView : CollectionType {

UnicodeScalarView should be a slice type, that is,
UnicodeScalarView.SubSequence == UnicodeScalarView.

Then, you will be able to remove the
StaticString.init(Slice<UnicodeScalarView>) initializer.

It should also be CustomStringConvertible, CustomDebugStringConvertible,
with the same behavior as String.

Please also add a CustomReflectable conformance, that extracts the string
value and reflects that.

    init(_: StaticString)

    /// A position in a `StaticString.UnicodeScalarView`.
    public struct Index : BidirectionalIndexType, Comparable {
      /// Returns the next consecutive value after `self`.
      ///
      /// - Requires: The next value is representable.
      @warn_unused_result
      public func successor() -> Index

      /// Returns the previous consecutive value before `self`.
      ///
      /// - Requires: The previous value is representable.
      @warn_unused_result
      public func predecessor() -> Index
    }

    /// The position of the first `UnicodeScalar` if the `StaticString` is
    /// non-empty; identical to `endIndex` otherwise.
    public var startIndex: Index

    /// The "past the end" position.
    ///
    /// `endIndex` is not a valid argument to `subscript`, and is always
    /// reachable from `startIndex` by zero or more applications of
    /// `successor()`.
    public var endIndex: Index

    /// Returns `true` iff `self` is empty.
    public var isEmpty: Bool

    public subscript(position: Index) -> UnicodeScalar
  }
}

You omitted == and < APIs for indices.

An alternative would be to make StaticString itself conform to
CollectionType, but this is a bad idea for the same reasons that String
doesn't conform to CollectionType.

Agreed.

Dmitri

···

On Sun, Dec 6, 2015 at 1:21 AM, Kevin Ballard via swift-evolution < swift-evolution@swift.org> wrote:

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/