# Storing an std.fs.File as the result of a conditional expression?

**URL:** <https://ziggit.dev/t/storing-an-std-fs-file-as-the-result-of-a-conditional-expression/13330>\
**Category:** Help\
**Tags:** language, compiler\
**Created:** [December 3, 2025, 3:47am UTC](https://ziggit.dev/t/storing-an-std-fs-file-as-the-result-of-a-conditional-expression/13330 "2025-12-03T03:47:40Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Quin](https://ziggit.dev/user_avatar/ziggit.dev/quin/32/7147_2.png) [@Quin](https://ziggit.dev/u/Quin)\
**Post date:** [December 3, 2025, 3:47am UTC](https://ziggit.dev/t/storing-an-std-fs-file-as-the-result-of-a-conditional-expression/13330/1 "2025-12-03T03:47:40Z")

</div>

Hi,  
I’m trying to write a basic CLI app that either reads from stdin, or a filename passed on the command line. However, this super basic code doesn’t work using Zig 0.15.2, telling me that I don’t use the result of std.fs.File.stdout() for some reason. What am I doing wrong?

```zig
const std = @import("std");

pub fn main() !void {
    const allocator = std.heap.page_allocator;
    var args = try std.process.argsWithAllocator(allocator);
    defer args.deinit();
    if (!args.skip()) unreachable;
    if (args.next()) |arg| {
        const file = if (std.mem.eql(u8, arg, "-")) {
            std.fs.File.stdout();
        } else {
            std.fs.cwd().openFile(arg, .{});
        };
        _ = file;
    }
}

```

Compiler output:

```zig
test.zig:10:31: error: value of type 'fs.File' ignored
            std.fs.File.stdout();
            ~~~~~~~~~~~~~~~~~~ ^~
test.zig:10:31: note: all non-void values must be used
test.zig:10:31: note: to discard the value, assign it to '_'
referenced by:
    callMain [inlined]: .zvm/0.15.2/lib/std/start.zig:627:37
    callMainWithArgs [inlined]: .zvm/0.15.2/lib/std/start.zig:587:20
    posixCallMainAndExit: .zvm/0.15.2/lib/std/start.zig:542:36
    2 reference(s) hidden; use '-freference-trace=5' to see all references

```

Thanks in advance!

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [December 3, 2025, 3:55am UTC](https://ziggit.dev/t/storing-an-std-fs-file-as-the-result-of-a-conditional-expression/13330/2 "2025-12-03T03:55:36Z")

</div>

In zig blocks `{}` don’t return values implicitly, you can either label them and use a `break` eg `label: { break :label foo; }`

```zig
const file = if (std.mem.eql(u8, arg, "-")) file: {
            break :file std.fs.File.stdout();
        } else file: {
            break :file try std.fs.cwd().openFile(arg, .{});
        };

```

Or you can also generally remove them.

```zig
const file = if (std.mem.eql(u8, arg, "-"))
            std.fs.File.stdout()
         else 
            try std.fs.cwd().openFile(arg, .{});

```

Except labelled blocks, `;` will only appear at the end of a statement, and not _within_ the expression. That’s why there is only a `;` at the end.

ps: for loops the label appears before the `while`/`for` keyword, elsewhere the label is immediately before the `{}`.

pps: label can appear before the `switch` keyword, or in individual branches, if the branch has a block. the latter is normal, but the former is a little special, see [labelled switch](https://ziglang.org/documentation/master/#Labeled-switch).

---

<div class="post-metadata">

**Author:** ![Quin](https://ziggit.dev/user_avatar/ziggit.dev/quin/32/7147_2.png) [@Quin](https://ziggit.dev/u/Quin)\
**Post date:** [December 3, 2025, 3:57am UTC](https://ziggit.dev/t/storing-an-std-fs-file-as-the-result-of-a-conditional-expression/13330/3 "2025-12-03T03:57:59Z")

</div>

Ah, I see! Very nice, thank you! Now the ability to break out of an if statement with a label makes much more sense… 😉

---

<div class="post-metadata">

**Author:** ![Quin](https://ziggit.dev/user_avatar/ziggit.dev/quin/32/7147_2.png) [@Quin](https://ziggit.dev/u/Quin)\
**Post date:** [December 3, 2025, 3:01pm UTC](https://ziggit.dev/t/storing-an-std-fs-file-as-the-result-of-a-conditional-expression/13330/5 "2025-12-03T15:01:24Z")

</div>

I think they’re actually correct as far as the semicolon placement goes, and when I think about it it makes sense. Consider this:

```zig
const x = if (my_condition) "yes" else "no";

```

Putting a semicolon after the first string would just be confusing and break the parser.

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [December 3, 2025, 11:13pm UTC](https://ziggit.dev/t/storing-an-std-fs-file-as-the-result-of-a-conditional-expression/13330/6 "2025-12-03T23:13:38Z")

</div>

I _explicitly_ didn’t say anything about `;` in relation to labels. Just noted them as **not** what I was talking about.

> [@vulpesx](#):
>
> Except labelled blocks, `;` will only appear at the end of a statement, and not _within_ the expression. That’s why there is only a `;` at the end.

But to be pedantic, blocks **are** expressions (especially labelled blocks), and they are unique in that they are the only expression which can contain `;` in the middle of them.  
It makes sense, as they are a sequence of statements, which always end with a `;`.

So they **are** an exception to what I was talking about.

You might say that type/function definitions can contain `;` even though they are expressions. But the ones that do allow that do so in a `{}`. Though I concede, they do count as expressions separate from blocks.

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [December 3, 2025, 11:28pm UTC](https://ziggit.dev/t/storing-an-std-fs-file-as-the-result-of-a-conditional-expression/13330/8 "2025-12-03T23:28:23Z")

</div>

like this ‘except foo, blah blah blah’

explicitly states ‘blah blah blah’ is not about ‘foo’
