Generic Functions and Protocols in Swift 3.2 failing to infer type - swift

Given the following .
func doSomething<T: JSONDecodable>() -> [T] { return [] }
and a concrete type of Animal: JSONDecodable I'm trying to invoke the doSomething method without specifying the type of Animal.
The following works: let result: [Animal] = doSomething()
The following examples do not:
let result: [JSONDecodable] = doSomething() // Cannot convert value of type '_' to closure result 'JSONDecodables'
Storing out the type:
let savedType = Animal.Type
let result: [savedType] = doSomething() // Use of undeclared type savedType
Any suggestions to how to hint the compiler without specifying the concrete type?

Related

Reference to generic function in Swift

In Swift, you can create a reference to a function in the form of a closure. For example:
func simpleFunc(param: Int) {
}
let simpleFuncReference = simpleFunc(param:) // works just fine
But in one case, I have a function with a generic parameter like this:
func hardFunc<T: StringProtocol>(param: T) {
}
let hardFuncReference = hardFunc(param:) // "Generic parameter 'T' could not be inferred"
To try to remove that error, I attempted to explicitly specify the type, but immediately another error comes up.
func hardFunc<T: StringProtocol>(param: T) {
}
let hardFuncReference = hardFunc(param:) // "Cannot explicitly specialize a generic function"
Is there a way I can get a reference to hardFunc as a closure?
As you already guessed, you have to help type inference out a little:
func hardFunc<T: StringProtocol>(param: T) {
}
let hardFuncReference:(String) -> Void = hardFunc(param:)
Note that you do have to specify the particular type that you're specializing on, but in this case you do it by specifying the type of the variable you're assigning the closure to.
You can't keep it generic unless you're in a generic context specifying that it's generic on the same type. So this will work too
struct Foo<T: StringProtocol> {
let hardFuncReference:(T) -> Void = hardFunc(param:)
}

Ways to infer type to generic function

How can I infer a type to a generic function other than like this:
let a: MyType = genericFunction()
or these casts:
let a = MyType(genericFunction())
let a = genericFunction() as MyType
A conditional cast doesn’t infer the type:
let a = genericFunction() as? MyType
What else does?
UPDATE:
As Victor Pro assumed the function should return a generic type. It could look like:
func genericFunction<T>() -> T {
}
I assume your genericFunction() has a generic return type. Then, another way to infer the type is to pass it as an argument to the function: func genericFunction<T>(returnType: T.Type) -> T {...}. You can call it now via e.g. let val = genericFunction(String.self), whereby val is of type String.

I expected the system to report non protocol conformance, but it does not! Why?

I am using Xcode Version 11.3.1 (11C504)
I am trying to create a generic function in Swift that will reject its
parameter unless such a parameter is Optional.
In the following code, I was expecting the system to report errors in all calls to onlyCallableByAnOptable() made inside test(), because none of them provide an optional value as a parameter.
However, the system only reports non-protocol conformance if I remove the Optional extension that conforms to Optable!
Which to me, it means that the system is regarding any and all values as Optional, regardless!
Am I doing something wrong?
(By the way, the following code used to be working as expected in earlier versions of Swift. I just recently found out that it stopped working, for it was letting a non-Optional go through.)
protocol Optable {
func opt()
}
func onlyCallableByAnOptable<T>( _ value: T) -> T where T: Optable {
return value
}
// Comment the following line to get the errors
extension Optional: Optable { func opt() {} }
class TestOptable {
static func test()
{
let c = UIColor.blue
let s = "hi"
let i = Int(1)
if let o = onlyCallableByAnOptable(c) { print("color \(o)") }
//^ expected ERROR: Argument type 'UIColor' does not conform to expected type 'Optable'
if let o = onlyCallableByAnOptable(s) { print("string \(o)") }
//^ expected ERROR: Argument type 'String' does not conform to expected type 'Optable'
if let o = onlyCallableByAnOptable(i) { print("integer \(o)") }
//^ expected ERROR: Argument type 'Int' does not conform to expected type 'Optable'
}
}
Since you've made all Optionals conform to Optable and you are using the if let syntax to unwrap the result of the call to onlyCallableByAnOptable (which means the return type must be some kind of Optional, which means the parameter must also be that same type of Optional because both the parameter and the return type are of type T in your generic method), Swift is inferring the types being passed in as UIColor?, String?, and Int? (implicitly wrapping them in Optionals) instead of UIColor, String and Int.
I am the one who posted this question.
I was trying to create a generic function in Swift that would reject
its parameter unless such parameter is an Optional.
As #TylerTheCompiler pointed out, using my original implementation (in the question), Swift was inferring type T (used in onlyCallableByAnOptable()), based on the full context of the call, not solely on the type of the value provided as parameter to it, therefore inferring T to be an Optional.
For the sake of helping others who might be trying to achieve the same as I was, the following is my solution to the problem I had.
All calls to onlyCallableByAnOptable(...) now correctly yield errors due to non-protocol conformance.
Errors like: Argument type 'UIColor' does not conform to expected type 'Optable'
If anyone knows of a simpler solution, please do post it as an answer
to: How to create a generic function in Swift that will reject the given parameter unless it is an Optional?.
protocol Optable {
associatedtype OptableType
func optionalOptable() -> OptableType?
func opt()
}
func onlyCallableByAnOptable<T>( _ value: T) -> T.OptableType? where T: Optable {
return value.optionalOptable()
}
extension Optional: Optable {
typealias OptableType = Wrapped //: Wrapped is the type of the element, as defined in Optional
func opt() {}
func optionalOptable() -> OptableType? {
return self
}
}
class TestOptable {
static func test()
{
let c = UIColor.blue
let s = "hi"
let i = Int(1)
if let o = onlyCallableByAnOptable(c) { // ERROR, as was desired.
print("color \(o)")
}
if let o = onlyCallableByAnOptable(s) { // ERROR, as was desired.
print("string \(o)")
}
if let o = onlyCallableByAnOptable(i) { // ERROR, as was desired.
print("integer \(o)")
}
}
}

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

How do I call a generic Swift function when none of the arguments provides the generic type?

The following compiles in the Swift REPL:
var m: [String:AnyObject] = [:]
func f<T: AnyObject>(s: String) {
m[s] = T.self
}
However, if I naively try to invoke f(), thus:
let s: String = "foo"
class Foo {}
f<Foo>(s)
I get this error:
repl.swift:7:1: error: cannot explicitly specialize a generic function
f<Foo>(s)
^
repl.swift:7:2: note: while parsing this '<' as a type parameter bracket
f<Foo>(s)
^
If I try it without "explicitly specializing"...
f(s)
Swift decides I'm trying to do something even weirder, and I get:
repl.swift:7:1: error: cannot convert the expression's type 'String' to type '()'
f(s)
^~~~
Meanwhile, however, if I define a new function g() as follows:
func g<T: AnyObject>(s: String, t: T) {
m[s] = T.self
}
and pass in a dummy Foo instance:
g(s, Foo())
it works fine:
> m
$R0: [String : AnyObject] = {
[0] = {
key = "foo"
value = {
instance_type = {}
}
}
}
So is there a reason Swift lets me define f() in the first place? And once defined, is there any way to invoke it?
ETA: I'm aware it's also possible to define a function h<T: AnyObject>(s: String, t: T.Type) that takes the type explicitly. It's the fact that Swift allows me to define the implicit version that I find questionable.
Differently from other languages, you cannot explicitly specify the generic type with a syntax like this:
f<Foo>(s)
instead the actual type is inferred via a parameter or the return type. In your case you are not providing a way for type inference to figure out what T is. And sadly I'm not aware of any way to use that function.
My suggestion is to explicitly pass the type of T:
func f<T: AnyObject>(s: String, type: T.Type) {
m[s] = type
}
...
f(s, Foo.self)