9

In OOP languages, composition over inheritance is a well-known best practice. Solidity is an OOP language too but there is also the gas efficiency issue.

Question is, in Solidity, how do composition and inheritance compare to each other considering respective gas costs?

P.S. Also asked in Ethereum.SE: https://ethereum.stackexchange.com/questions/59994/composition-over-inheritance-gas-efficiency

Pang
  • 9,564
  • 146
  • 81
  • 122
Ferit
  • 8,692
  • 8
  • 34
  • 59

2 Answers2

2

In a 1-1 comparison, Composition is more expensive to deploy and execute. That said, if you need to deploy many instances, you could use the Library pattern and use composition in that way.

Libraries can lower deployment costs if you're going to be deploying many copies of the same code. If you imagine deploying 100 copies of the same code, you may only have to deploy one Library, and then the more code you can push into the Library, the cheaper each dependent contract deployment will be. But calling that library increases execution costs.

Another thing to consider with libraries: there are significant security concerns to shared libraries. The Parity hack which locked up funds was due to usage of composition.

Inheritance is a much simpler model and will always be cheaper to execute.

But, you will have to make the call as to what fits your use case. Will there be many versions of this contract? If so, will each instance be executed often enough to make up for deployment costs?

Pang
  • 9,564
  • 146
  • 81
  • 122
Steve Ellis
  • 494
  • 5
  • 13
  • Your reference to the Parity hack as a result of library usage and calling it "usage of composition" is highly misleading. The hack would not have occurred if Parity had indeed used a library, which has no state and cannot self-destruct. The hack occurred because the proxy pattern they used required initializing the implementation contract through a delegatecall; however, they had overlooked anyone could initialize the implementation contract by a direct call to take ownership of it and then call self-destruct. – C S Oct 18 '21 at 02:05
-1

Tuning a contract is not an exact science, but is a balance of security, good coding practices, and cost.

In Ethereum transactions cost gas and hence ether. Reducing the gas consumed by a contract is important in two situations,

  1. Cost of deploying a contract
  2. Cost to call the contract functions

OOP principles like Inheritance & Composition facilitate code-reuse and hence automatically reduce byte-size of a contract. However, it is still very much responsibility of the developer to write efficient code to optimize gas usage.

To avoid huge cost in deploying a contract, it is important for developer to write efficient code. Especially when a contract inherits from another or when a contract is composed of another contract(s).

If Contract B inherits from Contract A then, during compilation, Solidity compiler injects byte-code of A into B. This increases deployment cost for B. (Essentially size of B = Size of B + Size of A). Similarly, if Contract C is composed of Contract D, byte-code of D will be compiled into byte-code of C. But, if you as a developer feel this initial cost is justified as compared to reducing transaction cost by re-using code, then you have an executive decision to make!

BUT, when you do composition like this:

// Foo bytecode will be loaded into memory from an existing Foo deployment
Foo public foo2 = Foo(0xF00BAA...); //THIS is more efficient compared to new Foo().

In some cases, You can consider alternatives to inheritance. For example, Child contracts that call external functions in a main contract (say, a registry or main storage/logic) will tend to be smaller than Child contracts that inherited a complex contract. This will not only reduce cost of deployment but also cost less gas for transactions in total.

Another way of reducing the size of by Removing useless code, . for eg:

function p1 ( uint x ){ 
   if ( x > 5)
    if ( x*x < 20)
       XXX }

In above code line 3 and 4 will never be executed and these type of useless code can be avoided carefully going through the contract logic and that will reduce the size of the smart contract.

Overall, Just choosing Composition vs Inheritance does not make it for gas efficiency. Its pragmatic coding which result in gas efficient code!

For more details, this article helps with good practises for coding gas efficient solidity code.

Hope it helps.

Pruthvi Kumar
  • 868
  • 1
  • 7
  • 15
  • I don't see any numbers here. I need data to justify my decisions. – Ferit Oct 04 '18 at 19:04
  • Note that doing `Foo public foo2 = Foo(0xF00BAA...);` is just creating a reference to an existing smart contract, not deploying a new one by cloning the existing one at this address. Hence, it is a different operation and it is useless to compare its gas cost with concrete construction. – dionyziz May 23 '20 at 07:58