Add Null option to Result?


#1

Result can return something, or an error. But, what if you want to return that there is nothing? You might return that as an error, but nothing really went wrong. Or you could return it as a reserved value, but then you have to reserve a value, which is what this struct is meant to mitigate. I’m just starting Rust and remembered this from a talk about the Mill CPU architecture http://youtu.be/DZ8HN9Cnjhc?t=47m36s . Should we distinguish between nothing and an error? Should there even be another option for invalid data so you could return a valid value, an invalid value, an empty value, or an error retrieving the value?
Imo it makes sense to, and it adds no overhead I can think of. Opinions?


#2

You didn’t say why Result<Option<T>, Error> doesn’t work for you.


#3

I’m new, so I didn’t even know about Option, but that would definitely work. It does increase the size of the Result to 12 bytes rather than 8 (storing an i32) with the some/none directly in Result, likely not a big issue, but it adds indirection. I think we should merge Option and Result because they’re both intended to be ways to represent a value that may or may not be valid, Option doesn’t have an invalid field, and Result doesn’t have a nothing field (w/o containing each other). Is there any reason why they shouldn’t be merged (other than existing code needing some changes)?


#4

They should not be merged because it increases the number of types in Rust to remember. But hopefully someday the compiler will optimize strict and enum layouts. This is a complicated because of the transmute function that relies on the normal unoptimized layout.


#5

I don’t think you can say a lot about this Result's size not knowing the sizes of T and Error. Find it for specific types maybe? I’d expect Option to add either 1 byte or none to the size. The representation of Result<Option<... could probably be optimized without changing any types.


#6

Actually you’re right, Result< Option> or using a different enum does make sense b/c it wouldn’t always make sense to return nothing. The size doesn’t really matter especially b/c of the optimization you mentioned, but for i32 it was 8 w/o Option, 12 w/, and i64 was 16 w/o Option and 24 w/. Option probably uses only 1 byte, but the alignment causes more since I was measuring it with an array. And if the optimization removes that, Result< Option> is probably best. So, nvm, and thanks.


#7

A custom enum type might be your best fit. Those are commonly used everywhere.


#8

Don’t try this at home, but in my code snippet below I distinguish between iterations over valid elements in an array (by returning null 0x0) and when the iterator runs out of elements in the array and has a null pointer (by returning an error). I’m yet to discover a purpose for it.

use std::old_io;

// Import Pointers (for creation of null)
use std::ptr;

fn main() {
    try_null();
}

fn try_null() {

    let my_null: *const i32 = ptr::null();

    let mut range = 0..2;

    loop {
        match range.next() {
            Some(iteration) => {
                // outputs 0x0
                println!("Iteration {} of null: {:?}", iteration, my_null);
            },
            None => {
                panic!("Panicked since no more elements in the array");
            }
        }
    }

}