How to create an instance that satisfies the generic requirements

I have created the following code and everything works fine except the definition of TestDBAPI.

When I want to create a type that conforms to the DBAPIProtocol protocol, it is always impossible to generate a type instance that satisfies the generic constraints

Please, how can I define TestNoteFetcher to satisfy the protocol requirement of DBAPIProtocol.

ps: I hope the flexibility of generic definitions can be maintained in DBAPIProtocol

thanks

import Combine

// For Value

public enum WrappedID: Equatable, Identifiable, Sendable, Hashable {
    case string(String)
    case integer(Int)

    public var id: Self {
        self
    }
}

public protocol BaseValueProtocol: Equatable, Identifiable, Sendable {
    var id: WrappedID { get }
}

public struct Note: BaseValueProtocol {
    public var id: WrappedID
    public var index: Int

    public init(id: WrappedID, index: Int) {
        self.id = id
        self.index = index
    }
}

// For Object

public protocol ConvertibleValueObservableObject<Value>: ObservableObject, Equatable, Identifiable where ID == WrappedID {
    associatedtype Value: BaseValueProtocol
    func convertToValueType() -> Value
}

public final class TestNote: ConvertibleValueObservableObject {
    public static func == (lhs: TestNote, rhs: TestNote) -> Bool {
        true
    }

    public var id: WrappedID {
        .integer(1)
    }

    public func convertToValueType() -> Note {
        .init(id: .integer(1), index: 0)
    }
}

// For Fetcher

public protocol ObjectFetcherProtocol<Object,ConvertValue> {
    associatedtype ConvertValue: BaseValueProtocol
    associatedtype Object: ConvertibleValueObservableObject<ConvertValue>
    var stream: AsyncPublisher<AnyPublisher<[Object], Never>> { get }
}

public final class TestNoteFetcher: ObjectFetcherProtocol {
    public typealias ConvertValue = Note
    public typealias Object = TestNote

    public var stream: AsyncPublisher<AnyPublisher<[TestNote], Never>> {
        sender.eraseToAnyPublisher().values
    }

    public var sender: CurrentValueSubject<[TestNote], Never>
    public init(_ notes: [TestNote] = []) {
        sender = .init(notes)
    }
}

// For API

public protocol DBAPIProtocol {
    var notesFetcher: () async -> any ObjectFetcherProtocol<any ConvertibleValueObservableObject<Note>, Note> { get set }
}

// get error in here . Cannot convert value of type 'TestNoteFetcher.Object' (aka 'TestNote') to closure result type 'any ConvertibleValueObservableObject<Note>'

public final class TestDBAPI: DBAPIProtocol {
    public var notesFetcher: () async -> any ObjectFetcherProtocol<any ConvertibleValueObservableObject<Note>, Note> = {
        TestNoteFetcher([])
    }
}

The error tells you exactly what the problem is.

You specify a return type of any ObjectFetcherProtocol<any ConvertibleValueObservableObject<Note>, Note>, meaning the associated type Object must be any ConvertibleValueObservableObject<Note>. You are trying to return a value of type TestNoteFetcher, but TestNoteFetcher.Object is TestNote and not any ConvertibleValueObservableObject<Note>.

1 Like

Sometimes the answer is right in front of me, but I do turn a blind eye to it. Thanks for the heads up. I made a change to this part of the code and it works now.

public protocol ObjectFetcherProtocol<ConvertValue> {
    associatedtype ConvertValue: BaseValueProtocol
    var stream: AsyncPublisher<AnyPublisher<[any ConvertibleValueObservableObject<ConvertValue>], Never>> { get }
}

public final class TestNoteFetcher: ObjectFetcherProtocol {

    public var stream: AsyncPublisher<AnyPublisher<[any ConvertibleValueObservableObject<Note>], Never>> {
        sender.eraseToAnyPublisher().values
    }

    public var sender: CurrentValueSubject<[any ConvertibleValueObservableObject<Note>], Never>
    public init(_ notes: [any ConvertibleValueObservableObject<Note>] = []) {
        sender = .init(notes)
    }
}