Skip to content

fmt.formatType() doesn't know about (undefined) #8521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mlawren opened this issue Apr 13, 2021 · 9 comments
Closed

fmt.formatType() doesn't know about (undefined) #8521

mlawren opened this issue Apr 13, 2021 · 9 comments
Milestone

Comments

@mlawren
Copy link

mlawren commented Apr 13, 2021

const std = @import("std");
const Empty = struct {
    pub const UNDEF = undefined;
};
test "struct namespaced variable" {
    std.debug.print("{}\n", .{Empty.UNDEF});
}
zig-linux-x86_64-0.7.1/lib/std/fmt.zig:502:17: error: Unable to format type '(undefined)'
        else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
                ^
zig-linux-x86_64-0.7.1/lib/std/fmt.zig:195:35: note: called from here
                    try formatType(
                                  ^
zig-linux-x86_64-0.7.1/lib/std/io/writer.zig:33:34: note: called from here
            return std.fmt.format(self, format, args);
                                 ^
zig-linux-x86_64-0.7.1/lib/std/debug.zig:67:27: note: called from here
    nosuspend stderr.print(fmt, args) catch return;
                          ^
./x.zig:6:20: note: called from here
    std.debug.print("{}\n", .{Empty.UNDEF});
                   ^
./x.zig:5:35: note: called from here
test "struct namespaced variable" {
                                  ^
@mlawren mlawren changed the title fmt.formatType doesn't know about (undefined) fmt.formatType() doesn't know about (undefined) Apr 13, 2021
@marler8997
Copy link
Contributor

I'm having a hard time coming up with a use case for why someone would want to print undefined. Do you have one?

@marler8997
Copy link
Contributor

It looks like you can't even pass undefined to an anytype parameter so that kinda rules out using it in any generic code that I was thinking might use it this way. Because of this, I believe this is as designed and not an issue. Feel free to close this issue unless you have some sort of use case that demonstrates how this would be used.

@ikskuh
Copy link
Contributor

ikskuh commented Apr 14, 2021

@mlawren: undefined isn't a value in zig like in other languages like JavaScript. I've seen you created two issues about undefined where both can be explained with the same answer:

undefined isn't a value but the information to not initialize a certain value. This is a statement to the compiler that you don't care for the value in that variable at all, either because it is never read (reading a undefined value is illegal behaviour) or because you will initialize it at a later pointer, but you already need the address to take a pointer:

// case 1:
const Point = struct {
    x: u32,
    y: u32,
};

var pt1 = Point { .x = 10, .y = undefined };
var pt2 = Point { .x = 20, .y = undefined };
return pt1.x == pt2.x;
// we never touch .y, so we can leave it undefined
// case 2:
const Ring = struct {
    value: u32,
    next: *Ring,
};

var r1 = Ring {
    .value = 1,
    .next = undefined, // we are not able to fill this yet
};
var r2 = Ring {
    .value = 2,
    .next = &r1,
};
r1.next = &r2; // now we can fill this "hole" in the data structure

Also note that you are not allowed to compare to undefined (like in #8520). This should be a compile error.

@mlawren
Copy link
Author

mlawren commented Apr 14, 2021

Thanks for the replies and the education - yes, I'm new to Zig. The use case here is simply debugging while I am learning, but I can also imagine wanting to check if a value as been assigned or not in more complicated code paths.

@andrewrk
Copy link
Member

If you want to be able to check, use optional types: https://ziglang.org/documentation/master/#Optionals

@andrewrk andrewrk added this to the 0.8.0 milestone Jun 4, 2021
@correabuscar
Copy link

correabuscar commented Sep 2, 2022

I'm new to zig too, got this while learning(or attempting to learn by doing after watching this video https://www.youtube.com/watch?v=I2E-9jSsxcM ):

undef-tst.zig:

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

pub fn main() !void {
    const undef = undefined;
    print("Hi! {s}\n", .{undef});
}
$ zig fmt undef-tst.zig ;echo $?
0
$ zig run undef-tst.zig 
/usr/lib/zig/std/fmt.zig:722:17: error: unable to format type '@TypeOf(undefined)'
        else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"),
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I'm kinda surprised that this isn't gonna get fixed or something...

EDIT: aww man, I thought zig was better:

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

pub fn main() !void {
    const u: u8 = undefined; //XXX: if this becomes 'var' then no error below:
    var w: u8 = u + 1; // undef-tst.zig:7:17: error: use of undefined value here causes undefined behavior
    print("Hi! {}\n", .{u});
    print("Hi! {}\n", .{u == undefined}); // false
    print("Hi! {}\n", .{undefined == u}); // true
    // XXX: ^ wtf?
    //print("Hi! {}\n", .{undefined == undefined}); // error: operator == not allowed for type '@TypeOf(undefined)'  //This makes some sense.
    u = u + 1;
    print("Hi! {}\n", .{w});
}
$ zig zen

 * Communicate intent precisely.
 * Edge cases matter.
 * Favor reading code over writing code.
 * Only one obvious way to do things.
 * Runtime crashes are better than bugs.
 * Compile errors are better than runtime crashes.
 * Incremental improvements.
 * Avoid local maximums.
 * Reduce the amount one must remember.
 * Focus on code rather than style.
 * Resource allocation may fail; resource deallocation must succeed.
 * Memory is a resource.
 * Together we serve the users.

"version": "0.10.0-dev.3857+10e11b60e"

@ikskuh
Copy link
Contributor

ikskuh commented Sep 3, 2022

@correabuscar you cannot expect Zig to ever do anything meaningful with undefined, as it means the absence of initialization or value. It will just take whatever is in the registers/memory/... at the time. This is why using undefined at comptime is completly forbidden and any comparison with undefined is undefined behaviour (as you compare to literally something).

Please read my comment above. I assume you're coming from JavaScript world where undefined has a very very different meaning (it has its own type and defined value) whereas in Zig, it's the absence of both. Everything in Zig has to be typed and initialized, but sometimes initialization hurts the performance or is just unnecessary. This is where undefined comes into play.

I'm kinda surprised that this isn't gonna get fixed or something...

It will never change, because there's nothing to fix. Please read the language documentation to learn more about undefined

@correabuscar
Copy link

Thank you.

It will never change, because there's nothing to fix.

The fix I would've expected was a better compiler error message. Maybe something saying that using undefined in anything other than right-hand side assignment position (or initialization) as the only expression (eg. var x:u8=undefined+1; shouldn't be valid and I see it's already detected as such which is great: error: use of undefined value here causes undefined behavior) is not allowed (or is undefined behavior which isn't allowed because zig zen or something).

Heck, the compiler errors(verb) for simple things like unused variables, which is great in my opinion. But it somehow allows using undefined in places like comparisons without even a warning, not to mention an error?(ie. print("{}\n", .{u == undefined}); // false and print("{}\n", .{undefined == u}); // true, sometimes are allowed by compiler, no warn/error) I'm sorry but that just blows my mind a little.

I guess maybe it's not easy to restrict the use of undefined for initialization only, in the internals of zig. Or perhaps it can have other valid uses(ie. hmm, no idea of such uses yet) that I can't think of, outside of just right-hand side of the assignment as the only expression (ie. var x:u8=undefined;) and that's why it's not restricted to just initialization. But frankly, I'm afraid that the reason is that edge cases don't really matter in the way that I understood that they did from the Zen. At least they seem to not, in the internals of zig. Needless to say, I am disappoint, sad and somewhat mad too :) why? because where else would I ever find another language with this Zen?!! When I looked at Rust, it would error at runtime for a file-not-found and it would be hard to find out what the filename in question was(without modifying the source code and re-running it, and then hope to hit the issue again - but for easy errors like this it wouldn't be an issue, but what of those rare occurring runtime errors), as it wasn't included in the error, and wasn't visible in the source code either(ie. it was computed at runtime, and for some reason not embedded in the error or its message, and the real problem is that this was idiomatic rust code ie. you're supposed to do it like this). And this kind of superficial error reporting/handling is(or at least was, at the time) rampant in anything using Rust, apparently. Now I get to see this kind of thing with undefined in Zig and that: issues that are found in production are more likely to be fixed(or maybe I misunderstand, from CONTRIBUTING.md), rather than theoretical issues, and it makes me think that well it doesn't seem like edge cases matter then, now does it?

you cannot expect Zig to ever do anything meaningful with undefined,

Though I do expect the compiler to prevent me from using it outside of just initialization.
It seems it already does for some cases, but having to ban all cases instead of just saying: allow use only for initialization, seems akin to having a firewall with allow-all policy and selectively denying connections when needed instead of deny-all policy and allow when needed.

I assume you're coming from JavaScript world where undefined has a very very different meaning (it has its own type and defined value) whereas in Zig, it's the absence of both.

Seems to have a "type" though:

    const r: @TypeOf(undefined) = undefined;                                                                                                                      
    _ = r;

(I don't really know Javascript though, but I've stumbled upon its undefined, yes)

But please, I don't want anything to change on my account. I'm merely expressing my, well, disappointment with however (wrongly) I'm understanding Zig at this point, and as I'm not a developer, you're not losing anything or anyone because of this. And really, keep up the great work, even though Zig isn't for me(apparently), it's for thousands of others and I wish all the best to them and to you all! Keep up the great work!

  • signed me, an armchair wannabecoder or something.

@Vexu
Copy link
Member

Vexu commented Sep 3, 2022

I would recommend reading #1947 to better understand how undefined is supposed to work.

But it somehow allows using undefined in places like comparisons without even a warning, not to mention an error?(ie. print("{}\n", .{u == undefined}); // false and print("{}\n", .{undefined == u}); // true, sometimes are allowed by compiler, no warn/error) I'm sorry but that just blows my mind a little.

That is a bug #10703

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants