Provide a log_and_revert function in the standard library

Summary

(this is a very small suggestion)

I believe providing a wrapper function around revert that logs a value without evaluating a condition, in the standard library, would allow for easier access to better ergonomics and flexibility while implementing functions. Thus encouraging better code styling (at least in my opinion, which may not be shared by the team) .

As of now the only function (require) that allows for both logging a value and reverting execution also evaluates a condition. There are cases where implementations could (arguably) be more concise and cleaner with a log_and_revert function.


Basic Example

Imagine I want to:

  • Retrieve sender’s indentity of current call.
  • In case identity could be determined, do some operation that requires it.
  • Otherwise, log a custom error.

Using the tools the library currently exposes, a developer would probably go down a path similar to this:

enum AuthorizationError {
    InvalidSender: (),
}

fn foo() {
    let sender_result = msg_sender();
    require(sender_result.is_ok(), AuthorizationError::InvalidSender);

    bar(sender_result.unwrap());
}

With access to a log_and_revert function, the developer could probably be more encouraged to instead do:

enum AuthorizationError {
    InvalidSender: (),
}

fn foo() {
    match msg_sender() {
        Result::Ok(identity) => bar(identity),
        _ => log_and_revert(AuthorizationError::InvalidSender),
    }
}

Conclusion

I could be wrong, but for the code I’ve been seeing from the team it seems to me that the styling of the second implementation is preferred. Sure, the developer could simply call the log function and then the revert. But I think that including this functionality in the standard library aligns with Fuel/Sway’s philosophy.

This is a very small suggestion, that requires a very low level of effort to implement, but decided to share it either way.

Also, I’m not sure if this is the appropriate category to post this, or if I should have posted it over in Sway. So sorry in advance if Sway was the correct place.

29 Likes

Great suggestion. Since we now support automatically decoding generic types that were logged, we can add something analogous to panic in rust, where a value is logged.

Should we update the existing revert function to be generic, or should we wrap it? Hm…I’m not sure how often revert will be used directly to log a numeric error code, and numeric error codes are an anti pattern anyway.

@furnic what do you think?

19 Likes

It could be possible to just have a function also named revert in the logging library instead of in the revert library. So can avoid that ugly name, avoid namespace errors and still provide the desired functionality

8 Likes

I do like the idea of a generic revert<T>(code: T), which could be implemented as follows:

fn revert<T>(code: T) {
    if !__is_reference_type::<T>() {
        __revert(code);
    } else {
        log(code);
        __revert(SOME_SPECIAL_ERROR_CODE);
    }
}

The idea is to only use a LogData receipt if needed. The old revert behavior would be preserved, while also allowing reverting with “complex” error codes (enums for example).

7 Likes

I like @mohammadfawaz s suggestion.
It seems like it achieves what @Reimao is asking for, allowing the more idiomatic match pattern to be used, while preserving the existing usage of both revert and require.

2 Likes

Created this issue in the Sway repo.

5 Likes

Great suggestion! Wrapping revert to allow logging without evaluating conditions would definitely improve ergonomics and clarity. I like the idea of adding a generic revert<T>(code: T) function to make it more flexible and aligned with Sway’s style. This approach strikes a good balance between keeping the existing functionality and enabling more idiomatic usage in the codebase.