[swift-evolution] [Review] SE-0026 Abstract classes and methods

Gwendal Roué gwendal.roue at gmail.com
Fri Mar 4 13:24:14 CST 2016


> Le 4 mars 2016 à 08:45, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> a écrit :
> 
>> For modeling subtype requirements we would need the ability to declare protocol members with reduced access scope like private or internal and hopefully protected, as subtype requirements most often are not public.
> 
> I've spoken about this elsewhere, but:
> 
> - For both abstract classes and protocols, all required/abstract members need to be visible everywhere you're permitted to conform/inherit.
> - There is currently no way in Swift to decouple a protocol's/class's visibility from the ability to conform to/inherit from it, so neither construct can currently offer this feature.
> - However, this feature is likely to come at least for classes as part of resiliency. I think it's a good idea for protocols, too.

Brent, please consider the sample code below:

	// Framework land
	public abstract class DatabaseRecord {
		// DatabaseRow initializer
		public required init(row: DatabaseRow) {
			referenceRow = row
		}

		// The table name
		public abstract class func databaseTableName() -> String

		// What should be stored in the database
		public abstract var persistedRow: DatabaseRow
		
		// True if record has been changed since last fetch
		public var hasChanges: Bool { 
			// return complex computation based on referenceRow and persistedRow
		}
		
		// Hidden implementation detail
		internal var referenceRow: DatabaseRow
	}
	
	// User land
	class Person : DatabaseRecord {
		var name: String
		class func databaseTableName() -> String { return "persons" }
		init(row: DatabaseRow) {
			name = row["name"]
			super.init(row)
		}
		var persistedRow: DatabaseRow { return Row("name": name) }
	}

	let person = Person(row: …)
	person.name			// "foo"
	person.hasChanges	// false
	person.name = "bar"
	person.hasChanges	// true


How do we express this with protocols?

	// Framework land
	public protocol DatabaseRecord {
		var referenceRow: DatabaseRow { get set }
		var persistedRow: DatabaseRow { get }
		static func databaseTableName() -> String
		init(row: DatabaseRow)
	}

	extension DatabaseRecord {
		public var hasChanges: Bool { 
			// return complex computation based on referenceRow and persistedRow
		}
	}
	
	// User land
	class Person: DatabaseRecord {
		var referenceRow: DatabaseRow
		var name: String
		init(row: DatabaseRow) {
			name = row["name"]
			super.init(row)
		}
		class func databaseTableName() -> String { return « persons" }
		var persistedRow: DatabaseRow { return Row("name": name) }
	}

	let person = Person(row: …)
	person.name			// "foo"
	person.hasChanges	// false
	person.name = "bar"
	person.hasChanges	// true
	person.referenceRow = …	// messed up internal state

The problem with protocols is that the implementation detail referenceRow has to be public (when it should remain an implementation detail), and that the conforming types must provide it (when they should not even know about its existence).

So abstract classes and protocols are NOT on the same stage today regarding members visibility.

Gwendal



More information about the swift-evolution mailing list