Cannot invoke initializer for type 'Range<_>' with an argument list of type '(Range<String.Index>)' - range

Since Xcode 10 I receive an error message Cannot invoke initializer for type 'Range<_>' with an argument list of type '(Range<String.Index>)' at the return line in the code below, which is an extension used to get a substring when needed.
I have found another good answer given by Martin R at Cannot invoke initializer for type 'Range<String.Index>' with an argument list of type '(Range<String.Index>)', but didn't find a way yet to fix my problem.
extension String {
subscript (i: Int) -> Character { return self[index(startIndex, offsetBy: i)] }
subscript (i: Int) -> String { return String(self[i] as Character) }
subscript (r: Range<Int>) -> String {
let start = index(startIndex, offsetBy: r.lowerBound)
let end = index(startIndex, offsetBy: r.upperBound)
return String(self[Range(start ..< end)])
}
}

Related

Cannot subscript on Collection with a type of Self.Index

This answer suggests how to extend the String class to enable subscripting. I thought it could be reused across my app by extending the Collection protocol instead. But this bit:
// https://stackoverflow.com/a/46634511
extension Collection {
subscript(value: Int) -> Self.SubSequence {
self[index(at: value)]
}
private func index(at offset: Int) -> Self.Index {
index(startIndex, offsetBy: offset)
}
}
cannot be compiled, because:
test.swift:3:7: error: cannot subscript a value of type 'Self' with an argument of type 'Self.Index'
self[index(at: value)]
^
test.swift:3:7: note: overloads for 'subscript' exist with these partially matching parameter lists: ((UnboundedRange_) -> ()), (Int), (Range<Self.Index>)
self[index(at: value)]
^
According to the docs, Collection already lets you subscript by index, but clearly the compiler doesn't recognize it.
What is going on here?
You have used the wrong return type for the subscript. It should be Self.Element, not Self.SubSequence:
subscript(value: Int) -> Self.Element {
self[index(at: value)]
}
Presuambly, the compiler finds that there is a subscript that returns a Self.SubSequence (the return type apparently takes priority in overload resolution here), and notices that it doesn't accept a Self.Index, hence the error.
A more helpful compiler would probably output an error message like "cannot convert return expression of type Self.Element to return type Self.SubSequence".

Error cannot invoke initializer for type 'Range<_>' with an argument list of type '(Range<String.Index>)'

Why do I get the error, Cannot invoke initializer for type 'Range<_>' with an argument list of type '(Range)'
extension String {
subscript (i: Int) -> Character {
if self.isEmpty {
return Character("")
}
if i > self.characters.count {
return Character("")
}
return self[self.index(self.startIndex, offsetBy: i)]
}
subscript (i: Int) -> String {
if self.isEmpty {
return ""
}
if i > self.characters.count {
return ""
}
return String(self[i] as Character)
}
subscript (r: Range<Int>) -> String {
let start = self.index(self.startIndex, offsetBy: r.lowerBound)
let end = self.index(start, offsetBy: r.upperBound - r.lowerBound)
return self[Range(start ..< end)]
}
}

Why does use of closure shorthand-named variables has to be exhaustive in a singular return expression in Swift?

The following piece of code are erroneous in Swift.
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {$0}))
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {return $0}))
The error given by XCode playground is Cannot convert value of type '(Int, Int)' to closure result type 'Int'.
While the following pieces of code are completely fine.
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {$0 + $1}))
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {$1; return $0}))
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {a, b in a}))
It seems that in a situation where arguments to a closure are referred to by shorthand argument names, they must be used exhaustively if the the body of the closure only consists of the return expression. Why?
If you just use $0, the closure arguments are assumed to be a tuple instead of multiple variables $0, $1 etc. So you should be able to work around this by extracting the first value of that tuple:
print(foo(closure: {$0.0}))
Your "why" is like asking "why is an American football field 100 yards long?" It's because those are the rules. An anonymous function body that takes parameters must explicitly acknowledge all parameters. It can do this in any of three ways:
Represent them using $0, $1, ... notation.
Represent them using parameter names in an in line.
Explicitly discard them by using _ in an in line.
So, let's take a much simpler example than yours:
func f(_ ff:(Int)->(Void)) {}
As you can see, the function f takes one parameter, which is a function taking one parameter.
Well then, let's try handing some anonymous functions to f.
This is legal because we name the parameter in an in line:
f {
myParam in
}
And this is legal because we accept the parameter using $0 notation:
f {
$0
}
And this is legal because we explicitly throw away the parameter using _ in the in line:
f {
_ in
}
But this is not legal:
f {
1 // error: contextual type for closure argument list expects 1 argument,
// which cannot be implicitly ignored
}

Swift block syntax failure to infer type

Can anyone explain why this single line block with an implicit return compiles:
let r = withUnsafePointer(&msg) {
dn_expand(UnsafePointer($0), eomorig: UnsafePointer($0).advancedBy(msg.count), comp_dn: UnsafePointer($0).advancedBy(offset), exp_dn: &buf, length: buf.count)
}
but this version refactored where the only difference is to avoid the multiple calls to UnsafePointer($0) doesn't:
let s = withUnsafePointer(&msg) {
let p = UnsafePointer($0)
return dn_expand(p, eomorig: p.advancedBy(msg.count), comp_dn: p.advancedBy(offset), exp_dn: &buf, length: buf.count)
}
with error message:
Cannot convert value of type 'inout [UInt8]' (aka 'inout Array<UInt8>') to expected argument type 'inout _'
The dn_function being called is just a trivial wrapper around dn_expand from libresolv:
public static func dn_expand(msg: UnsafePointer<UInt8>, eomorig: UnsafePointer<UInt8>, comp_dn: UnsafePointer<UInt8>, exp_dn: UnsafeMutablePointer<CChar>, length: Int) -> Int {
return Int(res_9_dn_expand(msg, eomorig, comp_dn, exp_dn, Int32(length)))
}
As already said in the comments, withUnsafePointer() is not the
correct way to get a pointer to the element storage. It compiles, but
gives unexpected results, as the following example demonstrates:
var msg: [UInt8] = [1, 2, 3, 4]
func foo(x: UnsafePointer<UInt8>) {
print(x[0])
}
withUnsafePointer(&msg) {
foo(UnsafePointer($0))
}
This prints "random" numbers, but not the expected 1. The correct
way is to call the withUnsafeBufferPointer() method on the array:
msg.withUnsafeBufferPointer {
foo($0.baseAddress)
}
In your case that would be
let r = msg.withUnsafeBufferPointer {
dn_expand($0.baseAddress, eomorig: $0.baseAddress + $0.count, ...)
}
Here the return type of the closure is inferred automatically because
it is a "single-expression" closure. If the closure contains more
than one expression, you have to specify its type:
let r = msg.withUnsafeBufferPointer { bufPtr -> Int in
let p = bufPtr.baseAddress
return dn_expand(p, eomorig: p + msg.count, ...)
}
or let the compiler infer the return type from the context:
let r: Int = msg.withUnsafeBufferPointer { bufPtr in
let p = bufPtr.baseAddress
return dn_expand(p, eomorig: p + msg.count, ...)
}

Why do I get an error when attempting to invoke indexOf on a generic ArraySlice?

The following function finds the second index of a given item in Array of Int:
func secondIndexOf(item: Int, inArray array: Array<Int>) -> Int? {
if let firstIndex: Int = array.indexOf(item) {
let slice: ArraySlice<Int> = array.suffixFrom(firstIndex + 1)
return slice.indexOf(item)
}
return nil
}
However, when I attempt to create a generic version of this function to find the second Equatable item, I get an error:
func secondIndexOf<T: Equatable>(item: T, inArray array: Array<T>) -> T? {
if let firstIndex: Int = array.indexOf(item) {
let slice: ArraySlice<T> = array.suffixFrom(firstIndex + 1)
return slice.indexOf(item) // Cannot invoke 'indexOf' with an argument list of type '(T)'
}
return nil
}
Why is this not valid Swift code, and what is the expected argument list if not (T)? Xcode autocomplete shows indexOf(element: Comparable) with which T should be compatible.
The compiler is giving you a confusing error message hereā€”it isn't actually concerned about the argument. The return value is the source of the problem, since you aren't returning a value of type T, but an index of the array. You just need to change your return type to Int?:
func secondIndexOf<T: Equatable>(item: T, inArray array: Array<T>) -> Int? {
if let firstIndex: Int = array.indexOf(item) {
let slice: ArraySlice<T> = array.suffixFrom(firstIndex + 1)
return slice.indexOf(item)
}
return nil
}