1

Pretty much all examples of contract functions I see use the require(...) pattern. If the initial condition is not as expected, an error is thrown and the transaction is reverted.

I don't like this pattern because the consumer will not know why they got an error, especially if the function logic is complex. Is there any downside to simply using if...else + events instead?

Instead of:

function AddUser(address _user) {
    require(!userExists(_user));
    ... add the user ...
}

I would do:

function AddUser(address _user) returns (bool) {
    if (userExists(_user)) {
        UserExistsEvent(_user);
        return false;
    } else {
        ... add the user ...
        return true;
    }
}

This way the caller will know exactly what happened in the callee function (by return value and/or event) instead of getting some generic error.

Am I missing something? Why are most functions I see follow the require/throw pattern instead? Is it cheaper?

1 Answer 1

2

Since it's very hard to write correct smart contract code, and the consequences of writing incorrect smart contract code can be very bad, you generally want to optimize for the simplest source code, and the simplest code execution path.

require() is shorter and clearer than an if... return flow, and also reduces the amount that the caller has to get right, as returning a value requires them to correctly catch the return value and respond appropriately.

Not only that, when the caller handles an error, they usually want to do this with a revert, as this can be guaranteed not to leave any side effects. If the caller reverts, you also lose your event log entry, so you didn't gain anything from the extra complexity.

If you're going to end up reverting then there is also a slight gas benefit to doing it as soon as possible, but the difference is usually fairly small and in most cases it's a less important motivation than making the code simpler and harder to use wrongly.

However, returning a result is easier to handle if the calling contract usually wants to continue operation even if it fails, so in those circumstances it is often better to use if... return.

3
  • I see your point. In my case the client app (web/android/ios) will be directly interacting with the contract, and knowing what exactly went wrong is essential, thus generic error from require will not cut it as teach function might have two-there different reasons for a failure and the app needs to know them. Looked, if i want to register a use and the user with this address is already registered, i want to know that instead of getting a generic error. But i agree, in simpler cases where you don't care about the nature of the returned error, require() might work.
    – Andrey
    Feb 9, 2018 at 2:50
  • There may indeed be some cases where this is the pragmatic thing to do, but in the example you give, your client-side app should already have checked that the user exists before it spent your user's money trying to send the transaction. Feb 9, 2018 at 2:55
  • Hm, now that you are talking money, i think it makes sense :) Thank you
    – Andrey
    Feb 9, 2018 at 3:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.