My false expectation about fn that returns an opt type

It looks strange to me that function that marked as a returning opt value one, can return only non-opt value.

Consider this code:

const print = @import("std").debug.print;

const S = struct {
    i: usize,
};

fn createOpt() ?S {
    return .{ .i = 1 };
}

pub fn main() void {
    const opt_s = createOpt();
    print("opt: {?}, typeOf={}\n", .{ opt_s, @TypeOf(opt_s) });
}

It should be clear to the compiler that createOpt fn can not produce an opt value, so why do not report about that?

(hmm, while writing it I think that type coercion is somehow involved, isn’t it?)

You might need to return an optional in order to satisfy some kind of interface.

I mean, why in my example compiler will not complain about unsatisfied return type of createOp fn?

What do you mean “unsatisfied return type”?

What I understood was that since the function never returns null, according to you the compiler should complain about the return type being an optional. Did I get this right?

If so, this would mean that you can’t use this function as you would a fn () ?S, which could be required by some kind of interface. It’s the same reason you can discard parameters from the function prototype: fn (_: UnusedParam) void.

1 Like

I also understood this was the question, but i didnt understand the explanation you gave

For example this:

pub fn Iterator(comptime Inner: type, comptime Item: type, comptime nextFn: fn (*Inner) ?Item) type {
    return struct {
        inner: Inner,
        
        const Self = @This();

        pub fn next(self: *Self) ?Item {
            return nextFn(&self.inner);
        }

        ...
    };
} 

The Iterator interface expects a fn (...) ?Item function. If the compiler were to forbid you to return ?Item because it never returns null, you would never be able to use this interface with your function.

Now I never have seen an iterator that can’t be entirely consumed, so maybe this example isn’t the best. But it illustrates that disallowing coercion a “wider” type would unintentionally disallow many kind of interfacing.

2 Likes

got it! thanks

oh, makes sense, ty