0

I have the following code:

protocol User {
   var photo: Int { get }
}

protocol Relationship {
    associatedtype Member: User

    var first: Member { get }
    var second: Member { get } 
}

protocol Friend: User {
     var a: Int { get }
}

protocol Lover: User {
     var b: String { get }
}

protocol Friendship: Relationship 
   where Member: Friend {
     var c: String { get }
}

protocol Love: Relationship
   where Member: Lover {
     var d: String { get }
}

enum RelationshipRecord<F, L>: Relationship 
where F: Friendship, L: Love {

    case friendship(value: F)
    case love(value: L) 

    typealias Member = User

    var first: Member {
        switch self {
        case .friendship(let o): return o.first
        case .love(let o): return o.first
        }
    }

    var second: Member {
        switch self {
        case .friendship(let o): return o.second
        case .love(let o): return o.second
        }
    }
}

As a result of compilation I have the following error:

error: type 'RelationshipRecord' does not conform to protocol 'Relationship'

enum RelationshipRecord<F, L>: Relationship

and notes:

note: possibly intended match 'RelationshipRecord.Member' (aka 'User') does not conform to 'User'

typealias Member = User

,

note: protocol requires nested type 'Member'; do you want to add it?

associatedtype Member:

After problem investigation, I know that changing User from protocol to class make code compilable.

class User {
   var photo: Int { return 0 }
}

But it isn't that what I need.
Is it possible to save both: 1) User as protocol and 2) architecture from the example?
If it isn't, Why?

Valentyn Zakharenko
  • 2,710
  • 1
  • 21
  • 47
  • This is another version of "protocols do not conform to themselves." See https://stackoverflow.com/a/43408193/97337 (Particularly see Hamish's answer.) The simplest version of the problem is that if `User` included an `init` or other static requirement, it would be impossible to use it this way. – Rob Napier Jul 24 '19 at 12:50
  • Why are these protocols, however? Why wouldn't `User` be a struct? It feels like you're trying to treat a protocol as an abstract class, which is not the intent. (To help us help you design this, you should lay out what kinds of concrete implementations you see for `User`. Without knowing what kinds of concrete implementations are expected, you can't design the generics.) You may find this talk useful in understanding what protocols are for. https://www.youtube.com/watch?v=DXwJg0QTlZE&list=PLljEvxF6pJBBSQXDRnQvACukLJGybS17O&index=13&t=0s – Rob Napier Jul 24 '19 at 12:55

1 Answers1

1

You can introduce the 3rd generic parameter to your enum this way:

enum RelationshipRecord<F, L, U>: Relationship where F: Friendship, L: Love, F.Member == U, L.Member == U {

    case frienship(value: F)
    case love(value: L)

    var first: U {
        switch self {
        case .frienship(let o): return o.first
        case .love(let o): return o.first
        }
    }

    var second: U {
        switch self {
        case .frienship(let o): return o.second
        case .love(let o): return o.second
        }
    }
}
iWheelBuy
  • 5,470
  • 2
  • 37
  • 71