Multiple captures for tuples

Today, I had code where a function returns an id for something and a pointer. I just wanted to quickly return two values without fuss.

I initially wrote something like:

fn get() std.meta.Tuple(&.{ThingId, *Thing}) {
	...
	return .{123, &moo};
}

Then, crossing my fingers

fn foo() {
	if (get()) |id, thing| {
		bar(id, thing);
	}
}

error: expected '|', found ','

The closest I can have with tuples is the ugly:

fn foo() {
	if (get()) |elems| {
		bar(elems[0], elems[1]);
	}
}

So, I ended up with the clear, but verbose

const IdentifiedThing = struct {
	id: ThingId,
	thing: *Thing,
};

fn get() ?IdentifiedThing {
	...
	return .{.id = 123, .thing = &moo};
}

fn foo() {
	if (get()) |idthing| {
		bar(idthing.id, idthing.thing);
	}
}

I wonder if this capture syntax has been considered. I realise that for is unusual in that it can have multiple conditions so deserves multiple captures, but that’s what made me think it might be valid.

I guess that the counter argument is that if the tuple elements had the same type, then it would be too easy to swap the elements accidentally?

1 Like
fn get() struct { usize, usize } {
    return .{ 5, 7 };
}

pub fn main() void {
    const a, const b = get();
    std.debug.print("{} {}", .{ a, b });
}
10 Likes

Well, I’ve learnt something new! Thanks

1 Like

I realise I mistyped in my question.

Can the pattern const a, const b = get() still work when there’s an option involved?

fn get() ?std.meta.Tuple(&.{ThingId, *Thing}) {...}
if (get()) |thing| {
    const a, const b = thing;
    std.debug.print("{} {}", .{ a, b });
}
3 Likes