Proposal: Improve Import of Scanner APIs into Swift 3


(Oliver Drobnik) #1

Working on a function for Foundation’s Scanner I stumbled on this LLVM crash: https://bugs.swift.org/browse/SR-3295

This got me thinking about a workaround and I would like to prose this:

When importing Foundation into Swift 3, all

AutoreleasingUnsafeMutablePointer<T?>?

should instead be exposed as simple:

inout T?

e.g.

open func scanString(_ string: String, into result: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool

would become

open func scanString(_ string: String, into result: inout String?) -> Bool

The call would stay exactly the same for normal use cases where you specify a receiving variable:

var string: String?
scanString("=", into: &string)

because inout parameters require a &

for the use case where you don’t require a receiving parameter, a second method without result parameter would be generated:

open func scanString(_ string: String) -> Bool

This is necessary because you cannot specify nil or an immutable value for an inout parameter.

A fixit/migration would change calls to

scanString(“foo", into result: nil)

into

scanString(“foo")

The normal call with receiving variable would stay the same. But the case without return would become more concise.

What do you think?

kind regards
Oliver Drobnik


(Ben Rimmington) #2

<https://github.com/apple/swift-corelibs-foundation/blob/5f8656628c79bf4df3980efbf45dfb3eebd35766/Foundation/NSScanner.swift#L485-L487>

  /// Revised API for avoiding usage of AutoreleasingUnsafeMutablePointer and better Optional usage.
  /// - Experiment: This is a draft API currently under consideration for official import into Foundation as a suitable alternative
  /// - Note: Since this API is under consideration it may be either removed or revised in the near future
  extension Scanner {
      public func scanInt() -> Int32?
      public func scanInteger() -> Int?
      public func scanLongLong() -> Int64?
      public func scanUnsignedLongLong() -> UInt64?
      public func scanFloat() -> Float?
      public func scanDouble() -> Double?
      public func scanHexInt() -> UInt32?
      public func scanHexLongLong() -> UInt64?
      public func scanHexFloat() -> Float?
      public func scanHexDouble() -> Double?
      public func scanString(string searchString: String) -> String?
      public func scanCharactersFromSet(_ set: CharacterSet) -> String?
      public func scanUpToString(_ string: String) -> String?
      public func scanUpToCharactersFromSet(_ set: CharacterSet) -> String?
  }

Foundation issues should be discussed on the swift-corelibs-dev list.

-- Ben

···

On 30 Nov 2016, at 10:10, Oliver Drobnik via swift-evolution <swift-evolution@swift.org> wrote:

Working on a function for Foundation’s Scanner I stumbled on this LLVM crash: https://bugs.swift.org/browse/SR-3295

This got me thinking about a workaround and I would like to prose this:

When importing Foundation into Swift 3, all

AutoreleasingUnsafeMutablePointer<T?>?

should instead be exposed as simple:

inout T?

e.g.

open func scanString(_ string: String, into result: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool

would become

open func scanString(_ string: String, into result: inout String?) -> Bool

The call would stay exactly the same for normal use cases where you specify a receiving variable:

var string: String?
scanString("=", into: &string)

because inout parameters require a &

for the use case where you don’t require a receiving parameter, a second method without result parameter would be generated:

open func scanString(_ string: String) -> Bool

This is necessary because you cannot specify nil or an immutable value for an inout parameter.

A fixit/migration would change calls to

scanString(“foo", into result: nil)

into

scanString(“foo")

The normal call with receiving variable would stay the same. But the case without return would become more concise.

What do you think?

kind regards
Oliver Drobnik