//
// https://medium.com/@jegnux/safe-collection-subsripting-in-swift-3771f16f883
// https://github.com/ReactiveX/RxSwift/issues/826
//
import Foundation
// we define a fire protocol.
protocol FireProtocol {
// Type placeholder
associatedtype FireType
var fire: FireType { get }
}
// make a fire type.
public class Fire<Base> {
public let base: Base
public init(_ base: Base) {
// base is the conforming type that conform to FireProtocol,
// in current file.
self.base = base
}
// default behavior
func fireInTheHole() {
print("fire !!!!!")
}
}
extension FireProtocol {
// Self reference to the conforming type.
public var fire: Fire<Self> {
get {
return Fire(self)
}
}
}
// -------------------------------
// Begin the fun part
// Create a dragon.
public class Dragon {}
// give the dragon fire attribute.
extension Dragon: FireProtocol {}
// Instead of extension the Dragon class, we extension `Fire` class
// and give the dragon a property that is a `Fire`. then the dragon can have the
// ability that Fire object have.
let dragon = Dragon()
dragon.fire.fireInTheHole()
extension Fire {
public func fireAgain() {
print("fireAgain")
}
}
// See ?
dragon.fire.fireAgain()
// create another type.
public class Bird: FireProtocol {}
// bird also have the ability that dragon have.
let bird = Bird()
bird.fire.fireInTheHole()
bird.fire.fireAgain()
// This is nothing special to the normal protocol oriented programming way.
// We can use generic constraint to add ability to one type.
// add ability to dragon only.
extension Fire where Base: Dragon {
public func dragonOnlyMethod() {
print("dragon only method")
}
}
dragon.fire.dragonOnlyMethod()
// error: 'Bird' is not a subtype of 'Dragon'
// bird.fire.dragonOnlyMethod()
extension Fire where Base: Bird {
public func eatWorm() {
print("bird eat worm")
}
}
bird.fire.eatWorm()