Pass class as param into function for comparison in swift? - swift

I want to write something like this:
func someFunc<T, U>(t1: T.Type, t2: U.Type) {
let k = someArray.first {$0 is t1}
...
}
It writes:
Use of undeclared type 't1'
Objective-C has Class and has class comparison but it seems swift hasn't it properly implemented.

Since this is a generic function you can use the generic type T instead of t1.
let k = someArray.first {$0 is T}

Related

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.

Generic of Generics ? class A<T<U>>?

Can I somehow force the generic type to have a generic type ?
I want to have some functions, that have as a parameter type U, so how can I do that ?
Code:
class TableViewViewModel<T<U>> {
typealias SectionDataType = T
typealias RowDataType = U
var sections = [SectionDataType<RowDataType>]()
}
Try declaring a protocol SectionDataType that requires an associated type. This means that any conforming type (like Section below) must implement a typealias. Then, in TableViewViewModel you can access the type which you were calling U through that typealias.
protocol SectionDataType {
associatedtype RowDataType
}
struct Section<U>: SectionDataType {
typealias RowDataType = U
}
class TableViewViewModel<T: SectionDataType> {
typealias RowDataType = T.RowDataType
var sections = [T]()
}
All you have to do with a generic, is declare the types (what you are doing with the angle brackets). After that, it's syntax-as-usual. I'm not sure exactly what you want to do, so I'll just post an example. The following function declares three generic types (T, U, Z), takes a type U and a function as parameters, the function itself takes a value of type U and returns a value of type T. All of this returns a value of type Z. (This is a pretty useless func as-is, but an example of how to use generics in a complex fashion):
func myFunc<U,T,Z>(curry : (U) -> T, value : U) -> Z {
return curry(value) as! Z
}

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

Generic function taking a type name in Swift

In C#, it's possible to call a generic method by specifying the type:
public T f<T>()
{
return something as T
}
var x = f<string>()
Swift doesn't allow you to specialize a generic method when calling it. The compiler wants to rely on type inference, so this is not possible:
func f<T>() -> T? {
return something as T?
}
let x = f<String>() // not allowed in Swift
What I need is a way to pass a type to a function and that function returning an object of that type, using generics
This works, but it's not a good fit for what I want to do:
let x = f() as String?
EDIT (CLARIFICATION)
I've probably not been very clear about what the question actually is, it's all about a simpler syntax for calling a function that returns a given type (any type).
As a simple example, let's say you have an array of Any and you create a function that returns the first element of a given type:
// returns the first element in the array of that type
func findFirst<T>(array: [Any]) -> T? {
return array.filter() { $0 is T }.first as? T
}
You can call this function like this:
let array = [something,something,something,...]
let x = findFirst(array) as String?
That's pretty simple, but what if the type returned is some protocol with a method and you want to call the method on the returned object:
(findFirst(array) as MyProtocol?)?.SomeMethodInMyProtocol()
(findFirst(array) as OtherProtocol?)?.SomeMethodInOtherProtocol()
That syntax is just awkward. In C# (which is just as strongly typed as Swift), you can do this:
findFirst<MyProtocol>(array).SomeMethodInMyProtocol();
Sadly, that's not possible in Swift.
So the question is: is there a way to accomplish this with a cleaner (less awkward) syntax.
Unfortunately, you cannot explicitly define the type of a generic function (by using the <...> syntax on it). However, you can provide a generic metatype (T.Type) as an argument to the function in order to allow Swift to infer the generic type of the function, as Roman has said.
For your specific example, you'll want your function to look something like this:
func findFirst<T>(in array: [Any], ofType _: T.Type) -> T? {
return array.lazy.compactMap { $0 as? T }.first
}
Here we're using compactMap(_:) in order to get a sequence of elements that were successfully cast to T, and then first to get the first element of that sequence. We're also using lazy so that we can stop evaluating elements after finding the first.
Example usage:
protocol SomeProtocol {
func doSomething()
}
protocol AnotherProtocol {
func somethingElse()
}
extension String : SomeProtocol {
func doSomething() {
print("success:", self)
}
}
let a: [Any] = [5, "str", 6.7]
// Outputs "success: str", as the second element is castable to SomeProtocol.
findFirst(in: a, ofType: SomeProtocol.self)?.doSomething()
// Doesn't output anything, as none of the elements conform to AnotherProtocol.
findFirst(in: a, ofType: AnotherProtocol.self)?.somethingElse()
Note that you have to use .self in order to refer to the metatype of a specific type (in this case, SomeProtocol). Perhaps not a slick as the syntax you were aiming for, but I think it's about as good as you're going to get.
Although it's worth noting in this case that the function would be better placed in an extension of Sequence:
extension Sequence {
func first<T>(ofType _: T.Type) -> T? {
// Unfortunately we can't easily use lazy.compactMap { $0 as? T }.first
// here, as LazyMapSequence doesn't have a 'first' property (we'd have to
// get the iterator and call next(), but at that point we might as well
// do a for loop)
for element in self {
if let element = element as? T {
return element
}
}
return nil
}
}
let a: [Any] = [5, "str", 6.7]
print(a.first(ofType: String.self) as Any) // Optional("str")
What you probably need to do is create a protocol that looks something like this:
protocol SomeProtocol {
init()
func someProtocolMethod()
}
And then add T.Type as a parameter in your method:
func f<T: SomeProtocol>(t: T.Type) -> T {
return T()
}
Then assuming you have a type that conforms to SomeProtocol like this:
struct MyType: SomeProtocol {
init() { }
func someProtocolMethod() { }
}
You can then call your function like this:
f(MyType.self).someProtocolMethod()
Like others have noted, this seems like a convoluted way to do what you want. If you know the type, for example, you could just write:
MyType().someProtocolMethod()
There is no need for f.

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)