Short answer
.send()
returns a boolean result for success/failure.
.transfer()
reverts on failure.
.send()
is the original method. If the receiver is a contract, flow control will be transfered to the receiver's fallback function until it returns.
Long answer
They can fail if the receiver is a contract that doesn't want the money, and there are many good reasons why that might be the case. It is almost always best to revert if the send was unsuccessful.
Therefore, in old syntax, a good pattern was:
bool success = <address>.send(amount);
if(!success) throw; // revert() in newer compilers, possibly require instead of if()
Developers would not always remember (or know) to do that, so the contract might carry on assuming money has been sent when it wasn't ... bugs.
There are few occasions when it would be appropriate to transfer assets, update accounting or generally carry on if the transfer actually failed, but .send()
provides a way to do that:
bool success = <address>.send(amount);
if(!success) {
// deal with the failure case
} else {
// deal with the success case
}
Reentrance
Reentrance was discovered with the DAO incident. "Checks, effects, interactions" is a defensive pattern, meaning:
- Validation
- Optimistic accounting
- send, transfer or call
So, you get something like:
balances[msg.sender] -= amount; // optimistic accounting
bool success = <address>.send(amount);
if(!success) {
// failure case
balances[msg.sender] += amount; // put it back
...
In most cases, one doesn't want to continue and one does want to revert the optimistic accounting, so:
balances[msg.sender] -= amount;
<address>.transfer(amount); // will revert on failure
// success, carry on
Hope it helps.