Cannot subscript on Collection with a type of Self.Index - swift

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".

Related

What does the swift keyword Wrapped mean in the Optional extension?

What does the swift keyword Wrapped mean in the Optional extension?
extension Optional {
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U? {
guard let x = self else { return nil }
return transform(x)
}
}
In extensions, the generic parameters of the type that you are extending can be referenced by just writing their simple names, and notice that Optional is a generic type.
#frozen enum Optional<Wrapped>
So Wrapped in the function declaration refers to the generic parameter declared there.
As you may know, optional types are usually written as T? (where T is some type), which is a syntactic sugar for Optional<T>. For example, Int? is the same as Optional<Int>, and String? is the same as Optional<String>, etc.
In other words, Wrapped basically just means the type that precedes the ?, whatever that may be. If you have a String? (aka Optional<String>), then the signature of flatMap for that would be:
func flatMap<U>(_ transform: (String) -> U?) -> U?
There is no keyword "Wrapped." This is a type parameter. This is similar to runtime parameters. If you see:
func f(x: Int) { ... }
x is not a keyword. It's just a parameter name. In the same way, Optional is defined as:
enum Optional<Wrapped>
"Wrapped" is just the type parameter passed to Optional. So in this extension:
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U? {
"Wrapped" just refers to whatever Optional is wrapping.

Getting error: String is not convertible to 'T'

This code compiles and works fine:
class Numbers {
func operateOn<T>(_ num1: T, _ num2: T, do task: (T, T) -> ()) {
task(num1, num2)
}
}
let n = Numbers()
n.operateOn(1,2) {
print(($0 + $1) * 10)
}
n.operateOn("l","ll") {
print(($0 + $1))
}
Yet for for following code does not compile.
func process<T> (add: String, completion: (T) -> () ) {
completion("k") // ERROR
}
Yet I get the following error:
'String' is not convertible to 'T'
I tried passing an Int, but I just got another error:
'Int' is not convertible to 'T'
Can't an Int or a String satisfy a generic requirement that doesn't have any constraints?!
The problem is that your code needs to work for any T. E.g. if T is Int then completion has type (Int) -> (), it's completely legitimate to call
n.process<Int>("") { $0 + 1 }
and completion("k") would have to do "k" + 1 which doesn't make sense.
This is going to be the same in basically any language with generics (C++ is different because it uses templates for the same purpose instead).
Can't an Int or a String satisfy a generic requirement that
doesn't have any constraints?!
Sure it can. But that's not the reason the compiler is giving you an error.
Think about it, what happens if you constrain a generic function/parameter within the function body itself?! It will no longer be a generic function!
Imagine if you had wrote your operateOn function as such:
class Numbers {
func operateOn<T>(_ num1: T, _ num2: T, do task: (T, T) -> ()) {
task("k", num2) // add two strings
}
}
Would you say that T is generic? Or that it's of type String? If you made it a String then can num2 be any generic type it wants to be? It can't!
If it's of type String then it's no longer generic. Since the compiler can't allow that it will throw that error.

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
}

Comparing type of literal in swift fails?

This code works is Swift 3:
let a = 1
type(of: a) == Int.self // true
However, remarkably this code fails:
// error: binary operator '==' cannot be applied to two 'Int.Type' operands
type(of: 1) == Int.self
What is the syntax to make the second comparison work, if any?
Thanks a lot.
I think the error message was misleading. The real issue was how to interpret the literal 1 in the second call. Swift defaults to an Int when you define a variable:
let a = 1 // a is an Int
But the compiler can read it as Double, UInt32, CChar, etc. depending on the context:
func takeADouble(value: Double) { ... }
func takeAUInt(value: UInt) { ... }
takeADouble(value: 1) // now it's a Double
takeAUInt(value: 1) // now it's a UInt
type(of:) is defined as a generic function:
func type<Type, Metatype>(of: Type) -> Metatype
The compiler has no clue on how to interpret the Type generic parameter: should it be an Int, UInt, UInt16, etc.? Here's the error I got from the IBM Swift Sandbox:
Overloads for '==' exist with these partially matching parameter lists
(Any.Type?, Any.Type?), (UInt8, UInt8), (Int8, Int8),
(UInt16, UInt16), (Int16, Int16), (UInt32, UInt32), ...
You can give the coompiler some help by tell it what type it is:
type(of: 1 as Int) == Int.self

What is the syntax for a closure argument in swift

In Swift headers, the isSeparator: argument accepts a closure
public func split(maxSplit: Int = default, allowEmptySlices: Bool = default, #noescape isSeparator: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.SubSequence]
But in the documentation, it lists closure syntax differently
{ (parameters) -> return type in
statements
}
How are you supposed to know that (Self.Generator.Element) throws -> Bool rethrows refers to a closure / requires a closure? Are there other ways that the headers/docs might list argument as meaning a closure?
The "thing" giving away that this is a closure is the ->. The full type is
(Self.Generator.Element) throws -> Bool
It means that the closure takes a variable of type Self.Generator.Element and has to return a Bool upon some calculation based on the input. It may additionally throw some error while doing so - that is what the throws is for.
What you then write
{ (parameters) -> return type in
statements
}
would be an actual implementation, a value of some generic closure type.
The type of a closure is for example (someInt:Int, someDouble:Double) -> String:
var a : ((someInt:Int, someDouble:Double) -> String)
Once again the thing giving away that a is actually a closure is the -> in the type declaration.
Then you assign something to a via some code snippet following your second code block:
a = { (integer, floating) -> String in
return "\(integer) \(floating)"
}
You can tell by the argument's type. Everything in Swift has a type, including functions and closures.
For example, this function...
func add(a: Int, to b: Int) -> Int { return a + b }
...has type (Int, Int) -> Int. (It takes two Ints as parameters, and returns an Int.)
And this closure...
let identity: Int -> Int = { $0 }
...has type Int -> Int.
Every function and closure has a type, and in the type signature there is always a -> that separates the parameters from the return value. So anytime you see a parameter (like isSeparator) that has a -> in it, you know that the parameter expects a closure.
the isSeparator definition means (Self.Generator.Element) throws -> Bool that you will be given an Element and you should return a Bool. When you will call split, you then can do the following :
[1,2,3].split(…, isSeparator : { element -> Bool in
return false
})
This is a pure silly example but that illustrates the second part of your question