In Solidity, both external
and public
functions can be called from outside a contract, but there are key differences in how they are used, accessed, and their gas efficiency. Understanding these differences is crucial for writing optimized and secure smart contracts.
Differences Between public
and external
Functions
1. Visibility and Accessibility:
- Public Functions:
- Can be called both externally (from outside the contract) and internally (from within the contract).
- When called internally, they can be called just like any other function (
functionName()
).
- External Functions:
- Can only be called from outside the contract.
- If you want to call an
external
function from within the same contract, you must usethis.functionName()
, which triggers an external call (which is less gas-efficient).
2. Gas Efficiency:
- Public Functions:
- When called externally, public functions copy all arguments to memory, which can be more expensive, especially with large arrays or strings.
- External Functions:
- External functions are more gas-efficient when called externally because they read their arguments directly from the calldata, which avoids unnecessary data copying.
3. Usage of msg.data
:
- Public Functions:
- Can access arguments directly and work with them in memory when called internally.
- External Functions:
- Arguments are accessed directly from calldata, which is read-only and generally cheaper in terms of gas.
When to Use public
vs. external
Use public
when:
- You need the function to be accessible both internally and externally.
- You expect the function to be called internally within the contract frequently.
- The function might modify state variables or interact with other internal functions.
Example:
pragma solidity ^0.8.24;
contract Example {
uint public data;
// Public function
function setData(uint _data) public {
data = _data; // Can be called internally and externally
}
function internalCall() public {
setData(100); // Internal call to a public function
}
}
Use external
when:
- The function is primarily intended to be called from outside the contract, such as by other contracts or users.
- You want to optimize gas costs for external calls, especially when passing large arrays or strings.
- The function doesn’t need to be called internally, or if it does, it will be done rarely, and you are okay with the overhead of using
this.functionName()
.
Example:
pragma solidity ^0.8.24;
contract Example {
uint public data;
// External function
function setData(uint _data) external {
data = _data; // Can only be called from outside the contract
}
function internalCall() public {
// This will trigger an external call, which is less gas efficient
this.setData(100);
}
}
Summary
public
:- Accessible both internally and externally.
- Less gas-efficient for external calls due to data copying.
- Ideal when the function is expected to be called internally frequently.
external
:- Only accessible externally (unless using
this.functionName()
). - More gas-efficient for external calls as it directly accesses calldata.
- Best for functions that are primarily designed to be called from outside the contract.
- Only accessible externally (unless using
By carefully choosing between public
and external
, you can optimize your contract for both performance and security.