Constructors & Contract Lifecycle

Historically selfdestruct(recipient) deleted the contract's code and storage and sent its Ether.

15.1 Constructors

Runs exactly once, during deployment; its code is not part of the runtime bytecode.

During construction, address(this).code.length == 0 — so code.length checks cannot detect calls coming from a constructor.

Constructors have no visibility (removed in 0.7.0); to prevent deployment of a base contract, mark it abstract.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Base {
    string public name;
    constructor(string memory _name) { name = _name; }
}

// Two ways to pass arguments to base constructors
contract Child1 is Base("fixed name") {}

contract Child2 is Base {
    uint256 public immutable created;
    constructor(string memory n) payable Base(n) {   // payable constructor can receive Ether at deployment
        created = block.timestamp;
    }
}

15.2 Lifecycle

compile → deploy (creation tx runs init code + constructor) → runtime code stored at address
        → users call functions (forever) → optional: pause / migrate / upgrade via proxy

15.3 selfdestruct (deprecated)

Historically selfdestruct(recipient) deleted the contract's code and storage and sent its Ether. Since the Cancun upgrade (EIP-6780, March 2024) it only transfers Ether unless called in the same transaction that created the contract. It is deprecated since 0.8.18 and emits a compiler warning. Do not design around it; use a pause flag or upgrade pattern instead.