Skip to content

Instantly share code, notes, and snippets.

@quesera2
Forked from gwengrid/TypeErasure.swift
Last active May 4, 2016 08:52
Show Gist options
  • Save quesera2/a57242183bee8d4e645c75caf9fb0006 to your computer and use it in GitHub Desktop.
Save quesera2/a57242183bee8d4e645c75caf9fb0006 to your computer and use it in GitHub Desktop.
Example of type erasure with Pokemon
class Thunder { }
class Fire { }
protocol Pokemon {
associatedtype PokemonType
func attack(move:PokemonType)
}
struct Pikachu: Pokemon {
typealias PokemonType = Thunder
func attack(move: Thunder) { print("⚡️") }
}
class Charmander: Pokemon {
func attack(move: Fire) { print("🔥") }
}
class Raichu: Pokemon {
typealias PokemonType = Thunder
func attack(move: Thunder) { print("⚡️") }
}
// 付随型をジェネリクスに置き換えた抽象クラスを作る
// Swiftの言語仕様上、抽象クラスはないので、実際には「抽象クラスのようなもの」です
private class _AnyPokemonBase<PokemonType>: Pokemon {
func attack(move:PokemonType) {
// 空実装を提供する。オリジナルは abstruct() という関数を呼んでいる
fatalError()
}
}
// 抽象クラスを継承したラッパーを作る
private class _AnyPokemonBox<ConcretePokemon: Pokemon> : _AnyPokemonBase<ConcretePokemon.PokemonType> {
let base :ConcretePokemon
init(_ base :ConcretePokemon) {
self.base = base
}
override func attack(move: ConcretePokemon.PokemonType) {
self.base.attack(move)
}
}
// AnyPokemonでは、_AnyPokemonBoxに処理を移譲する
final class AnyPokemon <PokemonType>: Pokemon {
private let _box : _AnyPokemonBase<PokemonType>
required init<U:Pokemon where U.PokemonType == PokemonType>(_ pokemon: U) {
self._box = _AnyPokemonBox(pokemon)
}
func attack(move: PokemonType) {
self._box.attack(move)
}
}
let thunderAttack = Thunder()
let electricPokemon = [AnyPokemon(Pikachu()), AnyPokemon(Raichu())]
for pokemon in electricPokemon {
pokemon.attack(thunderAttack)
}
@quesera2
Copy link
Author

quesera2 commented May 4, 2016

without protocol oriented.

class Thunder { }

class AbstractPokemon<PokemonType> {
    func attack(move:PokemonType) {
        fatalError()
    }
}

class AbstractElectricPokemon : AbstractPokemon<Thunder> {
     override func attack(move: Thunder) { print("⚡️") }   
}

class Pikachu: AbstractElectricPokemon { }

class Raichu: AbstractElectricPokemon { }

let electricPokemon = [Pikachu(), Raichu()]
let thunderAttack = Thunder()

for pokemon in electricPokemon {
    pokemon.attack(thunderAttack)
}

// 英語は適当
I think...
Than deceive compiler by trick, provided abstract class can easy understood.

Each framework are making abstract class of their own.
Are you serious??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment