Sunday, October 30, 2016

bool + messages = uiRetVal

Often you need to return whether something worked or not. If it didn't, you need to provide a message. That message may actually be a series of messages. And all users need to be able to understand it, also those that cannot read English. In short, you want to return:
  1. The status (OK/Fail)
  2. One or more uiString's if the operation failed
We see this a lot in current code:
uiString errmsg;
if ( !myobj.doIt( errmsg ) )
   uiMSG().error( errmsg );
The new way is to use a uiRetVal. It is implemented as a set of uiStrings. OK means the list is empty. It's really simple. In new interfaces I now routinely use this object, and it works really well. Above example would become:
uiRetVal rv = myobj.doIt();
if ( rv.isError() )
    uiMSG().error( uirv );
Advantages:
  • uiRetval tells you OK/Fail but also has any number of messages with it
  • You cannot 'forget' setting the error message(s)
  • It works really smooth.
Example from the trenches:

uiRetVal Well::Saver::doStore( const IOObj& ioobj ) const
{
    uiRetVal uirv;
    ConstRefMan wd = wellData();
    if ( !wd )
        return uirv; // all OK, that's uiRetVal's default

    Writer wrr( ioobj, *wd );
    const StoreReqs sreqs = curstorereqs_.getObject();
    if ( sreqs.isAll() )
    {
        if ( !wrr.put() )
            uirv.add( wrr.errMsg() );
    }
    else
    {
        if ( sreqs.includes(Trck) && !wrr.putInfoAndTrack() )
            uirv.add( wrr.errMsg() );
        if ( sreqs.includes(D2T) )
        {
            if ( !wrr.putD2T() )
                uirv.add( wrr.errMsg() );
            else if ( wd->haveCheckShotModel() && !wrr.putCSMdl() )
                uirv.add( wrr.errMsg() );
        }
        if ( sreqs.includes(Mrkrs) && !wrr.putMarkers() )
            uirv.add( wrr.errMsg() );
        if ( sreqs.includes(Logs) && !wrr.putLogs() )
            uirv.add( wrr.errMsg() );
        if ( sreqs.includes(DispProps) && !wrr.putDispProps() )
            uirv.add( wrr.errMsg() );
    }

    curstorereqs_.getObject() = StoreReqs::All();
    return uirv;
}