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
}
EntityProtocolrequires avar someValueof protocol typeSomethingProtocolSomethingConcreteimplementsSomethingProtocoland thus is of typeSomethingProtocolConcreteClassimplementsEntityProtocoland thus needs avar someValueof 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 }
}
