Proposal: Improve Import of Scanner APIs into Swift 3


(Oliver Drobnik) #1

Earlier I posted this proposal to the Swift Evolution Mailing list. Then I looked at the NSScanner implementation in core libs and found experimental API using the return value to for returning the scanned results. See my comments on that below:

···

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

The new experimental API does not consider the situation that one might just want to scan a token in a long string and since I know what I am scanning I don’t care about the result. For example in my scanning I would like to processed if I hit a “foo“ …

The experimental API would force me to do this:

if let _ = scanString(“foo“) { }

My proposal is more elegant:

if scanString(“foo”) {}

And if you do lots and lots of these scans then performance would benefit from the compiler not having to pack the return for an autoreleasing value which would have to be released right away due to assignment to _.

IMHO my proposal is more in line with the spirit of the original API: 1) return Bool if the scan was successful, 2) optionally return the scanned value.

kind regards
Oliver Drobnik


(Alfredo Delli Bovi) #2

Thanks Oliver for bringing this up.

Anyone can share the thread for the draft/experimental API which is in the implementation? I cannot find it.

About performance, I think the idea is to return Swift types only and not autoreleasing objects anymore.
Still a performance test would be needed to clarify if your proposed solution performs better or not.
Also we have to clarify if this suggestion is in line with Swift API guidelines and maybe find a trade-off if performance is better.

Cheers,
Alfredo Delli Bovi

···

On 30 Nov 2016, at 11:50, Oliver Drobnik via swift-corelibs-dev <swift-corelibs-dev@swift.org> wrote:

Earlier I posted this proposal to the Swift Evolution Mailing list. Then I looked at the NSScanner implementation in core libs and found experimental API using the return value to for returning the scanned results. See my comments on that below:

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

The new experimental API does not consider the situation that one might just want to scan a token in a long string and since I know what I am scanning I don’t care about the result. For example in my scanning I would like to processed if I hit a “foo“ …

The experimental API would force me to do this:

if let _ = scanString(“foo“) { }

My proposal is more elegant:

if scanString(“foo”) {}

And if you do lots and lots of these scans then performance would benefit from the compiler not having to pack the return for an autoreleasing value which would have to be released right away due to assignment to _.

IMHO my proposal is more in line with the spirit of the original API: 1) return Bool if the scan was successful, 2) optionally return the scanned value.

kind regards
Oliver Drobnik
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev