Я только начал изучать Swift (v. 2.x), потому что мне любопытно, как появляются новые функции, особенно протоколы с Self-требованиями.
Следующий пример будет компилироваться просто отлично, но вызывает произвольные эффекты выполнения:
// The protocol with Self requirement
protocol Narcissistic {
func getFriend() -> Self
}
// Base class that adopts the protocol
class Mario : Narcissistic {
func getFriend() -> Self {
print("Mario.getFriend()")
return self;
}
}
// Intermediate class that eliminates the
// Self requirement by specifying an explicit type
// (Why does the compiler allow this?)
class SuperMario : Mario {
override func getFriend() -> SuperMario {
print("SuperMario.getFriend()")
return SuperMario();
}
}
// Most specific class that defines a field whose
// (polymorphic) access will cause the world to explode
class FireFlowerMario : SuperMario {
let fireballCount = 42
func throwFireballs() {
print("Throwing " + String(fireballCount) + " fireballs!")
}
}
// Global generic function restricted to the protocol
func queryFriend<T : Narcissistic>(narcissistic: T) -> T {
return narcissistic.getFriend()
}
// Sample client code
// Instantiate the most specific class
let m = FireFlowerMario()
// The call to the generic function is verified to return
// the same type that went in -- 'FireFlowerMario' in this case.
// But in reality, the method returns a 'SuperMario' and the
// call to 'throwFireballs' will cause arbitrary
// things to happen at runtime.
queryFriend(m).throwFireballs()
Здесь вы можете увидеть пример в действии в IBM Swift Sandbox. В моем браузере вывод выглядит следующим образом:
SuperMario.getFriend() Throwing 32 fireballs!
(вместо 42! Или, скорее, "вместо исключения времени выполнения", поскольку этот метод даже не определен для объекта, на который он вызван.)
Является ли это доказательством того, что Swift в настоящее время не безопасен для типов?
EDIT # 1:
Непредсказуемое поведение, подобное этому, должно быть неприемлемым.
Истинный вопрос: какой точный смысл имеет ключевое слово Self
(первая буква).
Я не мог найти ничего в Интернете, но есть, по крайней мере, эти две возможности:
-
Self
- просто синтаксический ярлык для полного имени класса, в котором он появляется, и он может быть заменен последним без какого-либо изменения смысла. Но тогда он не может иметь то же значение, что и при определении протокола. -
Self
- это своего рода общий/связанный тип (как в протоколах, так и в классах), который повторно создается в процессе получения/принятия классов. Если это так, компилятор должен был отказаться от переопределенияgetFriend
вSuperMario
.
Возможно, истинное определение не является ни тем, ни другим. Было бы здорово, если бы кто-то с большим опытом работы с языком мог пролить свет на эту тему.