Thanks for trying Adrian but, no it doesn't help.
Here's the complete playground:
protocol Copyable
{
init(other: Self)
func copy() -> Self
}
extension Copyable
{
func copy() -> Self
{
return type(of: self).init(other: self)
}
}
protocol DefaultValueProvider
{
init()
}
extension Int : DefaultValueProvider { }
extension String : DefaultValueProvider { }
protocol PropertyProtocol
{
func getValue<valueType : DefaultValueProvider & Equatable>() throws -> valueType
func setValue<valueType : DefaultValueProvider & Equatable>(_ value: valueType) throws
func copy() -> PropertyProtocol
}
final class Property<valueT : DefaultValueProvider & Equatable> : Copyable
{
var value = valueT()
init() { }
required convenience init(other: Property)
{
self.init()
value = other.value
}
}
extension Property where valueT : Copyable
{
convenience init(other: Property)
{
self.init()
value = other.value.copy()
}
func copy() -> Property
{
return .init(other: self)
}
}
extension Property : PropertyProtocol
{
public enum Error : Swift.Error
{
case invalidPropertyType
}
public func getValue<valueType>() throws -> valueType where valueType : DefaultValueProvider & Equatable
{
guard let value = value as? valueType else
{
throw Error.invalidPropertyType
}
return value
}
public func setValue<valueType>(_ value: valueType) throws where valueType : DefaultValueProvider & Equatable
{
guard let newValue = value as? valueT else
{
throw Error.invalidPropertyType
}
self.value = newValue
}
public func copy() -> PropertyProtocol
{
return Property(other: self)
}
}
class Thing : DefaultValueProvider, Equatable, Copyable
{
public static func == (lhs: Thing, rhs: Thing) -> Bool
{
return lhs.value == rhs.value
}
public var value: Int
public required convenience init()
{
self.init(value: 0)
}
public init(value: Int)
{
self.value = value
}
public required convenience init(other: Thing)
{
self.init()
value = other.value
}
}
let stringProperty: PropertyProtocol = Property<String>()
let copyStringProperty = (stringProperty).copy()
try stringProperty.setValue("Joanna")
let stringValue: String = try stringProperty.getValue()
print(stringValue)
let copyStringValue: String = try copyStringProperty.getValue()
print(copyStringValue)
let thingProperty: PropertyProtocol = Property<Thing>()
let copyThingProperty = thingProperty.copy()
let thingValue: Thing = try thingProperty.getValue()
thingValue.value = 123
print(thingValue.value)
let copyThingValue: Thing = try copyThingProperty.getValue()
print(copyThingValue.value)
PropertyProtocol is necessary because I am holding a dictionary of Property objects and use the PropertyProtocol as a non-generic "type eraser"
And the problem with the conditional extension is that, addressing the Property objects through the PropertyProtocol, neither the copy() or the init(:_) in the extension get called.
If I address the Property objects directly, then all is fine and the extension methods get called.
So, I resorted to doing away with the extension and putting conditional code in the one init(:_) method in Property, which then meant that I then had to use a version of init(:_) in the protocol that took a Copyable parameter, to avoid the Self error.
I have no problem getting around this, it just means a different way of coding.
But, the question remains - why do I get the Self error in the protocol for the init(:_) declaration but not for the copy() method declaration?