kas-kad
kas-kad

Reputation: 3764

Function that return either of two generics

I'm trying to implement either function, which accepts two generic container and return either of them:

func either<A,B>(a: Container<A>, b: Container<B>) -> ?either Container<A> or Container<B>? {
    // choose any of container
    return chosen
}

Looks like I need a protocol, that Container must conforms to, so that my either's return type should be of this protocol. Is this right solution?

protocol ContainerProtocol
struct Container<T>: ContainerProtocol

func either<A: ContainerProtocol, B:ContainerProtocol, C:ContainerProtocol>(a: A, b: B) -> C {
    // choose any of container
    return chosen
}

UPDATE

ok so I've implemented the EitherContainer enum and the final code is following:

struct Container<T>: Unique {
    typealias UnderlyingObject = T
    var object: UnderlyingObject
    var uniqueId: String
}

enum EitherContainer<A,B> {
    case a(container: Container<A>)
    case b(container: Container<B>)
}

func wrappedInput<A,B>(wra: Container<A>, wrb: Container<B>, paramClosure: (Container<A>, Container<B>) -> EitherContainer<A,B>) -> EitherContainer<A,B> {
    //do some work here
    return paramClosure(wra, wrb)
}

func rawInput<A, B>(a: A, b: B) -> Any {
    let wrappedA = Container(object: a, uniqueId: "a")
    let wrappedB = Container(object: b, uniqueId: "b")
    let wrappedRes = wrappedInput(wrappedA, wrb: wrappedB) {
        (a1: Container, a2: Container) -> EitherContainer<A,B> in
        // do some work here
        return EitherContainer.a(container: a1)
    }
    var rawRes: Any
    switch wrappedRes {
    case .a(let container):
        rawRes = container.object
    case .b(let container):
        rawRes = container.object
    }
    return rawRes
}

what bothers me now, is Any type, which shuts the compiler up, but for me looks like a weak crutch. Again same problem rawInput<A, B>(a: A, b: B) -> Any . rawInput should return either A or B, but I'm forced to use Any instead. Should I add another enum for raw options? Any thoughts?

Upvotes: 1

Views: 720

Answers (1)

molbdnilo
molbdnilo

Reputation: 66459

The traditional Either type looks like this:

enum Either<A, B>
{
    case Left(A)
    case Right(B)
}

and is more useful, as it's not limited to your Container type.
(Either is the "canonical" sum type.)

It would be used like this:

func wrappedInput<A, B> (
    a : Container<A>,
    b: Container<B>,
    paramClosure: (Container<A>, Container<B>) -> Either<Container<A>,Container<B>>
    ) -> Either<Container<A>, Container<B>>
{
    return Either.Left(a) // Dummy
}

func rawInput<A, B>(a: A, b: B) -> Either<A,B> {
    let wrappedA = Container(object: a, uniqueId: "a")
    let wrappedB = Container(object: b, uniqueId: "b")
    let wrappedRes = wrappedInput(wrappedA, b: wrappedB) {
        (a1: Container, a2: Container) -> Either<Container<A>, Container<B>> in
        // do some work here
        return Either.Left(a1)
    }

    switch wrappedRes {
    case .Left(let container):
        return Either.Left(container.object)
    case .Right(let container):
        return Either.Right(container.object)
    }
}

Upvotes: 3

Related Questions