简体   繁体   中英

“Never” Type as Default Type for Multi-Generic Initialization

Problem

My goal is to somehow initialize a generic object similar to this:

struct SomeStruct<A, B> where A: View, B: View {
    let a: A?
    let b: B?
    
    init(a: A? = nil, b: B? = nil) {
        self.a = a
        self.b = b
    }
}

let someStruct: SomeStruct = .init(a: Color.red)

However, this snippet throws an error:

Generic Parameter 'B' Couldn't Be Inferred

Alternative #1: Diamond Notation

One alternative would be specifying Never type in a diamond notation:

let someStruct: SomeStruct<Color, Never> = .init(a: Color.red)

But this is a clunky solution as I don't want to pass types explicitly.

Alternative #2: Constrained Initializers

Another wordy alternative is writing custom initializers, omitting each type by specifying Never type:

struct SomeStruct<A, B> where A: View, B: View {
    let a: A?
    let b: B?
}

extension SomeStruct where A == Never {
    init(b: B) {
        self.a = nil
        self.b = b
    }
}

extension SomeStruct where B == Never {
    init(a: A) {
        self.a = a
        self.b = nil
    }
}

extension SomeStruct where A == Never, B == Never {
    init() {
        self.a = nil
        self.b = nil
    }
}

let someStruct: SomeStruct = .init(a: Color.red)

But as you can see, this requires a lot of repetitive code. So if I have an object of 10 generic types, this can become a mess.

Question

In short, I am looking for a way to retain a simple initializer, as shown in Problem section. Is there a way to provide a default type to a parameter ( Never ), as you would usually provide a default value to that parameter?.

This is not a solution, but rather Combine patterns reuse (as done by Apple SDK itself)...

Instead of

let someStruct: SomeStruct<Color, Never> =.init(a: Color.red)

I would propose to use

let someStruct = SomeStruct<Color, Never>(a: Color.red)

as this is widely used notation by Apple itself, like AnySubscriber<Color, Never> , AnyPublisher<Color, Never> , etc.

let subject = CurrentValueSubject<CGFloat, Never>(0)  // exactly your case

Note: for 10 types look at ViewBuilder

Is there a way to provide a default type to a parameter (Never), as you would usually provide a default value to that parameter?

No. But everybody wants it (I asked them), and although there has been activity on the Swift forum about it, it hasn't come to pass yet.

Example thread: https://forums.swift.org/t/draft-allow-default-value-for-parameters-in-generic-clause/11200

So if I have an object of 10 generic types, this can become a mess.

Aye, this is the state of things. Your problem, and lack of variadics , are the big ones.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM