Protocols with associated type and factory pattern?









up vote
2
down vote

favorite












My data access layer consists of a generic Repository protocol



protocol Repository 
associatedtype T
func getAll() -> Promise<[T]>



and its concrete implementation:



class FirebaseRepository<T: Model>: Repository 
func getAll() -> Promise<[T]>
fatalError()




Basically, Repository can be RestRepository, FirebaseRepository, PlistRepositry etc. Repository is used by the business logic:



/// My business logic
class ModelService<T: Repository>
private let repository: T

public init(repository: T)
self.repository = repository




The problem comes when I'm trying to apply a factory pattern to a repository. Here's what I came in first:



/// Returns a concrete Repository implementation
class RepositoryFactory
func makeRepository<T: Model>(type: T.Type) -> Repository
return FirebaseRepository<T>()




and this definitely gets a compiler error:



Protocol 'Repository' can only be used as a generic constraint because it has Self or associated type requirements


The only viable option I came to is this:



func makeRepository<T: Model>(type: T.Type, U: Repository) -> U 
return FirebaseRepository<T>() as! U



but as you understand, the force optional unwrapping is not acceptable in the production code.



How to make protocols with associated types work with factory design pattern?










share|improve this question

























    up vote
    2
    down vote

    favorite












    My data access layer consists of a generic Repository protocol



    protocol Repository 
    associatedtype T
    func getAll() -> Promise<[T]>



    and its concrete implementation:



    class FirebaseRepository<T: Model>: Repository 
    func getAll() -> Promise<[T]>
    fatalError()




    Basically, Repository can be RestRepository, FirebaseRepository, PlistRepositry etc. Repository is used by the business logic:



    /// My business logic
    class ModelService<T: Repository>
    private let repository: T

    public init(repository: T)
    self.repository = repository




    The problem comes when I'm trying to apply a factory pattern to a repository. Here's what I came in first:



    /// Returns a concrete Repository implementation
    class RepositoryFactory
    func makeRepository<T: Model>(type: T.Type) -> Repository
    return FirebaseRepository<T>()




    and this definitely gets a compiler error:



    Protocol 'Repository' can only be used as a generic constraint because it has Self or associated type requirements


    The only viable option I came to is this:



    func makeRepository<T: Model>(type: T.Type, U: Repository) -> U 
    return FirebaseRepository<T>() as! U



    but as you understand, the force optional unwrapping is not acceptable in the production code.



    How to make protocols with associated types work with factory design pattern?










    share|improve this question























      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      My data access layer consists of a generic Repository protocol



      protocol Repository 
      associatedtype T
      func getAll() -> Promise<[T]>



      and its concrete implementation:



      class FirebaseRepository<T: Model>: Repository 
      func getAll() -> Promise<[T]>
      fatalError()




      Basically, Repository can be RestRepository, FirebaseRepository, PlistRepositry etc. Repository is used by the business logic:



      /// My business logic
      class ModelService<T: Repository>
      private let repository: T

      public init(repository: T)
      self.repository = repository




      The problem comes when I'm trying to apply a factory pattern to a repository. Here's what I came in first:



      /// Returns a concrete Repository implementation
      class RepositoryFactory
      func makeRepository<T: Model>(type: T.Type) -> Repository
      return FirebaseRepository<T>()




      and this definitely gets a compiler error:



      Protocol 'Repository' can only be used as a generic constraint because it has Self or associated type requirements


      The only viable option I came to is this:



      func makeRepository<T: Model>(type: T.Type, U: Repository) -> U 
      return FirebaseRepository<T>() as! U



      but as you understand, the force optional unwrapping is not acceptable in the production code.



      How to make protocols with associated types work with factory design pattern?










      share|improve this question













      My data access layer consists of a generic Repository protocol



      protocol Repository 
      associatedtype T
      func getAll() -> Promise<[T]>



      and its concrete implementation:



      class FirebaseRepository<T: Model>: Repository 
      func getAll() -> Promise<[T]>
      fatalError()




      Basically, Repository can be RestRepository, FirebaseRepository, PlistRepositry etc. Repository is used by the business logic:



      /// My business logic
      class ModelService<T: Repository>
      private let repository: T

      public init(repository: T)
      self.repository = repository




      The problem comes when I'm trying to apply a factory pattern to a repository. Here's what I came in first:



      /// Returns a concrete Repository implementation
      class RepositoryFactory
      func makeRepository<T: Model>(type: T.Type) -> Repository
      return FirebaseRepository<T>()




      and this definitely gets a compiler error:



      Protocol 'Repository' can only be used as a generic constraint because it has Self or associated type requirements


      The only viable option I came to is this:



      func makeRepository<T: Model>(type: T.Type, U: Repository) -> U 
      return FirebaseRepository<T>() as! U



      but as you understand, the force optional unwrapping is not acceptable in the production code.



      How to make protocols with associated types work with factory design pattern?







      swift generics design-patterns swift-protocols






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 11 at 13:38









      Andrey Gordeev

      15.2k662100




      15.2k662100






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          You can use Type erasure. Here is an example:



          protocol CustomProtocol 
          associatedtype AssociatedType
          func foo(argument: AssociatedType)
          func bar() -> AssociatedType



          If you want to use CustomProtocol directly, you will receive your error:



          let array = [CustomProtocol]()



          Protocol 'CustomProtocol' can only be used as a generic constraint because it has Self or associated type requirements




          So you can make the same trick, as Swift does with their sequences:



          public struct AnyCustomProtocol<T>: CustomProtocol 
          func bar() -> T
          fatalError("Needs implementation")

          func foo(argument: T)




          let array = [AnyCustomProtocol<Any>]() // works fine


          Your problem solution in this case will look somehow like this:



           class Promise<T> 



          protocol Model



          protocol Repository
          associatedtype T
          func getAll() -> Promise<[T]>


          class FirebaseRepository<T: Model>: AnyRepository<T>
          override func getAll() -> Promise<[T]>
          fatalError()



          class AnyRepository<T>: Repository
          func getAll() -> Promise<[T]>
          fatalError()




          class RepositoryFactory
          func makeRepository<T: Model>(type: T.Type) -> AnyRepository<T>
          return FirebaseRepository<T>()




          __



          For further reading you can check this and Official docs on Generics






          share|improve this answer






















          • Thank you very much for your reply. The approach you've suggested works good, though I'd expect more clear solution. AnyRepository has to have method stubs, which doesn't look clean. I suppose it's related to Swift's lacking of expressiveness. Abstract class sounds a better fit for solving this problem, but we don't have such in Swift yet :-/
            – Andrey Gordeev
            Nov 11 at 15:03






          • 1




            @AndreyGordeev, yes. But this is the most "Correct" solution of your problem, IMO. There is a proposal for abstract classes and methods in Swift. So let's just wait :)
            – fewlinesofcode
            Nov 11 at 15:07










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53249303%2fprotocols-with-associated-type-and-factory-pattern%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          1
          down vote



          accepted










          You can use Type erasure. Here is an example:



          protocol CustomProtocol 
          associatedtype AssociatedType
          func foo(argument: AssociatedType)
          func bar() -> AssociatedType



          If you want to use CustomProtocol directly, you will receive your error:



          let array = [CustomProtocol]()



          Protocol 'CustomProtocol' can only be used as a generic constraint because it has Self or associated type requirements




          So you can make the same trick, as Swift does with their sequences:



          public struct AnyCustomProtocol<T>: CustomProtocol 
          func bar() -> T
          fatalError("Needs implementation")

          func foo(argument: T)




          let array = [AnyCustomProtocol<Any>]() // works fine


          Your problem solution in this case will look somehow like this:



           class Promise<T> 



          protocol Model



          protocol Repository
          associatedtype T
          func getAll() -> Promise<[T]>


          class FirebaseRepository<T: Model>: AnyRepository<T>
          override func getAll() -> Promise<[T]>
          fatalError()



          class AnyRepository<T>: Repository
          func getAll() -> Promise<[T]>
          fatalError()




          class RepositoryFactory
          func makeRepository<T: Model>(type: T.Type) -> AnyRepository<T>
          return FirebaseRepository<T>()




          __



          For further reading you can check this and Official docs on Generics






          share|improve this answer






















          • Thank you very much for your reply. The approach you've suggested works good, though I'd expect more clear solution. AnyRepository has to have method stubs, which doesn't look clean. I suppose it's related to Swift's lacking of expressiveness. Abstract class sounds a better fit for solving this problem, but we don't have such in Swift yet :-/
            – Andrey Gordeev
            Nov 11 at 15:03






          • 1




            @AndreyGordeev, yes. But this is the most "Correct" solution of your problem, IMO. There is a proposal for abstract classes and methods in Swift. So let's just wait :)
            – fewlinesofcode
            Nov 11 at 15:07














          up vote
          1
          down vote



          accepted










          You can use Type erasure. Here is an example:



          protocol CustomProtocol 
          associatedtype AssociatedType
          func foo(argument: AssociatedType)
          func bar() -> AssociatedType



          If you want to use CustomProtocol directly, you will receive your error:



          let array = [CustomProtocol]()



          Protocol 'CustomProtocol' can only be used as a generic constraint because it has Self or associated type requirements




          So you can make the same trick, as Swift does with their sequences:



          public struct AnyCustomProtocol<T>: CustomProtocol 
          func bar() -> T
          fatalError("Needs implementation")

          func foo(argument: T)




          let array = [AnyCustomProtocol<Any>]() // works fine


          Your problem solution in this case will look somehow like this:



           class Promise<T> 



          protocol Model



          protocol Repository
          associatedtype T
          func getAll() -> Promise<[T]>


          class FirebaseRepository<T: Model>: AnyRepository<T>
          override func getAll() -> Promise<[T]>
          fatalError()



          class AnyRepository<T>: Repository
          func getAll() -> Promise<[T]>
          fatalError()




          class RepositoryFactory
          func makeRepository<T: Model>(type: T.Type) -> AnyRepository<T>
          return FirebaseRepository<T>()




          __



          For further reading you can check this and Official docs on Generics






          share|improve this answer






















          • Thank you very much for your reply. The approach you've suggested works good, though I'd expect more clear solution. AnyRepository has to have method stubs, which doesn't look clean. I suppose it's related to Swift's lacking of expressiveness. Abstract class sounds a better fit for solving this problem, but we don't have such in Swift yet :-/
            – Andrey Gordeev
            Nov 11 at 15:03






          • 1




            @AndreyGordeev, yes. But this is the most "Correct" solution of your problem, IMO. There is a proposal for abstract classes and methods in Swift. So let's just wait :)
            – fewlinesofcode
            Nov 11 at 15:07












          up vote
          1
          down vote



          accepted







          up vote
          1
          down vote



          accepted






          You can use Type erasure. Here is an example:



          protocol CustomProtocol 
          associatedtype AssociatedType
          func foo(argument: AssociatedType)
          func bar() -> AssociatedType



          If you want to use CustomProtocol directly, you will receive your error:



          let array = [CustomProtocol]()



          Protocol 'CustomProtocol' can only be used as a generic constraint because it has Self or associated type requirements




          So you can make the same trick, as Swift does with their sequences:



          public struct AnyCustomProtocol<T>: CustomProtocol 
          func bar() -> T
          fatalError("Needs implementation")

          func foo(argument: T)




          let array = [AnyCustomProtocol<Any>]() // works fine


          Your problem solution in this case will look somehow like this:



           class Promise<T> 



          protocol Model



          protocol Repository
          associatedtype T
          func getAll() -> Promise<[T]>


          class FirebaseRepository<T: Model>: AnyRepository<T>
          override func getAll() -> Promise<[T]>
          fatalError()



          class AnyRepository<T>: Repository
          func getAll() -> Promise<[T]>
          fatalError()




          class RepositoryFactory
          func makeRepository<T: Model>(type: T.Type) -> AnyRepository<T>
          return FirebaseRepository<T>()




          __



          For further reading you can check this and Official docs on Generics






          share|improve this answer














          You can use Type erasure. Here is an example:



          protocol CustomProtocol 
          associatedtype AssociatedType
          func foo(argument: AssociatedType)
          func bar() -> AssociatedType



          If you want to use CustomProtocol directly, you will receive your error:



          let array = [CustomProtocol]()



          Protocol 'CustomProtocol' can only be used as a generic constraint because it has Self or associated type requirements




          So you can make the same trick, as Swift does with their sequences:



          public struct AnyCustomProtocol<T>: CustomProtocol 
          func bar() -> T
          fatalError("Needs implementation")

          func foo(argument: T)




          let array = [AnyCustomProtocol<Any>]() // works fine


          Your problem solution in this case will look somehow like this:



           class Promise<T> 



          protocol Model



          protocol Repository
          associatedtype T
          func getAll() -> Promise<[T]>


          class FirebaseRepository<T: Model>: AnyRepository<T>
          override func getAll() -> Promise<[T]>
          fatalError()



          class AnyRepository<T>: Repository
          func getAll() -> Promise<[T]>
          fatalError()




          class RepositoryFactory
          func makeRepository<T: Model>(type: T.Type) -> AnyRepository<T>
          return FirebaseRepository<T>()




          __



          For further reading you can check this and Official docs on Generics







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 11 at 14:23

























          answered Nov 11 at 14:11









          fewlinesofcode

          1,900515




          1,900515











          • Thank you very much for your reply. The approach you've suggested works good, though I'd expect more clear solution. AnyRepository has to have method stubs, which doesn't look clean. I suppose it's related to Swift's lacking of expressiveness. Abstract class sounds a better fit for solving this problem, but we don't have such in Swift yet :-/
            – Andrey Gordeev
            Nov 11 at 15:03






          • 1




            @AndreyGordeev, yes. But this is the most "Correct" solution of your problem, IMO. There is a proposal for abstract classes and methods in Swift. So let's just wait :)
            – fewlinesofcode
            Nov 11 at 15:07
















          • Thank you very much for your reply. The approach you've suggested works good, though I'd expect more clear solution. AnyRepository has to have method stubs, which doesn't look clean. I suppose it's related to Swift's lacking of expressiveness. Abstract class sounds a better fit for solving this problem, but we don't have such in Swift yet :-/
            – Andrey Gordeev
            Nov 11 at 15:03






          • 1




            @AndreyGordeev, yes. But this is the most "Correct" solution of your problem, IMO. There is a proposal for abstract classes and methods in Swift. So let's just wait :)
            – fewlinesofcode
            Nov 11 at 15:07















          Thank you very much for your reply. The approach you've suggested works good, though I'd expect more clear solution. AnyRepository has to have method stubs, which doesn't look clean. I suppose it's related to Swift's lacking of expressiveness. Abstract class sounds a better fit for solving this problem, but we don't have such in Swift yet :-/
          – Andrey Gordeev
          Nov 11 at 15:03




          Thank you very much for your reply. The approach you've suggested works good, though I'd expect more clear solution. AnyRepository has to have method stubs, which doesn't look clean. I suppose it's related to Swift's lacking of expressiveness. Abstract class sounds a better fit for solving this problem, but we don't have such in Swift yet :-/
          – Andrey Gordeev
          Nov 11 at 15:03




          1




          1




          @AndreyGordeev, yes. But this is the most "Correct" solution of your problem, IMO. There is a proposal for abstract classes and methods in Swift. So let's just wait :)
          – fewlinesofcode
          Nov 11 at 15:07




          @AndreyGordeev, yes. But this is the most "Correct" solution of your problem, IMO. There is a proposal for abstract classes and methods in Swift. So let's just wait :)
          – fewlinesofcode
          Nov 11 at 15:07

















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53249303%2fprotocols-with-associated-type-and-factory-pattern%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          Barbados

          How to read a connectionString WITH PROVIDER in .NET Core?

          Node.js Script on GitHub Pages or Amazon S3