Inheriting from Another Smart Contract: Understanding Storage in Ethereum
When writing smart contracts on the Ethereum blockchain, one of the fundamental concepts to grasp is inheritance. Inheritance allows a new contract (the inheritor) to build upon or modify the functionality of an existing contract (the parent). However, there’s a crucial aspect to consider when working with storage: the this
keyword and its implications.
In your example, Contract A has an immutable
variable x
, initialized with the value 42. In Contract B, which inherits from Contract A, it is not explicitly specified that y
should be inherited or have a specific value. However, we will explore why y
might seem to be set to 0 in Contract B.
Why doesn’t y
inherit the value of x
from Contract A?
In Ethereum contracts, when using the immutable
keyword, any non-immutable variables (like constants) are not affected by inheritance. This is because immutability is a contract-level property that prevents modification after the constructor call.
The reason you might see y
set to 0 in Contract B is due to the way Ethereum’s storage works for inherited variables:
- When a new contract inherits from an existing one, it uses the storage location of its parent (Contract A) as its own.
- If a variable is not initialized with a specific value in the constructor call, it will be initialized with the default value from the storage location of the parent contract.
- Since
y
is not explicitly initialized with a value in Contract B’s constructor call, it defaults to 0.
Workarounds: Assigning a value to y
To fix this issue, you have a couple of options:
- Use an explicit variable declaration: In your code, you can declare
y
as an instance variable, like so:
contract A {
immutable uint x;
builder() {
x = 42;
y = 0; // Assigning a value to y explicitly
}
...
}
- Use the
memory
storage type: When working with smart contracts, it’s often more convenient to use thememory
storage type instead ofstorage
. Thememory
type allows you to dynamically allocate memory and deallocate it as needed.
contract A {
immutable uint x;
constructor() public {
x = 42;
}
...
}
contract B extends A {
function setY(uint y) public {
// y is now accessible in Contract B
}
}
In this example, y
can be modified directly without affecting the inheritance.