[swift-evolution] [Pitch] Tweak `Self` and introduce `Current`

Braeden Profile jhaezhyr12 at gmail.com
Sat Jan 7 16:00:15 CST 2017


> 
>  One could workaround the problem and use final, but what if the class
>  meant to be subtypeable? Self simply does not work in this scenario.
> 
> 
> It works exactly as it should in this scenario. If A isn't final, then by
> definition it's impossible for A to make a copy of type Self. I see,
> however, what you mean, which is that you wish you could write a protocol
> requirement for a function that returns #Self.

What do you mean?  Even with the limited `Self` support in Swift 3, I can write a very effective copying paradigm.
protocol Copyable
{
	func copy() -> Self
}

class Building: Copyable
{
	var floors = 1
	
	required init()
		{  }
	
	func copy() -> Self
	{
		let dynamicType = type(of: self)
		let newObject = dynamicType.init()
		newObject.floors = self.floors
		
		return newObject
	}
}

class Mansion: Building
{
	var butlers = 3
	
	override func copy() -> Self
	{
	//	let newObject = super.copy()
		let newObject = super.copy() as! Mansion
		
		newObject.butlers = self.butlers
		
	//	return newObject
		return unsafeBitCast(newObject, to: type(of: self))
	}
}


let hoboHouse = Building()
hoboHouse.floors = 0

let beggarHouse = hoboHouse.copy()
print(beggarHouse.floors)  // "0"


let myHouse = Mansion()
myHouse.floors = 4

let yourHouse = myHouse.copy()
print(yourHouse.floors)  // “4”

Besides the poor support for `Self` in the function body (SE–0068 fixes that), it seems like an acceptable way of doing it.

Of course, I would love being able to use an initializer setup, but there are serious bugs in the implementation.

protocol Clonable
{
	init(other: Self)
}

extension Clonable
{
	func clone() -> Self
		{ return type(of: self).init(other: self) }
}


class Base: Clonable
{
	var x: Int
	
	init(x: Int)
		{ self.x = x }
	
	required init(other: Base)
		{ self.x = other.x }
}

class Derived: Base
{
	var y: String
	
	init(x: Int, y: String)
	{
		self.y = y
		super.init(x: x)
	}
	
	// Should be required by the Clonable protocol, but it isn't.
	required init(other: Derived)
	{
		self.y = other.y
		super.init(other: other)
	}
	
	// Required because it was `required` in Base.  Even a `Derived` calls this initializer to clone, which is wrong.  Bugs abound.
	required init(other: Base)
		{ fatalError("init(other:) is wrong.") }
}



let me = Derived(x: 1, y: "food")
let alienClone = me.clone() // "init(other:) is wrong."

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170107/18af8048/attachment.html>


More information about the swift-evolution mailing list