Ability to implement a protocol's generic method with a non-generic equivalent

Imagine a protocol:

protocol Copyable
{
  init(other: Self)
  
  func copy() -> Self
}

Unfortunately, using this protocol is difficult because of the mention of Self in the init(:_) definition.

So, we change the parameter type:

protocol Copyable
{
  init(other: Copyable)
  
  func copy() -> Self
}

This now means that every implementing type has to cast the other parameter to itself in order to access its members.

So, why not use a generic definition?

protocol Copyable
{
  init<otherT : Copyable>(other: otherT)
  
  func copy() -> Self
}

That's all well and good until it comes to implementing it, when the compiler insists that it needs to be implemented by the exact same generic signature.

What is more, it is still necessary to cast from otherT to the implementing type, just as with using Copyable.

My "pitch" is that, in an implementing type should be able to satisfy the generic signature with a non-generic signature that matches all the requirements:

class Property<valueT : DefaultValueProvider & Equatable> : Copyable
{
  var value = valueT()
  
  init() { }
  
  required convenience init(other: Property)
  {
    self.init()
    
    value = other.value
  }
}

That wouldn't be correct. A generic function allows the caller to choose the type, while an associated type allows the callee to choose the type. For a concrete example:

extension String: Copyable { … }
extension Int: Copyable { … }
print(Int(other: "abc")) // obviously fails

func copyABC<Result: Copyable>() -> Result {
  return Result(other: "abc") // also needs to fail, but matches the protocol requirement
}
print(copyABC() as Int)
1 Like