6 Replies
      Latest reply on Jan 7, 2016 8:10 AM by davidlondono
      GoZoner Level 1 Level 1 (0 points)
        protocol Person : Hashable {
          var fullname : String { get set }
          
          typealias R : Relationship
          var relationships : Array<R> { get }
        }
        
        protocol Relationship : Hashable {
          typealias P : Person
          var source : P { get }
          var target : P { get }
        }
        

         

        The above causes a compiler crash; surely it is a known issue?  Is there a work-around?  Is the above a coding-style that is to be avoided (in a language like Swift)?

         

        [Apple Swift version 2.0 (swiftlang-700.0.52.2 clang-700.0.65)

        Target: x86_64-apple-darwin14.4.0]

        • Re: Mutually Recursive Protocols / Compiler Crash
          Dave Level 2 Level 2 (25 points)

          Don't know if there's a syntactically valid way to do it, but does it work if source and target are weak or unowned?

           

          Edit: I thought maybe the compiler was trying to save you from a reference cycle, but I tried it with both weak and unowned, and no difference. Splitting <Person> into two protocols compiles, though.

          protocol Person : Hashable {
              var fullname : String { get set }
          }
          protocol PersonInRelationship : Person {
              typealias R : Relationship
              var relationships : Array<R> { get }
          }
          protocol Relationship : Hashable {
              typealias P : Person
              var source : P { get }
              var target : P { get }
          }
          
          
          • Re: Mutually Recursive Protocols / Compiler Crash
            OOPer Level 7 Level 7 (4,315 points)

            Compiler should not crash and I don't know if this case matches any of the known issues. You should send a Bug Report.


            Is the above a coding-style that is to be avoided (in a language like Swift)?

            I'm afraid the answer for this question is Yes.

             

            When Swift applies a protocol as a type constraint, it needs to infer the actual types of the associated types.

            So, when you use Person protocol, Person.R needs to be inferred.

            And, any arbitrary type conforming to Relationship can be Person.R, Swift needs to infer Person.R.P,

            two types conforming to Person and Person.R.P may be different, so this makes an inifinite recursion, not mutual recursion:

            Person.R.P, Person.R.P.R, Person.R.P.R.P, ...

             

            You may already know, if you remove Hashable, you can write something like this:

            protocol Relationship {
                var source : Person { get }
                var target : Person { get }
            }
            protocol Person {
                var fullname : String { get set }
            
                var relationships: [Relationship] {get}
            }
            

            If you want to make all actual implementation of Person and Relationship to be Hashable, you can make derived protocols and use them:

            protocol PersonType: Person, Hashable {}
            protocol RelationshipType: Relationship, Hashable {}
            

             

            One more, you should consider if both type may be value types, when you define mutually dependent types.

              • Re: Mutually Recursive Protocols / Compiler Crash
                GoZoner Level 1 Level 1 (0 points)

                I asked specifically about 'coding style' because there is something about my modelling style that causes me to hit these issues _every_ time.

                 

                If I don't expose `var Relationship : Set<Relationship>` and instead add methods like `addFriend`, `mapFriends`, `mapRivals`, etc (all the different facets of a Relationship - or addRelationship:as:) then the problem is avoided - Relationship becomes an implementation detail of Person.  That is workable; maybe I learn something about modeling from that.

                 

                Regarding the 'infinite recursion', is there not something like a `where` clause on a `typealias`?

                 

                protocol Person : Hashable {
                  var fullname : String { get set }
                
                  typealias R : Relationship where R.P == Self
                  var relationships : Set<R> { get }
                }
                
                  • Re: Mutually Recursive Protocols / Compiler Crash
                    OOPer Level 7 Level 7 (4,315 points)

                    Having `where` constraint in `typealias` of protocols seems to be a possible extension for me, you'd better write a feature request.

                     

                    I'm not sure the feature make this case easier, but it can be a good tool to represent our idea more straightforward.

                    And maybe we need some more good tools to use Swift as a really Protocol Oriented Programming language.

                • Re: Mutually Recursive Protocols / Compiler Crash
                  GoZoner Level 1 Level 1 (0 points)

                  No longer crashes in: Apple Swift version 2.0 (700.0.57 700.0.72).  Issues a warning of 'Type may not reference itself as a requirement'.

                    • Re: Mutually Recursive Protocols / Compiler Crash
                      davidlondono Level 1 Level 1 (0 points)

                      there is a warning but not a solution

                      I want to use it for VIPER, and the type alias conclict is on the View, Presenter and Interactor

                       

                      
                      protocol ViewControllerProtocol: class {
                          typealias PresenterType:PresenterProtocol
                          var presenter:PresenterType! {get set}
                      }
                      protocol PresenterProtocol: class {
                          typealias InteractorType: InteractorProtocol
                          typealias ViewControllerType: ViewControllerProtocol
                      
                          weak var view: ViewControllerType! {get set}
                          var interactor: InteractorType! {get set}
                          init()
                      }
                      protocol InteractorProtocol:class {
                          typealias PresenterType: PresenterProtocol
                      
                          weak var presenter:PresenterType! {get set}
                          init()
                      }
                      

                       

                       

                      i get the "Type may not reference itself as a requirement" error so dont know how to do it

                       

                      if I erase the typealias type doesent work to use the Routing as generic and ad a func

                      
                       presenter.interactor = newInteract
                       loginPresenter.routing = self
                       loginPresenter.view = viewController