Is there a way to get the return type of the containing function?

Just like @This() return the namespace type, I fail to find a @Result() function which returns the containing function return type. What is the reason it is not supported yet?

In what context would you need this? I can’t think of any situation where you don’t know the type of the containing function.

If you had a situation where the return type changes based on the input types, it would sometimes be convenient to be able to reference the function return type rather than copy the return type and paste it inside the function. Another solution which would reduce code bloat/duplication is to allow an anytype return type, although I heard that Zig doesn’t support that anymore because it was difficult to implement so it’s being put off.

1 Like

I suppose you could just alias the return type at the top of the function, but actually you can see an example of a type changing based on input to a generic type in std.ArrayListAligned:

// lots of code cut out of here...
pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
    return struct {
        pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
        pub fn allocatedSlice(self: Self) Slice { ... }
        pub fn toOwnedSlice(self: *Self) Allocator.Error!Slice { ... }

    };
}
1 Like

You can also invoke the function itself and get its own return type:

fn foo(x: usize) usize {
    const y: @TypeOf(foo(x)) = 42;
    return y;
}

Works in certain circumstances - you can actually get pretty crazy with this.

9 Likes

An example:

    const spanMarksTable = struct{
        fn run() [256]?struct{markType: tmd.SpanMarkType, precedence: u3} {
        	var table: [256]?struct{markType: tmd.SpanMarkType, precedence: u3} = .{null} ** 256;
			...
			return table;
        }
    }.run();

It would be great to write it as

    const spanMarksTable = struct{
        fn run() [256]?struct{markType: tmd.SpanMarkType, precedence: u3} {
        	var table: @Result() = .{null} ** 256;
			...
			return table;
        }
    }.run();

My first thought would be to extract the struct in the return type, but you can also use @AndrewCodeDev’s trick:

        var table: @TypeOf(run()) = .{null} ** 256;
3 Likes

Aha, I never thought of that. Thanks all for the replies.

I like that it works, but I also think using this casually is cursed.

Just give your long struct a name and use that name twice instead, much more expected and easier to understand.

4 Likes

I do like the trick for this specific case, for that type is not referenced elsewhere.

I think using it will confuse beginners.

This seems more obvious to me:

const spanMarksTable = struct{
    const Table = [256]?struct{markType: tmd.SpanMarkType, precedence: u3}; 
    fn run() Table {
    	var table: Table = .{null} ** 256;
        ...
        return table;
    }
}.run();

Might even use:

var table: Table = .{null} ** @as(Table, undefined).len;
2 Likes

In this instance, I’m in agreement with @Sze - I personally would factor it out and use it as a named type.

This technique is legitimate, but I wouldn’t use it to skip naming types. You can get weird diagnostic messages because we’re not naming the type (although, anything from anonymous structs are weird to read).

Again, it does answer the question “is there a way to get the return type of the containing function?” but I’d use it sparingly and not as a way to avoid naming types.

3 Likes

You also could write a function, but this can give you cursed names for types:

const std = @import("std");

pub fn Result(comptime func: anytype) type {
    return @typeInfo(@TypeOf(func)).Fn.return_type.?;
}
pub fn foo() void {
    std.debug.print("{any}\n", .{Result(foo)});
}

pub fn main() !void {
    std.debug.print("{any}\n", .{Result(main)});
    foo();
}

This prints:

@typeInfo(@typeInfo(@TypeOf(getresult.main)).Fn.return_type.?).ErrorUnion.error_set!void
void
1 Like

Cool!

But why return_type.??
Doesn’t every function have a return type?

return_type is null when it’s determined dynamically based on the arguments given to the function. Example:

fn add(a: anytype, b: anytype) @TypeOf(a) {
    return a + b;
}
3 Likes
/// x is a function type
inline pub fn return_type(x: anytype) type {
  return @typeInfo(@TypeOf(x)).Fn.return_type.?;
}
1 Like
pub inline fn return_type

works.

It looks the inline function modifier and comptime parameter modifier are both not required. Are there any actual differences when the two modifiers are used?

no. you’re right. inline is a runtime thing and would be totally unneeded (doesnt even make sense) for a comptime only function.

I thought I could get away with just typing it in and not using godbolt or the compiler to check since it wasn’t tha difficult of a function – oops. sry.

2 Likes