Possible to write own version of `?` operator or some equivalent macro?

Hello,

Firstly, am loving Rust so far!!

I have get_id_point() which returns a result. Any way to reduce the boilerplate code when calling it?

fn get_id_point(id: i32, x: i32, y: i32) -> Result<(Id, Point), &'static str> {
        let id = Id::from(id)?;
        let point = Point::from(x, y)?;
        Ok((id, point))
}

// example function which uses get_id_point(), but eventually will be many functions
#[no_mangle]
pub unsafe extern "C" fn place(id: i32, x: i32, y: i32) -> i32 {
    let (id, pos) = if let Ok((id, pos)) = get_id_point(id, x, y) {
        (id, pos)
    } else {
        return -1;
    };
    // ... 
    0 // everything good, return 0
}

Is there a better approach where with one line I either get back the tuple or I return early with a -1?

Many thanks for your support!

Sure.

macro_rules! int_try {
    ($value:expr) => {
        match $value {
            Ok(out) => out,
            Err(_) => return -1,
        }
    };
}

#[no_mangle]
pub unsafe extern "C" fn place(id: i32, x: i32, y: i32) -> i32 {
    let (id, pos) = int_try!(get_id_point(id, x, y));
    0
}

Damn Alice, you make programming look easy!

Thank you!

1 Like

The ? operator started life as the try!() macro, Welsh basically looked like this.

which?

Yes

Coming back to this, could someone point me towards how to override the ? Operator to do the same?

Refer to https://doc.rust-lang.org/std/ops/trait.Try.html
This is currently unstable to implement, IIRC

1 Like

Note that if you do want to use ? for this, you'll need to make a repr(transparent) wrapper for i32, because you're not allowed to impl Try for i32 (as you're not the standard library).

1 Like

A transparent wrapper is something I did for HRESULT while experimenting with Windows FFI, which is just a typedef for i32 in C. Though I've been wondering if Result<(),NonZeroI32> could have the same layout.

Given S_FALSE, I'm not sure that's semantically correct.

Certainly some sort of Result<NonNegativeI32, StrictlyNegativeI32> could be made to work, but I'm pretty sure Rust's current layout doesn't support overlaying things like that.

Now if only we had custom patterns...

S_FALSE indicates success. It's not often used but when it is it usually means that the function returned successfully but it may not have needed to actually do anything.

As you say, Result<(),NonZeroI32> is still wrong for HRESULT.

Yes, something like Result<i32,HRESULT> or an equivalent is just as usable, and I wrote a method .result() to return that, so I could write .result()? and also impl Error for HRESULT.

Along the way I ended up trying to understand variants, before deciding I had better things to do.

Yeah, the correct way to handle this would to use a hypothetical Result<PositiveI32, NegativeI32> (where 0 is positive). But that's not currently possible. Or at least it's not currently possible to have the layout optimized to a single i32.

I guess the main problem is that the Result type is special but it is limited in terms of specifying the layout. The Try trait mention above will help but doesn't totally address the issue.