It would be nice if libmexclass provided a mechanism for clients to throw MATLAB-facing errors without forcing clients to call feval via the MATLABEngine themselves.
Required Changes
Add a struct called libmexclass::error::Error that has two fields: id and message.
Add a field named error to libmexclass::proxy::method::Context, which is passed to all proxy method classes. This field should be a std::optional<libmexclass::error::Error>. By default, error will be a nullopt. If clients want libmexclass to throw a MATLAB-facing error, they should set this field to a non-nullopt value in their proxy class methods. Here's an example of this workflow in example/proxy/Car.cpp:
void Car::SetSpeed(libmexclass::proxy::method::Context& context) {
matlab::data::TypedArray<uint64_t> speed_mda = context.inputs[0];
const std::uint64_t speed = uint64_t(speed_mda[0]);
if (speed > 100) {
// force libmexclass to throw an error if the desired speed is greate than 100
context.error = libmexclass::error::Error{"Car:Speed:TooFast", "Slow down!!"};
return;
}
car.SetSpeed(speed);
}
Change the return value of libmexclass::action::Action::execute() from void to std::optional<libmexclass::error::Error. Update the execute() of the concrete subclasses of Action (i.e. Create, Delete, MethodCall) to return the error field stored on the context.
In the gateway function, capture the return value of action->execute(). If return value is not a nullopt, throw a MATLAB-facing error using feval. The error id and message should be taken from the id and message fields of the libmexclass::error::Error struct returned by execute(). Here's what this will look like:
libmexclass::proxy::MakeResult is a typedef to std::variant<std::shared_ptr<libmexclass::proxy::Proxy>, libmexclass::error::Error>.
Here's an example of this workflow in example/proxy/Car.cpp:
libmexclass::proxy::MakeResult make(const libmexclass::proxy::FunctionArguments& constructor_arguments) {
const std::string make = convert(constructor_arguments, 0);
const std::string model = convert(constructor_arguments, 1);
const std::string color = convert(constructor_arguments, 2);
// return an error if one of the strings is empty
if (make.empty() || model.empty() || color.empty()) {
return libmexclass::error::Error{"libmexclass:example:Car:EmptyInputs", "Inputs make, model, and color must be nonempty"};
}
// otherwise construct the proxy class and return it
return std::make_shared<example::proxy::Car>(make, model, color);
}
Change the return type of libmexclass::proxy::Factory::make_proxy() from void to libmexclass::proxy::MakeResult
In the Create::execute() update the code to check if the variant returned contains a std::shared_ptr<libmexclass::proxy::Proxy> or a libmexclass::error::Error. If it has a libmexclass::error::Error, return the error. Otherwise, add the proxy to the manager and return a nullopt.
OLD DESCRIPTION
To enable error-handling, we should consider making all the methods of ProxyManager return some sort of Result or Status object. The callers of these functions (libmexclasss::action::Create, libmexclass::action::Destroy) would be responsible for throwing exceptions in MATLAB.
The advantage of this approach is that ProxyManager would not need to know anything about the MATLABEngine.
NEW DESCRIPTION
Summary
It would be nice if
libmexclass
provided a mechanism for clients to throw MATLAB-facing errors without forcing clients to callfeval
via theMATLABEngine
themselves.Required Changes
Add a struct called
libmexclass::error::Error
that has two fields:id
andmessage
.Add a field named
error
tolibmexclass::proxy::method::Context
, which is passed to all proxy method classes. This field should be astd::optional<libmexclass::error::Error>
. By default,error
will be anullopt
. If clients wantlibmexclass
to throw a MATLAB-facing error, they should set this field to a non-nullopt
value in their proxy class methods. Here's an example of this workflow inexample/proxy/Car.cpp
:Change the return value of
libmexclass::action::Action::execute()
fromvoid
tostd::optional<libmexclass::error::Error
. Update theexecute()
of the concrete subclasses ofAction
(i.e.Create
,Delete
,MethodCall
) to return theerror
field stored on thecontext
.In the
gateway
function, capture the return value ofaction->execute()
. If return value is not anullopt
, throw a MATLAB-facing error usingfeval
. The error id and message should be taken from theid
andmessage
fields of thelibmexclass::error::Error
struct returned byexecute()
. Here's what this will look like:REGISTER_PROXY
macro to the following:This requires all proxy classes to define a a static make function:
libmexclass::proxy::MakeResult
is a typedef tostd::variant<std::shared_ptr<libmexclass::proxy::Proxy>, libmexclass::error::Error>
.Here's an example of this workflow in
example/proxy/Car.cpp
:Change the return type of
libmexclass::proxy::Factory::make_proxy()
fromvoid
tolibmexclass::proxy::MakeResult
In the
Create::execute()
update the code to check if the variant returned contains astd::shared_ptr<libmexclass::proxy::Proxy>
or alibmexclass::error::Error
. If it has alibmexclass::error::Error
, return the error. Otherwise, add the proxy to the manager and return anullopt
.OLD DESCRIPTION
To enable error-handling, we should consider making all the methods of
ProxyManager
return some sort ofResult
orStatus
object. The callers of these functions (libmexclasss::action::Create
,libmexclass::action::Destroy
) would be responsible for throwing exceptions in MATLAB.The advantage of this approach is that
ProxyManager
would not need to know anything about theMATLABEngine
.