Implementation:Mlc ai Mlc llm Result Type
Overview
The Result type header at cpp/support/result.h defines a generic Result<T, E> class template that represents either a successful value of type T or an error of type E. This is a lightweight implementation of the Result/Either pattern commonly used in Rust and functional programming, enabling MLC LLM functions to signal success or failure without relying on exceptions.
Purpose
The Result class provides a structured way to handle operations that may fail. Instead of throwing exceptions (which can be costly in performance-critical code paths), functions return a Result object that the caller must explicitly inspect. This pattern is used extensively in the JSON parser utilities and other validation-heavy areas of MLC LLM.
Class Template
template <typename T, typename E = std::string>
class Result {
public:
static Result Ok(T value);
static Result Error(E error);
bool IsOk() const;
bool IsErr() const;
T Unwrap();
E UnwrapErr();
};
The error type E defaults to std::string, meaning that in the common case, error information is conveyed as a human-readable message.
Factory Methods
Ok
static Result Ok(T value) {
Result result;
result.ok_value_ = std::move(value);
return result;
}
Creates a Result containing a successful value. The value is moved into the internal storage.
Error
static Result Error(E error) {
Result result;
result.err_value_ = std::move(error);
return result;
}
Creates a Result containing an error. The error value is moved into the internal storage.
Query Methods
| Method | Description |
|---|---|
IsOk() |
Returns true if the result holds a successful value.
|
IsErr() |
Returns true if the result holds an error value.
|
Both are implemented by checking has_value() on the respective internal std::optional.
Unwrap Methods
Unwrap
T Unwrap() {
ICHECK(ok_value_.has_value()) << "Cannot unwrap result on an error value.";
ICHECK(!unwrapped_) << "Cannot unwrap a Result instance twice.";
unwrapped_ = true;
return std::move(ok_value_.value());
}
Extracts and returns the success value by move. Two safety checks are enforced:
- The result must actually contain a success value (not an error).
- The result must not have been previously unwrapped (enforcing single-use semantics).
UnwrapErr
E UnwrapErr() {
ICHECK(err_value_.has_value()) << "Cannot unwrap result on an okay value.";
ICHECK(!unwrapped_) << "Cannot unwrap a Result instance twice.";
unwrapped_ = true;
return std::move(err_value_.value());
}
Extracts and returns the error value by move, with the same single-use enforcement.
Internal Representation
| Member | Type | Description |
|---|---|---|
unwrapped_ |
bool |
Flag preventing double unwrapping. Initialized to false.
|
ok_value_ |
std::optional<T> |
Holds the success value when present. |
err_value_ |
std::optional<E> |
Holds the error value when present. |
The use of two separate std::optional fields ensures that success and error states are independent. A Result should never have both set simultaneously.
Usage Example
A typical usage pattern (as seen in json_parser.h):
Result<picojson::object> result = ParseToJSONObjectWithResultReturn(json_str);
if (result.IsErr()) {
// Handle error: result.UnwrapErr() returns the error message
LOG(ERROR) << result.UnwrapErr();
return;
}
picojson::object obj = result.Unwrap();
Dependencies
tvm/runtime/logging.h-- ProvidesICHECKmacros for runtime assertions.<optional>-- Standard library optional for storing success/error values.<string>-- Default error type.
File Location
- Source file:
cpp/support/result.h - Namespace:
mlc::llm - Header guard:
MLC_LLM_SUPPORT_RESULT_H_