Swift: Support protocol default methods and protocol extensions (=mixins)

Originator:christoffer
Number:rdar://17298843 Date Originated:13-Jun-2014 09:36 AM
Status:Closed Resolved:Duplicate of 14011860
Product:Developer Tools Product Version:6.0 (6A215l)
Classification:Enhancement Reproducible:Always
 
Summary:
In Java 8, optional default methods were added to Java interfaces.

By adding similar support, it is possible to trivially support mixins and safe binary backward compatibility of protocols. 

Example 1:

protocol Equals {
	func isEqualTo(object : AnyObject) -> Bool
}

class MyClass : Equals {
	let value : Int
	func isEqualTo(object: AnyObject) -> Bool {
		if let myObject = object as? MyClass {
			return myObject.value == value
		}
		return false
	}
	init(_ value : Int) { self.value = value }
}

Let's say we want to add isNotEqual to the Equals interface. That is not possible, since that would require MyClass to add the method conforming to the extended interface. 

However, if we have something like default protocol method:

extension protocol Equals {
	func isNotEqualTo(object : AnyObject) -> Bool {
		return !self.isEqualTo(object)
	}
}

We could then immediately use MyClass(1).isNotEqualTo(MyClass(1))

We could define our protocol with isNotEquals immediately, by providing a default method:

protocol Equals {
	func isEqualTo(object : AnyObject) -> Bool
	default func isNotEqualTo(object : AnyObject) -> Bool {
		return !self.isEqualTo(object)
	}
}

This would work as a mixin:

class MyClass : Equals {
	let value : Int
	func isEqualTo(object: AnyObject) -> Bool {
		if let myObject = object as? MyClass {
			return myObject.value == value
		}
		return false
	}
	init(_ value : Int) { self.value = value }
}

class MyClass2 : Equals {
	let value : Double
	func isEqualTo(object: AnyObject) -> Bool {
		if let myObject = object as? MyClass {
			return myObject.value == value
		}
		return false
	}
	init(_ value : Double) { self.value = value }
}

Now both MyClass2 and MyClass share the implementation for isNotEqualTo defined in protocol Equals.
 
We could even make pure mixins:

protocol UselessMixin {
	default func bracketDescription {
		return "[\(self)]"
	}
}

And either add it when creating the class

class MyClass : UselessMixin {}

or add it as an extension:

extension MyClass : UselessMixin {}

If we look at Equatable, then this is essentially what we have:

== is defined, but we get != for free. So this extensible protocol with default method is actually dual to free functions.

This is readily seen because

class MyClass {}
func myFunction(O : MyClass, arg : Int) {
	// do something
}

Is dual to 

extension MyClass {
	func myFunction(arg : Int) {
		// do something
	}
}

Consequently

protocol MyProtocol {}
func myFunction(O : MyProtocol, arg : Int) {
	// do something
}

Is dual to 

extension MyProtocol {
	func myFunction(arg : Int) {
		// do something
	}
}

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!