Roman Podymov
Roman Podymov

Reputation: 4521

How to create extension for a generic structure that will be available only for Optional generic parameters in Swift 4.1?

I have the following structure in my iOS application:

struct MyStruct<T> {

    var property1: T
    var property2: T

    init(property1: T, property2: T) {
        self.property1 = property1
        self.property2 = property2
    }

    init(allPropertiesWith value: T) {
        self.property1 = value
        self.property2 = value
    }
}

I also have 2 classes that don't have a common ancestor:

class A { }
class B { }

In my application I have instances of MyStruct<A>, MyStruct<B>, MyStruct<A?>, MyStruct<B?> and I use them in these functions:

func f1(myStrurct: MyStruct<A?>) { }

func f2(myStrurct: MyStruct<A>) { }

func g2() {
    f1(myStrurct: MyStruct<A?>(property2: A()))
} 
/* I also have the same functions for MyStruct<B> and MyStruct<B?> */

I cannot modify f1, f2 and g2. That's why I created 2 extensions to make initialisation of MyStruct<T> easier:

extension MyStruct where T == A? {

    init(property1: T) {
        self.property1 = property1
        self.property2 = nil
    }

    init(property2: T) {
        self.property1 = nil
        self.property2 = property2
    }
}

extension MyStruct where T == B? {

    init(property1: T) {
        self.property1 = property1
        self.property2 = nil
    }

    init(property2: T) {
        self.property1 = nil
        self.property2 = property2
    }
}

As you can see these extensions are almost the same. Is it possible to refactor it with only 1 extension?

Upvotes: 0

Views: 531

Answers (3)

Roman Podymov
Roman Podymov

Reputation: 4521

In the answer provided by Rakesha Shastri I found out that I can use protocol to refactor my code. However to be able to use this solution I need to rewrite other parts of my application. I tried to add the solution by Rakesha Shastri to my application and compile it with Swift 3, Swift 4 or Swift 4.2 (all Swift versions available in Xcode 10.0), but every time I received a compiler error. It means that currently there are no ways how to solve the problem that I described in this question.

Upvotes: 1

Rakesha Shastri
Rakesha Shastri

Reputation: 11242

You can make both A and B (or whichever class needs it) conform to a dummy protocol and check that for T.

protocol MyStructProtocol {

}

class A: MyStructProtocol { }
class B: MyStructProtocol { }

extension MyStruct where T == MyStructProtocol? {
    init(property1: T) {
        self.property1 = property1
        self.property2 = nil
    }

    init(property2: T) {
        self.property1 = nil
        self.property2 = property2
    }
}

Upvotes: 1

Yusuf Ak
Yusuf Ak

Reputation: 781

You don't have to extend anything to create such an easier constructor. Check out the modified version of your struct definition below:

struct MyStruct<T> {

    var property1: T?
    var property2: T?

    init(property1: T? = nil, property2: T? = nil) {
        if T.self == String.self {
            self.property1 = property1
            self.property2 = nil
        }
        else if T.self == Int.self {
            self.property1 = nil
            self.property2 = property2
        }
    }

    init(allPropertiesWith value: T) {
        self.property1 = value
        self.property2 = value
    }
}

Then you can use initialize them as you wish with following lines.

MyStruct<String>(property2: "sadsad")
MyStruct<Int>(property1: 23)

Upvotes: 0

Related Questions