Is it possible to implement a protocol type var
with a concrete class which implements this protocol?
Does that sound confusing? Here is an example :-)
// A protocol requires some var. And an implementation of this class
protocol SomethingProtocol {
var something: String { get }
}
class SomethingConcrete: SomethingProtocol {
var something: String { "something" }
var someOther: String { "something else" }
}
// A protocol which requires someValue of protocol type SomethingProtocol
protocol EntityProtocol {
var someValue: SomethingProtocol { get }
}
// Implementation of EntityProtocol
class ConcreteEntiy: EntityProtocol {
// DOES NOT WORK:
// Implementing the var someValue of required typ SomethingProtocol
// using its implementation SomethingConcret
//
// Error: Type 'ConcretEntiy' does not conform to protocol 'EntityProtocol'
var someValue: SomethingConcrete = SomethingConcrete()
// DOES WORK:
// Implementation as SomethingProtocol as required by EntityProtocol
// but no access to others values of SomethingConcret
var someValue: SomethingProtocol = SomethingConcrete()
// Error: Value of type 'SomethingProtocol' has no member 'somethingElse'
let otherValue = someValue.somethingElse
}
EntityProtocol
requires avar someValue
of protocol typeSomethingProtocol
SomethingConcrete
implementsSomethingProtocol
and thus is of typeSomethingProtocol
ConcreteClass
implementsEntityProtocol
and thus needs avar someValue
of protocol typeSomethingProtocol
Why is it not possible to full fill the requirement of EntityProtocol
by providing a var someValue
of type SomethingConcrete
?
CodePudding user response:
You're requiring the class conforming to EntityProtocol
to have a property holding SomethingProtocol
, & not any object conforming to that protocol.
That's why generics exist, when using associatedtype
you're first implementation works because you're setting the type of someValue
to be whatever you say it is that conforms to SomethingProtocol
(i.e: SomethingConcret
). Hence it's not set like your attempt, it is inferred.
// A protocol requires some var. And an implementation of this class
protocol SomethingProtocol {
var something: String { get }
}
class SomethingConcret: SomethingProtocol {
var something: String { "something" }
var someOther: String { "something else" }
}
// A protocol which requires someValue conforming to the type SomethingProtocol
protocol EntityProtocol {
associatedtype SomeValue: SomethingProtocol
var someValue: SomeValue { get }
}
// Implementation of EntityProtocol
class ConcretEntiy: EntityProtocol {
// WORKS:
// Implementing the var someValue of required type SomethingProtocol
// using its implementation SomethingConcret
// has access to others values of SomethingConcret
var someValue: SomethingConcret = SomethingConcret()
// ALSO WORKS:
// Implementation as SomethingProtocol as required by EntityProtocol
// but no access to others values of SomethingConcret
var someValue: SomethingProtocol = SomethingConcret()
}
CodePudding user response:
- Syntax error where you wrote extra
=
:
var someOther: String { "something else" }
- You can assign a conformed concrete to an abstracted
var
:
var someValue: SomethingProtocol = SomethingConcret()
- You can not access concrete's property from an abstracted
var
. You may want to cast it first:
var otherValue: String? { (someValue as? SomethingConcret)?.someOther
Full working demo code (typos and syntax errors fixed)
protocol SomethingProtocol {
var something: String { get }
}
class SomethingConcrete: SomethingProtocol {
var something: String { "something" }
var someOther: String { "something else" }
}
protocol EntityProtocol {
var someValue: SomethingProtocol { get }
}
class ConcreteEntity: EntityProtocol {
var someValue: SomethingProtocol = SomethingConcrete()
var otherValue: String? { (someValue as? SomethingConcrete)?.someOther }
}