En el lenguaje Swift, para inicializar una instancia, uno debe completar todos los campos de esa clase, y solo luego llamar a superconstructor:
class Base {
var name: String
init(name: String) {
self.name = name
}
}
class Derived: Base {
var number: Int
init(name: String, number: Int) {
// won't compile if interchange lines
self.number = number
super.init(name)
}
}
Para mí, parece al revés, porque la instancia debe self
crearse antes de asignar valores a sus campos, y ese código da la impresión de que el encadenamiento ocurre solo después de la asignación. Aparte de eso, la superclase no tiene medios legales para leer los atributos introducidos de su subclase, por lo que la seguridad no cuenta en este caso.
Además, muchos otros lenguajes, como JavaScript, e incluso el Objetivo C, que es un ancestro espiritual de Swift, requieren un encadenamiento antes de acceder self
, no después.
¿Cuál es el razonamiento detrás de esta elección para requerir que los campos se definan antes de llamar al superconstructor?
fuente
self
.Respuestas:
En C ++, cuando crea un objeto Derivado, comienza como un objeto Base mientras se ejecuta el constructor Base, por lo que en el momento en que se ejecuta el constructor Base, los miembros Derivados ni siquiera existen. Por lo tanto, no necesitan ser inicializados, y no podrían ser inicializados. Solo cuando el constructor Base ha finalizado, el objeto cambia a un objeto Derivado con muchos campos no inicializados que luego se inicializan.
En Swift, cuando crea un objeto derivado, es un objeto derivado desde el principio. Si los métodos se anulan, entonces el método de inicio Base ya usará los métodos anulados, que pueden acceder a las variables miembro Derivadas. Por lo tanto, todas las variables miembro Derivadas deben inicializarse antes de llamar al método Base init.
PD. Mencionaste Objective-C. En Objective-C, todo se inicializa automáticamente a 0 / nil / NO. Pero si ese valor no es el valor correcto para inicializar una variable, entonces el método de inicio Base podría llamar fácilmente a un método que se anula y utiliza la variable aún no inicializada con un valor de 0 en lugar del valor correcto. En Objective-C, eso no es una violación de las reglas del lenguaje (así es como se define que funciona), pero obviamente es un error en su código. En Swift, ese error no está permitido por el idioma.
PD. Hay un comentario "¿es un objeto derivado desde el principio, o no es observable debido a las reglas del lenguaje"? La clase Derivada ha inicializado sus propios miembros antes de que se llame al método Base init, y estos miembros Derivados mantienen sus valores. Entonces, es un objeto Derivado en el momento en que se llama Base init, o el compilador tendría que hacer algo bastante extraño. Y justo después de que el método Base init haya inicializado todos los miembros de la instancia Base, puede invocar funciones anuladas y eso demostrará que es una instancia de la clase derivada.
fuente
Esto proviene de las reglas de seguridad de Swift, como se explica en la sección Inicialización de dos fases en la página de Inicialización del documento de idioma .
Asegura que cada campo esté configurado antes de su uso (especialmente los punteros, para evitar bloqueos).
Swift logra esto con una secuencia de inicialización de dos fases: cada inicializador debe inicializar todos sus campos de instancia, luego llamar a un inicializador de superclase para hacer lo mismo, y solo después de que suceda en el árbol, estos inicializadores pueden dejar
self
escapar el puntero, llamar a la instancia métodos, o leer los valores de las propiedades de instancia.Luego pueden hacer una mayor inicialización, asegurando que el objeto está bien formado. En particular, todos los punteros no opcionales tendrán valores válidos. nil no es válido para ellos.
El objetivo C no es muy diferente, excepto que 0 o nulo siempre es un valor válido, por lo que la inicialización de la primera fase la realiza el asignador simplemente configurando todos los campos a 0. Además, Swift tiene campos inmutables, por lo que deben inicializarse en la fase uno . Y Swift hace cumplir estas reglas de seguridad.
fuente
Considerar
Por lo tanto, no existe un diseño simple que haga que el contratista sea seguro cuando se permiten métodos virtuales , Swift evita estos problemas al requerir la inicialización de dos fases, por lo tanto, brinda una mayor seguridad al programador y al mismo tiempo resulta en un lenguaje más complejo.
Si puede resolver estos problemas de una manera agradable, no pase "Ir", proceda directamente a la recolección de su PHd ...
fuente