@@ -40,27 +40,27 @@ Details are given in the following example.
40
40
41
41
// SPDX-License-Identifier: GPL-3.0
42
42
pragma solidity >=0.7.0 <0.9.0;
43
- // This will report a warning due to deprecated selfdestruct
44
43
45
44
contract Owned {
46
- constructor() { owner = payable(msg.sender); }
47
45
address payable owner;
46
+ constructor() { owner = payable(msg.sender); }
48
47
}
49
48
50
-
51
49
// Use `is` to derive from another contract. Derived
52
50
// contracts can access all non-private members including
53
51
// internal functions and state variables. These cannot be
54
52
// accessed externally via `this`, though.
55
- contract Destructible is Owned {
53
+ contract Emittable is Owned {
54
+ event Emitted();
55
+
56
56
// The keyword `virtual` means that the function can change
57
57
// its behavior in derived classes ("overriding").
58
- function destroy() virtual public {
59
- if (msg.sender == owner) selfdestruct(owner);
58
+ function emitEvent() virtual public {
59
+ if (msg.sender == owner)
60
+ emit Emitted();
60
61
}
61
62
}
62
63
63
-
64
64
// These abstract contracts are only provided to make the
65
65
// interface known to the compiler. Note the function
66
66
// without body. If a contract does not implement all
@@ -69,37 +69,35 @@ Details are given in the following example.
69
69
function lookup(uint id) public virtual returns (address adr);
70
70
}
71
71
72
-
73
72
abstract contract NameReg {
74
73
function register(bytes32 name) public virtual;
75
74
function unregister() public virtual;
76
75
}
77
76
78
-
79
77
// Multiple inheritance is possible. Note that `Owned` is
80
- // also a base class of `Destructible `, yet there is only a single
78
+ // also a base class of `Emittable `, yet there is only a single
81
79
// instance of `Owned` (as for virtual inheritance in C++).
82
- contract Named is Owned, Destructible {
80
+ contract Named is Owned, Emittable {
83
81
constructor(bytes32 name) {
84
82
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
85
83
NameReg(config.lookup(1)).register(name);
86
84
}
87
85
88
86
// Functions can be overridden by another function with the same name and
89
- // the same number/types of inputs. If the overriding function has different
87
+ // the same number/types of inputs. If the overriding function has different
90
88
// types of output parameters, that causes an error.
91
89
// Both local and message-based function calls take these overrides
92
90
// into account.
93
91
// If you want the function to override, you need to use the
94
92
// `override` keyword. You need to specify the `virtual` keyword again
95
93
// if you want this function to be overridden again.
96
- function destroy () public virtual override {
94
+ function emitEvent () public virtual override {
97
95
if (msg.sender == owner) {
98
96
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
99
97
NameReg(config.lookup(1)).unregister();
100
98
// It is still possible to call a specific
101
99
// overridden function.
102
- Destructible.destroy ();
100
+ Emittable.emitEvent ();
103
101
}
104
102
}
105
103
}
@@ -108,93 +106,132 @@ Details are given in the following example.
108
106
// If a constructor takes an argument, it needs to be
109
107
// provided in the header or modifier-invocation-style at
110
108
// the constructor of the derived contract (see below).
111
- contract PriceFeed is Owned, Destructible, Named("GoldFeed") {
109
+ contract PriceFeed is Owned, Emittable, Named("GoldFeed") {
110
+ uint info;
111
+
112
112
function updateInfo(uint newInfo) public {
113
113
if (msg.sender == owner) info = newInfo;
114
114
}
115
115
116
116
// Here, we only specify `override` and not `virtual`.
117
117
// This means that contracts deriving from `PriceFeed`
118
- // cannot change the behavior of `destroy ` anymore.
119
- function destroy () public override(Destructible , Named) { Named.destroy (); }
118
+ // cannot change the behavior of `emitEvent ` anymore.
119
+ function emitEvent () public override(Emittable , Named) { Named.emitEvent (); }
120
120
function get() public view returns(uint r) { return info; }
121
-
122
- uint info;
123
121
}
124
122
125
- Note that above, we call ``Destructible.destroy () `` to "forward" the
126
- destruction request. The way this is done is problematic, as
123
+ Note that above, we call ``Emittable.emitEvent () `` to "forward" the
124
+ emit event request. The way this is done is problematic, as
127
125
seen in the following example:
128
126
129
127
.. code-block :: solidity
130
128
131
129
// SPDX-License-Identifier: GPL-3.0
132
130
pragma solidity >=0.7.0 <0.9.0;
133
- // This will report a warning due to deprecated selfdestruct
134
131
135
- contract owned {
136
- constructor() { owner = payable(msg.sender); }
132
+ contract Owned {
137
133
address payable owner;
134
+ constructor() { owner = payable(msg.sender); }
138
135
}
139
136
140
- contract Destructible is owned {
141
- function destroy() public virtual {
142
- if (msg.sender == owner) selfdestruct(owner);
137
+ contract Emittable is Owned {
138
+ event Emitted();
139
+
140
+ function emitEvent() virtual public {
141
+ if (msg.sender == owner) {
142
+ emit Emitted();
143
+ }
143
144
}
144
145
}
145
146
146
- contract Base1 is Destructible {
147
- function destroy() public virtual override { /* do cleanup 1 */ Destructible.destroy(); }
147
+ contract Base1 is Emittable {
148
+ event Base1Emitted();
149
+ function emitEvent() public virtual override {
150
+ /* Here, we emit an event to simulate some Base1 logic */
151
+ emit Base1Emitted();
152
+ Emittable.emitEvent();
153
+ }
148
154
}
149
155
150
- contract Base2 is Destructible {
151
- function destroy() public virtual override { /* do cleanup 2 */ Destructible.destroy(); }
156
+ contract Base2 is Emittable {
157
+ event Base2Emitted();
158
+ function emitEvent() public virtual override {
159
+ /* Here, we emit an event to simulate some Base2 logic */
160
+ emit Base2Emitted();
161
+ Emittable.emitEvent();
162
+ }
152
163
}
153
164
154
165
contract Final is Base1, Base2 {
155
- function destroy() public override(Base1, Base2) { Base2.destroy(); }
166
+ event FinalEmitted();
167
+ function emitEvent() public override(Base1, Base2) {
168
+ /* Here, we emit an event to simulate some Final logic */
169
+ emit FinalEmitted();
170
+ Base2.emitEvent();
171
+ }
156
172
}
157
173
158
- A call to ``Final.destroy () `` will call ``Base2.destroy `` because we specify it
174
+ A call to ``Final.emitEvent () `` will call ``Base2.emitEvent `` because we specify it
159
175
explicitly in the final override, but this function will bypass
160
- ``Base1.destroy ``. The way around this is to use ``super ``:
176
+ ``Base1.emitEvent ``, resulting in the following sequence of events:
177
+ ``FinalEmitted -> Base2Emitted -> Emitted ``, instead of the expected sequence:
178
+ ``FinalEmitted -> Base2Emitted -> Base1Emitted -> Emitted ``.
179
+ The way around this is to use ``super ``:
161
180
162
181
.. code-block :: solidity
163
182
164
183
// SPDX-License-Identifier: GPL-3.0
165
184
pragma solidity >=0.7.0 <0.9.0;
166
- // This will report a warning due to deprecated selfdestruct
167
185
168
- contract owned {
169
- constructor() { owner = payable(msg.sender); }
186
+ contract Owned {
170
187
address payable owner;
188
+ constructor() { owner = payable(msg.sender); }
171
189
}
172
190
173
- contract Destructible is owned {
174
- function destroy() virtual public {
175
- if (msg.sender == owner) selfdestruct(owner);
191
+ contract Emittable is Owned {
192
+ event Emitted();
193
+
194
+ function emitEvent() virtual public {
195
+ if (msg.sender == owner) {
196
+ emit Emitted();
197
+ }
176
198
}
177
199
}
178
200
179
- contract Base1 is Destructible {
180
- function destroy() public virtual override { /* do cleanup 1 */ super.destroy(); }
201
+ contract Base1 is Emittable {
202
+ event Base1Emitted();
203
+ function emitEvent() public virtual override {
204
+ /* Here, we emit an event to simulate some Base1 logic */
205
+ emit Base1Emitted();
206
+ super.emitEvent();
207
+ }
181
208
}
182
209
183
210
184
- contract Base2 is Destructible {
185
- function destroy() public virtual override { /* do cleanup 2 */ super.destroy(); }
211
+ contract Base2 is Emittable {
212
+ event Base2Emitted();
213
+ function emitEvent() public virtual override {
214
+ /* Here, we emit an event to simulate some Base2 logic */
215
+ emit Base2Emitted();
216
+ super.emitEvent();
217
+ }
186
218
}
187
219
188
220
contract Final is Base1, Base2 {
189
- function destroy() public override(Base1, Base2) { super.destroy(); }
221
+ event FinalEmitted();
222
+ function emitEvent() public override(Base1, Base2) {
223
+ /* Here, we emit an event to simulate some Final logic */
224
+ emit FinalEmitted();
225
+ super.emitEvent();
226
+ }
190
227
}
191
228
192
- If ``Base2 `` calls a function of ``super ``, it does not simply
229
+ If ``Final `` calls a function of ``super ``, it does not simply
193
230
call this function on one of its base contracts. Rather, it
194
231
calls this function on the next base contract in the final
195
- inheritance graph, so it will call ``Base1.destroy () `` (note that
232
+ inheritance graph, so it will call ``Base1.emitEvent () `` (note that
196
233
the final inheritance sequence is -- starting with the most
197
- derived contract: Final, Base2, Base1, Destructible, owned ).
234
+ derived contract: Final, Base2, Base1, Emittable, Owned ).
198
235
The actual function that is called when using super is
199
236
not known in the context of the class where it is used,
200
237
although its type is known. This is similar for ordinary
0 commit comments