Getting error: String is not convertible to 'T' - swift

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.

Related

Generic parameter 'T' could not be inferred after assignment

// Xcode 11.6 / Swift 5
import Foundation
func f<T>(_: (T) -> Void) { }
#discardableResult
func g(_: Int) -> Int { 0 }
f { g($0) } // compiles fine
f { let _ = g($0) } // Generic parameter 'T' could not be inferred
In the above code, the generic function f expects as its argument a function that takes an argument of type T.
The function g takes an argument of type Int.
When I write f { g($0) }, the code compiles. I believe (please correct me if I'm wrong) this compiles because the compiler can infer that T is an Int based on g's argument type.
However, when I try to do something with the return value of g, for example in the let _ = g($0) line, the compiler complains that it can no longer infer the type of T.
It seems to me the return type of g should have no bearing on how the compiler infers T's type, but clearly it does.
Can anyone shed some light on why this happens, and what (if anything) can be done to correct it?
This may or may not be a compiler bug.
It is known that Swift does not try to infer the types of some closures, namely, multi-statement ones, as said in SR-1570:
This is correct behavior: Swift does not infer parameter or return types from the bodies of multi-statement closures.
However, your closure consists of only one statement, one declaration to be specific. It is possible, albeit weird, that they designed it so that Swift doesn't try to infer types if the closure contains one declaration as well. For example, this does not compile either
f { let x: Int = $0 } // nothing to do with "g"! The issue seems to be with declarations
If this were by-design, the rationale behind it might be because a single declaration in a closure doesn't make much sense anyway. Whatever is declared, won't be used.
But again, this is just speculation, and this could be a bug as well.
To fix it, simply make it a not-a-declaration:
f { _ = g($0) } // this, without the "let", is IMO the idiomatic way to ignore the function result
Or
f { g($0) } // g has #discardableResult anyway, so you don't even need the wildcard
The function f takes in a function as a parameter which in turn takes a parameter of type T and returns nothing (Void). For a closure to infer types automatically, it has to consist of single (and sometimes simple) expression. Anything complex makes it difficult for the compiler to infer (which makes sense from the compiler's standpoint). Apparently, let _ = g($0) is a complex statement as far as the compiler is concerned. For further information, see this mailing list discussion
it looks like #discardableResult gives you an ability to have 2 types of functions:
g(_: Int) -> Int and g(_: Int) -> Void (it is when you don't want to use a result of function)
I think that
f { g($0) } - here your f can infer a type because it has the same Type
(_: (T) -> Void) and (_: (Int) -> Void)
f { let _ = g($0) } - in this case the type of g function is different from f function
(_: (T) -> Void) and (_: (Int) -> Int)
If you will remove "let" it will compile again:
f { _ = g($0) }
I think that
f { let _ = g($0) } - return only Int value
f { _ = g($0) } - return function (_: (Int) -> Int)
Maybe it is a key here

How to make mutable copy of let parameter in generic function in Swift

I'm trying to make a generic test function in Swift that tests a function that mutates its argument. However, I get an error message that I can't find a way to solve:
public func testMutating<T: Comparable>(id: Int, input: T, output: T, testObj: (T) -> Any) {
var inputMutating = input // Make a mutable copy of input
_ = testObj(&inputMutating) // Compiler error: Argument type 'inout T' does not conform to expected type 'Comparable'
if (inputMutating == output) {
print("Test \(id) PASSED :D")
} else {
print("Test \(id) FAILED :(")
print(" Expected: \(output)")
print(" Actual : \(inputMutating)")
}
}
You need to set the testObj parameter to inout
Like this:
public func testMutating<T: Comparable>(id: Int, input: T, output: T, testObj: (inout T) -> Any) {
In other words, &inputMutating is not of type T like you declared it, it's of type inout T.
Also, if you are only testing for equality, it would be better to use Equatable instead of Comparable as generic constraint.

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
}

Return any type from a function in Swift

I am attempting to create a function that can return any type. I do not want it to return an object of type Any, but of other types, i.e. String, Bool, Int, etc. You get the idea.
You can easily do this using generics in this fashion:
func example<T>(_ arg: T) -> T {
// Stuff here
}
But is it possible to do it without passing in any arguments of the same type? Here is what I am thinking of:
func example<T>() -> T {
// Stuff here
}
When I try to do this, everything works until I call the function, then I get this error:
generic parameter 'T' could not be inferred
is it possible to do it without passing in any arguments of the same type?
The answer is yes, but there needs to be a way for the compiler to infer the correct version of the generic function. If it knows what it is assigning the result to, it will work. So for instance, you could explicitly type a let or var declaration. The below works in a playground on Swift 3.
protocol Fooable
{
init()
}
extension Int: Fooable {}
extension String: Fooable {}
func foo<T: Fooable>() -> T
{
return T()
}
let x: String = foo() // x is assigned the empty string
let y: Int = foo() // y is assigned 0

Swift 2.0 Generics and Type Safety Issues

I was doing this tutorial http://blog.teamtreehouse.com/introduction-learn-power-swift-generics and I came upon this code;
func someFunction<T, U>(a: T, b: U) {}
The problem is when I call the function using
someFunction<String, Int>(1, "Test")
I get an error saying "cannot explicitly specialize a generic function".
I then change it to
someFunction(1,b: "Test")
and now there is no error. The problem is that there is now no type safety. (Is there something wrong with the code, as it was written before swift 2.0?) What is the best way to re-introduce type safety?
The declaration is completely generic and is specifying that any two types can be used.
func someFunction<T, U>(a: T, b: U) {}
It is not that there is no type safety in Swift, this is how you express a generic without any type constraints.
You get what you ask for.
If you wanted to constrain the function to String and Int, you would have written it as
func someFunction(a:String, b:Int)
Generics are more often used with collections, protocols and classes. Basic types rarely need them :
func someFunction<T:Comparable, U:Comparable>(a:T, b:U) -> Bool
{ return (a < b) || (a > b) }
ok, see this 'self explanatory' example. try it in playground and play with it a little bit.
func foo<T>(t: T)->T {
return t
}
// here the resulting type is infered by compiler
let i = foo(1) // 1
let j: Int = foo(1) // 1
let t = foo("alpha") // "alpha"
// if you declare it self ..
//let s: String = foo(1) // error: cannot convert value of type 'Int' to expected argument type 'String'
/* this fails to compile!
func bar<T>(t:T)->Int {
return t.count
}
*/
/* this fails to compile too !!
func bar0<T:CollectionType>(t:T)->Int {
return t.count
}
*/
func bar<T:CollectionType>(t:T)->T.Index.Distance {
return t.count
}
let arr = [1,2,3]
let k:Int = bar(arr) // 3
print(k.dynamicType) // Int
// and even more interesting
let l = bar(arr)
print(l.dynamicType) // Int