Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I assign a default type to generic type T in Swift?

Tags:

generics

swift

I have a generic class that I want to be able to use with a default type. Right now I can initialize it with any type, but I have to be explicit.

//Initialize with a type MyManager<MyCustomerObject>()  // Initialize with NSObject (what I want to be my default type) MyManager<NSObject>()  // This doesn't work, but I want this kind of functionality class MyManager<T = NSObject> {}  // So I can create my manager like so and it inserts the default type as NSObject MyManager() //Or MyManager<>() 

Is this possible in Swift?

like image 846
teradyl Avatar asked Feb 03 '17 01:02

teradyl


People also ask

What is T type Swift?

The placeholder type T is used in the function declaration. It tells Swift that this function can find any item in any array, as long as the foundItem and items in the array are of the same type. This makes sense — you want to look for a T value in an array of T values.

What is difference between generic and any Swift?

Generics and Any are often used for similar purposes, yet they behave very differently. In languages without generics, you typically use a combination of Any and runtime programming, whereas generics are statically checked at compile time.

Why would you use generics in Swift?

Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.


2 Answers

There's no support for default generic arguments, but you can fake it by defining the default init() on a type-constrained extension, in which case the compiler will be smart enough to use that type. E.g.:

class MyManager<T> {     let instance: T      init(instance: T) {         self.instance = instance     } }  extension MyManager where T == NSObject {     convenience init() {         self.init(instance: NSObject())     } } 

And now you can initialize the type with no argument and it will default to MyManager<NSObject>:

let mm1 = MyManager(instance: "Foo") // MyManager<String> let mm2 = MyManager(instance: 1) // MyManager<Int> let mm3 = MyManager() // MyManager<NSObject> 

SwiftUI uses this technique quite a lot.

like image 192
marcprux Avatar answered Oct 19 '22 21:10

marcprux


No, this currently isn't possible – although it is a part of the Generics Manifesto, so might be something that the Swift team will consider for a future version of the language.

Default generic arguments

Generic parameters could be given the ability to provide default arguments, which would be used in cases where the type argument is not specified and type inference could not determine the type argument. For example:

public final class Promise<Value, Reason=Error> { ... }  func getRandomPromise() -> Promise<Int, Error> { ... }  var p1: Promise<Int> = ...  var p2: Promise<Int, Error> = p1     // okay: p1 and p2 have the same type Promise<Int, Error> var p3: Promise = getRandomPromise() // p3 has type Promise<Int, Error> due to type inference 

In the meantime however, a somewhat unsatisfactory compromise would be the use of a typealias:

class MyManager<T> {}  typealias MyManagerDefault = MyManager<NSObject>  let defaultManager = MyManagerDefault() 

Not nearly as slick as just being able to say MyManager(), but it does show up next to MyManager in auto-complete, which is pretty handy.

like image 23
Hamish Avatar answered Oct 19 '22 21:10

Hamish