1) Your consideration about readability improvement is a very much important aspect of modifiers use. As far as I know, it is THE most important.
2) They are currently used for inputs and state variables check, without differentiation.
3) Given this, another consideration you can add is that modifiers are also inheritable contract properties, that can be overriden by contracts deriving from the root contract.
This means that everytime you need to implement a repetitive pattern of check (without regarding about state variable or input, they are used for both) but you need a slight different implementation detail in particular areas of your code, you can have a very positive impact on code readability using slight different implementation in the various contracts.
For instance if you store the "owner" variable in a root contract, the same "onlyOwner" modifier can be implemented in the root contract itself and overridden in the leaf contracts, aiming to have the check vs the local "owner" variable in the root contract, vs. the root.owner() public getter return value in the leaf contracts.
This aspect can be found described here (bitdegree.org)
-> EDIT (AFTER COMMENTS):
1) you should not read the rule as regarding text size, but readability. Often you can use a slight longer definition for readability, it is not something strictly related to text characters count:
uint currentHeapSize; // is more readable than
uint cHSz; // but it is longer by far.
In the same way if the modifier impact is POSITIVE in terms of readability, it is the case to use it. If it is negative or neutral, better to omit it. For instance Consensys best practices simply says:
"Use modifiers to replace duplicate condition checks in multiple functions, such as isOwner(), otherwise use require or revert inside the function. This makes your smart contract code more readable and easier to audit."
2) The problem is not related to the kind of data you are checking, but the side effect of the checking. You can find any kind of check in standard implementation, even if the more frequent is the environmental/transactional check (who is the msg.sender? is the msg.value > 0? is the current block number > of..?). For instance Consensys reccomend to use modifiers only for assertions. The fact is that the code inside a modifier is usually executed before the function body, so any state changes or external calls will violate the Checks-Effects-Interactions pattern. Moreover, these statements may also remain unnoticed by the developer, as the code for modifier may be far from the function declaration. For example, an external call in modifier can lead to the reentrancy attack:
contract Registry {
address owner;
function isVoter(address _addr) external returns(bool) {
// Code
}
}
contract Election {
Registry registry;
modifier isEligible(address _addr) {
require(registry.isVoter(_addr));
_;
}
function vote() isEligible(msg.sender) public {
// Code
}
}
In this case, the Registry contract can make a reentracy attack by calling Election.vote() inside isVoter().
See "Use modifiers only for assertions" in Consensys Best Practices
3) I appreciate very much a simple article how-to-write-clean-elegant-solidity-code-using-function-modifiers, which concludes: "It might take a few iterations to achieve and using modifiers won’t magically make your code legible. But when used with care, they become a powerful tool to tame complexity and leverage reusability, making your code cleaner and safer."
4) About assertion (see comments): you could have any kind of code in modifiers. For instance you could think to have a (not reccomended!) modifier which calculates the mean value of a vector of elements without check nothing.
For instance you could think to define a
modifier makeMeanBefore {
// here code which calculates the mean value of the current values in a vector elements and do not checks
// any condition, just calculate the mean value and set it in a variable
_;
}
and to define somewhere
function readVectorMean() makeMeanBefore {
...
}
where makeMeanBefore is a modifier, but not implements any assertion; this is what is to be avoided (by newbie, I suppose...)