Function visibility in Solidity

Function Visibility

Private- can only be called by the main contract itself. So if you create a contract {}, you can only access the scoped variable from within it. This is useful for internal functionality, like calling a helper function or Chainlink VRF, or doing custom logic. It is best practice to keep your functions private unless there is a need to access them from somewhere else.

Internal - can be called by the contract itself and any contracts that are derived from it. For instance, if you have a contract called MyContract with some custom methods, what you could do is scope the functions to be `internal`, then when you create a child contract called MyChildContract is MyContract, you can access the `internal` scoped functions from the child contract's functions.

External- can only be called from a third party (like on Etherscan). These functions are good for contract -> contract calls, and are actually more performant than the other two because thair arguments do not need to be copied to memory.

Public- can be called from all parties. Functions are made `public` by default.

Function Keywords

Override- you use this if you create a function that has the same name as one that you inherit from a parent contract. For instance, if you make a contract called TestToken is ERC20, meaning it inherits all of the functions in ERC20, then you want to create a new function called Transfer (ERC20 has a Transfer function), you need to override the previously named Transfer function in the ERC20 contract you inherit. Override should really be called Rename.

Virtual- functions that CAN be written over (override), such as functions in an interface contract, have the keyword `virtual`. So the Transfer function mentioned above would have the keyword `virtual` in an interface version of the contract (IERC20). An interface contract is like a model contract that you pull whatever functions you want from, that's why you need to make the functions `virtual.`

Payable- this keyword literally means that you can attach Eth, or whatever EVM-forked chain currency you're using for the application, to the function. You usually see this on Transfer functions or any that need to send/receive money. You'll see addresses in the parameters (to/from, >=2 addresses).

View- this means that the specific function will not modify the state of a contract. Usually implemented on read/getter functions that need to read state. This is different from `pure`, which cannot read the state of the smart contract that it is currently in.

Constant- this was used as a modifier to indicate that a function won't change the storage state.

Pure- these functions do not read or modify the state variables in a contract.You would use this for functionally scoped programming, where there is no state stored in a contract. I think the best example of this would be a utility function that returns the same output. There is a great function example here between `view` and `pure.`

Indexed- this keyword allows you to search for events that you can later filter. Sort of like the graph, but within the EVM.

Honestly, the best way to understand the differences between all of them is to just write some out and do contract -> contract calls. Even after writing this I had trouble, but when deploying them and testing, it made more sense.

Tired of doing the same activities over and over again?

Get Started