Autodesk Maya’s MStatus with exceptions

The API of Autodesk Maya is very powerful, but also a bit cumbersome to use due to its age and extremely conservative design. One of its code features is the use of the MStatus class to handle error states — almost all API calls either return or accept a pointer to an MStatus instance. In other Maya’s APIs (Python and .NET), the same functionality is implemented using more “modern” exceptions.

In this post I’d like to explain an approach that addresses specifically the way Maya uses MStatus objects, and how to convert them into exceptions using a proxy class.

Handling errors in C/C++

Using a status code is a common practice for low-level C libraries. In more modern C++, its use has its own advantages and disadvantages.

For C++ code, I prefer exceptions:

  • the resulting code is more concise and arguably easier to read without explicit error handling for each line
  • exceptions are compatible with modern programming methods, like the standard library and boost
  • exceptions cannot be overlooked or ignored (not handling an exception leads to exception propagation; not handing a status code leads to silent failures)
  • handling of error states is supported in core language, with its behaviour and state of the system after an error implicit and well-defined (status codes can only guarantee correct error handling with extremely rigorous programming style)

When using a 3rd-party API, the programmer doesn’t have a vote in the matter. Problems start when a project needs to use a combination of multiple APIs, some handling errors by exceptions and some by status codes — a situation all too common in practice. The only way out is to wrap all API calls of a library that uses one approach to mimic the other:

  • either wrap a status returning API calls in an if-statement that throws an exception on error,
  • or wrap all throwing API calls in a try...catch block and convert them into exceptions.

Error handling using Maya’s MStatus class

Maya’s MStatus class is a very simple class holding a status code (a value from MStatus::MStatusCode enum) and a string error message. In an API call succeeds, it returns an MStatus value of MStatus::kSuccess = 0. On failure it has one of the other enum values, and fills the error message with a human-readable error string.

There are two main types of API calls working with MStatus — returning an MStatus instance, and taking a non-constant pointer to an MStatus instance. In both cases, testing the value (and the success of related API call) is optional. Unfortunately, in practice most programmers ignore the MStatus value in cases that are unlikely to fail (i.e., most of the time), and only add explicit error checks when a part of their code doesn’t work as expected. For obvious reasons, this leads to fragile code with a high possibility of silent failure.

Returning MStatus

If a function or method does not need to return any other value, in Maya’s API it often returns an MStatus instance instead. Using the comparison operators of the class, we can perform error checking of the returned value:

Maya’s API provides a CHECK_MSTATUS macro (in several flaviour), which essentially does the same. Most of the examples shipped with Maya’s API use a variant called MCheckErr:

While a custom macro of this kind allows to simplify the code significantly, the requirement of the status value to be used only once means that it is tricky to implement when we are interested in the error message text the API call returned (the implementation provided by Autodesk discards the error message).

Passing a pointer to an MStatus instance

In some cases, when returning a value from a function is preferable to allow call nesting, the API allows the programmer to pass in a pointer to an
existing MStatus instance:

In this case, every statement requires two lines of code, making it significantly longer and harder to read. However, as it is possible to re-use the status value, we can also return the original error message produced by the failing API call.

Converting MStatus to an exception

The macro-based approach can be easily converted to throw an exception. In this case, all exceptions have to be caught before the highest-level function exists — leaking exceptions to Maya would lead to unpredictable behaviour at best. However, exceptions allow to use the same approach for both 3rd-party exception-based libraries and Maya’s native status-code-based API calls.

To simplify and shorten the error-checking code, we can use a proxy class – a simple class with operators allowing to replace both the return values and MStatus pointers with a class instance.

A proxy class

A simple class, implementing an assignment operator and an MStatus* type-conversion operator, can be used in place of both possibilities used by Maya’s API:

To convert the result into an exception, we can throw from a destructor:

While in general, throwing exceptions from a destructor is not a great idea, in the case of exception-free Maya’s API and a simple proxy class not held in a container, it will not lead to any issues.

Using a proxy class

The use of our proxy class is quite simple – just create a new instance in place of any of the MStatus or MStatus* instances:

All such calls have to be wrapped in a try...catch block to avoid leaking exceptions into Maya.

Wrapping in a macro

In practice, the proxy class can be wrapped in a macro, which can add additional debugging information. E.g.:

Conclusion

Wrapped in a macro, a proxy class eliminates a large amount of ballast code, provides a consistent exception-based error checking compatible with other libraries using exceptions, and just generally makes the coding experience with Maya API much more pleasant. A similar approach can be often used with many other libraries that use status codes for their error states, allowing to use only one consistent exception-driven error mechanism.

A full implementation of the exception-throwing MStatus proxy class I use looks like this: