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?
swift generics design-patterns swift-protocols
add a comment |
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?
swift generics design-patterns swift-protocols
add a comment |
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?
swift generics design-patterns swift-protocols
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
swift generics design-patterns swift-protocols
asked Nov 11 at 13:38
Andrey Gordeev
15.2k662100
15.2k662100
add a comment |
add a comment |
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
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
add a comment |
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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