function visibility
Visibility answers one question for each function: who is allowed to call it? Solidity offers four levels — public, external, internal, and private — and choosing the wrong one is a frequent source of bugs, from accidentally exposing an admin function to needlessly burning gas on big inputs.
public functions are callable both from inside the contract and from outside via a transaction or message call; declaring a state variable public also auto-generates a getter for it. external functions can only be called from outside — an internal call to an external function must go through this.f(), which is a real CALL with its overhead. internal functions are reachable from this contract and any contract that inherits it. private functions are reachable only from the exact contract that defines them, not even from derived contracts. These levels shape the contract's ABI and how the dispatcher routes a call; they do not make anything secret.
Two practical points. On gas: an external function can read array and bytes arguments directly from calldata, whereas a public function copies them into memory first, so external is cheaper for large inputs. On security: internal and private restrict who can call the code, not who can read the data. All contract storage is publicly readable on-chain by anyone running a node, so a 'private' variable is not confidential — never store a secret, password, or key material in contract state expecting visibility to hide it.
uint256 public totalSupply; // auto getter: totalSupply()
function _mint(address to) internal {} // this contract + heirs
function transfer(...) external {} // outside callers onlyPick the narrowest visibility that still works.
Common misconception: private means confidential. It does not. private only blocks other Solidity code from calling it — anyone can still read the underlying storage slot straight off the chain.