¿Cuál es el orden de ejecución de los constructores Heredados en solidez?

Estoy leyendo la sección sobre constructores heredados en la documentación aquí .

El ejemplo dado me confunde más que entender el concepto, y no explica la parte más importante, el orden de ejecución.

Para resumir la documentación, dice en el siguiente ejemplo:

pragma solidity ^0.4.0;

contract Base {
  uint x;
  function Base(uint _x) { x = _x; }
}


contract Derived1 is Base(7) {
  function Derived1(uint _y) {
  }
}

contract Derived2 is Base{
  function Derived2(uint _y) Base(_y * _y) {
  }
}

Derived1hereda el Base(7)constructor y Derived2usa una sintaxis similar a un modificador de Base(_y * _y).

Pero lo que NO explica es cómo se ejecutan realmente. Tomemos un ejemplo

contract Base {
  public uint x;
  function Base(uint _x) { x = _x; }
}


contract Derived1 is Base(7) {
  function Derived1(uint _y) {
    x = _y;
  }
}

contract Derived2 is Base {
  function Derived2(uint _y) Base(_y * _y) {
    x = _y;
  }
}

¿ x = _ySe ejecuta en cada herencia ANTES del constructor base? ¿o después?

Normalmente, en cualquier programación orientada a objetos, usa notaciones como super()para indicar explícitamente cómo se ejecutará el constructor principal.

En caso de objetivo-c

- (void) init {
  [super init];
  // do something
}

y

- (void) init {
  // do something
  [super init];
}

hacer una gran diferencia ya que el orden de ejecución es diferente. Y la //do somethingparte puede incluso utilizar el resultado de [super init].

Entonces, ¿cómo funciona esto en Solidity? Si puede, comparta también la fuente de la explicación. No puedo encontrar esto en la documentación, así que no sé dónde más puedo encontrar esto.

Además, no diga que es un duplicado y use un ejemplo que apunte a cómo usar constructores en herencia. Ya sé la sintaxis. Estoy preguntando explícitamente sobre la orden de ejecución y dónde está documentado oficialmente. Por ejemplo, ya he leído esta respuesta ethereum.stackexchange.com/questions/16318/… pero esto no explica el orden que es el núcleo de esta pregunta.
En su código, en los contratos Derived1y Derived2, ¿quiso decir que los nombres de las funciones fueran Derived1y Derived2, respectivamente, para que fueran constructores, en lugar de Deriveden ambos?
@AjoyBhatia ¡gracias por señalarlo! Acabo de arreglarlo.

Respuestas (2)

No pude encontrar un documento oficial para explicar esto. Pero cuando nos referimos al código, el flujo del programa podemos asumir que el constructor del Basees llamado antes que el Derivedconstructor.

En el primero , Derived1 is Base(7)la Base(7)sintaxis tiene el aspecto del constructor con el valor 7que se pasa y probablemente esté llamando antes de ir al Derived1constructor cuando se considera el orden declarado.

En el segundo ya que los documentos dicen,

la forma en que se invocaría un modificador

y como siempre los modificadores se ejecutan antes de entrar en el cuerpo de la función, podemos llegar a la conclusión de que Base(7)se ejecuta primero.

Con las suposiciones anteriores, probé el siguiente código en Remix con _y=10la creación del contrato. La getXfunción en ambos contratos devolvió un valor 10pero no 7en Derived1o 100que está (_y*_y)en Derived2. Eso significa que el Baseconstructor se ejecuta primero y el valor de xse sobrescribe 10en x = _y;el cuerpo de los Derivedconstructores. Creo que esto prueba que Basese espera primero al constructor.

pragma solidity ^0.4.0;

contract Base {
  uint x;
  function Base(uint _x) { x = _x; }
}


contract Derived1 is Base(7) {
  function Derived1(uint _y) {
      x = _y;
  }

  function getX() constant returns(uint){
      return x;
  }
}

contract Derived2 is Base {
  function Derived2(uint _y) Base(_y * _y) {
      x = _y;
  }

  function getX() constant returns(uint){
      return x;
  }

}

(si no tiene x = _yen Derivedlos constructores, los valores devueltos son 7y 100)

Los documentos actuales de Solidity brindan la respuesta en este párrafo: https://docs.soliditylang.org/en/v0.8.13/contracts.html#multiple-inheritance-and-linearization

Básicamente: Solidity garantiza que todos los constructores de las clases base serán llamados antes que un constructor de clases derivadas. Y el constructor de clases derivadas no puede cambiar el orden en que Solidity llama a los constructores de clases base.

Pero esto es un poco complicado ya que Solidity tiene que lidiar con la herencia múltiple. Como se explica en los documentos, el gráfico de herencia para la clase derivada se linealiza mediante la linealización C3 , que produce una lista ordenada de clases donde cada clase derivada aparece después de todas sus clases base. Los constructores se llaman en el orden de la lista. Cuando tiene más de una clase base, el orden en que aparecen en la lista se verá afectado por el orden en que aparecen en la lista de herencia (es decir, después de is).

Citando de la documentación:

Un área donde la linealización de herencia es especialmente importante y quizás no tan clara es cuando hay varios constructores en la jerarquía de herencia. Los constructores siempre se ejecutarán en el orden linealizado, independientemente del orden en que se proporcionen sus argumentos en el constructor del contrato heredado. Por ejemplo:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Base1 {
    constructor() {}
}

contract Base2 {
    constructor() {}
}

// Constructors are executed in the following order:
//  1 - Base1
//  2 - Base2
//  3 - Derived1
contract Derived1 is Base1, Base2 {
    constructor() Base1() Base2() {}
}

// Constructors are executed in the following order:
//  1 - Base2
//  2 - Base1
//  3 - Derived2
contract Derived2 is Base2, Base1 {
    constructor() Base2() Base1() {}
}

// Constructors are still executed in the following order:
//  1 - Base2
//  2 - Base1
//  3 - Derived3
contract Derived3 is Base2, Base1 {
    constructor() Base1() Base2() {}
}