Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write generic factory method in swift?

I am not sure how to, if it's possible to, write method that calls constructor of it's generic type inheriting from common known base class < T:Base > to create some instances of T without resorting to explicit factory function i.e. with all bells and whistles provided by type inference.

Example that works in playground:

// Let there be classes MyPod and Boomstick with common Base (not important)
class Base : Printable {
    let value : String; init(_ value : String) { self.value = "Base." + value }
    var description: String { return value }
}
class MyPod : Base {
    init(_ value: String) { super.init("MyPod." + value) }
}
class Boomstick : Base {
    init(_ value: String) { super.init("Boomstick." + value) }
}
// PROBLEM: do not know how to force call of Boomstick(n) instead of Base(n) in here
func createSome<T : Base>() -> T[] {
    var result = Array<T>()
    for n in 1...5 {
        result += T(toString(n))
    }
    return result
}
// This seems to be fine. 
// I was expecting call of createSome<Boomstick>() { ... result += Boomstick(n) ...
let objs : Boomstick[] = createSome() 
// Prints: Base.1, Base.2, ... not much wished Boomstick.1, Boomstick.2, ...
println(objs)

One obvious solution is to delegate creation to caller, but that seems clunky:

func createSome<T>(factory : (Int)->T) { ... }

Thank you.

PS: Isn't assignment of createSome()->Base[] to objs:Boomstick[] type safety violation?

like image 784
Adam Avatar asked Jun 21 '14 11:06

Adam


People also ask

How to use generics in Swift?

With the help of generics in Swift, we can write code that will work with different types of data. For example, func genericFunction<T>(data: T) {...} Here, we have created a generics function. This same function can be used to perform operations on integer data, string data, and so on. 2. Used with Collections

What is the return type of the static function of genericfactory?

You have the function parameters: the factory object that will be any object that conforms to GenericFactory, and the configuration that is anything that the Generic factory consider to be the necessary configuration. The return type of the factory static function is Output.

How does the generic factory work?

The factory will take a generic factory and the configuration to return the product of any possible factory. First you have the generic parameters inside angle brackets: Output, Input and a Factory that conforms to GenericFactory protocol.

How do you create a stack of objects in Swift?

Because it’s a generic type, Stack can be used to create a stack of any valid type in Swift, in a similar manner to Array and Dictionary. You create a new Stack instance by writing the type to be stored in the stack within angle brackets. For example, to create a new stack of strings, you write Stack<String> ():


1 Answers

Right now I don't have an answer about the why, but defining a protocol with the initializer only seems to work:

protocol A {
    init(_ value: String)
}

You implement this protocol in all classes as below

class Base : Printable, A {
    let value : String;
    init(_ value : String) { self.value = "Base." + value }
    var description: String { return value }
}

class MyPod : Base, A {
    init(_ value: String) { super.init("MyPod." + value) }
}

class Boomstick : Base, A {
    init(_ value: String) { super.init("Boomstick." + value) }
}

and use A rather than Base in your createSome() func

func createSome<T : A>() -> [T] {
    var result = Array<T>()
    for n in 1...5 {
        result += T(toString(n))
    }
    return result
}

Tested in playground:

let objs : [Boomstick] = createSome()
objs[0]

and it prints:

{value "Base.Boomstick.1"}

Also tried using MyPod and Base and it printed the expected results. Test it out and let me know if it works for you as well.

like image 112
Antonio Avatar answered Oct 12 '22 11:10

Antonio