Skip to content
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

Problem 46, is undefined == null? #25

Closed
charlieman opened this issue Feb 22, 2021 · 7 comments
Closed

Problem 46, is undefined == null? #25

charlieman opened this issue Feb 22, 2021 · 7 comments

Comments

@charlieman
Copy link

First of all, thanks for this project, it makes learning zig so much fun!

Problem 46 asks to make tail optional, when I did it, I also changed the default from undefined to null (tail: ?*Elephant = null,) thinking it needs to be null so the check on line 42 (if (e.tail == null) ) works. However I changed it back to undefined later to see if it would break and it didn't!

So far it seems like undefined == null. I also checked with swapping the values around and what I got is:

  • undefined != undefined
  • null != undefined
  • undefined == null

So undefined == null when a value is optional but not the other way around, and no two undefined are the same.

Maybe there could be a note about this in the exercise, or make a new exercise that explains this?

@ratfactor
Copy link
Owner

@charlieman First off, I'm delighted that you've enjoyed Ziglings so far and I'm glad you figured out the real answer - making tail an optional value with ?.

This null vs undefined is pretty fascinating. I hadn't thought of it that way. You're absolutely right that setting the default value of the tail field to null rather than undefined works just fine. That part makes sense.

But what really surprised me was that I could put undefined in this condition as well:

if (e.tail == undefined) break;

My understanding is that null is a value meaning "no value" where undefined is a placeholder telling the compiler (in a contractual sense) that this value doesn't exist and must never be used.

At the very least, I might need to add an additional comment on this exercise. Do you think adding a hint about using the ?<type> syntax we learned in the previous exercise would do the trick?

In the meantime, I'm going to see if my understanding of the undefined keyword needs some refinement. 😄

Thanks!

@ratfactor
Copy link
Owner

Ha ha. Just our luck, I think undefined being allowed in the condition in this one case is a Zig bug. I've filed an issue: ziglang/zig#8056

In the meantime, I think my understanding wasn't entirely wrong, so let me know what you think about adding the hint.

@charlieman
Copy link
Author

Neat, I'm thrilled my question led to a bug in the compiler itself.

I don't think the extra hint is necessary, but maybe the exercise could use tail: *Elephant = null to avoid the confusion?

If I try to print elephantA.tail to the console right after creating it:

std.debug.print("{}\n", .{elephantA.tail});

It prints null whether the default is null or undefined, so it seems both use null internally?

@charlieman
Copy link
Author

charlieman commented Feb 24, 2021

Wait, I take that last part back. With this little example it prints u8@aaaaaaaaaaaaaaaa:

const std = @import("std");
const Foo = struct {
    a: ?*u8 = undefined,
    //b: ?*u8 = null,
};
pub fn main() void {
    var foo = Foo{};
    std.debug.print("{}", .{foo.a});
}

However if I uncomment b it prints null. Maybe I shouldn't trust the print output that much. 😕

@ifreund
Copy link

ifreund commented Feb 24, 2021

It prints null whether the default is null or undefined, so it seems both use null internally?

as you seem to have discovered judging by your next comment, the value of undefined is, as one might expect from the keyword, undefined. That is to say that the value could be literally anything and that branching on this value is a bug in all cases.

In safe build modes (debug and release safe) zig uses 0xaa as the value for undefined bytes to make spotting undefined values when using a debugger easier. This is merely an implementation detail however and should never be relied upon in correct code.

ratfactor added a commit that referenced this issue Feb 28, 2021
It was confusing to see

    tail... = undefined

in the struct definition and then

    if (tail == null)

later in the exercise - it appears that the mismatch would be the issue
- but that's distracting from the real issue: making the value optional!

Changing the initial value to null is still correct, but won't distract.

The only worry now is that the user will remember the undefined
definition from the previous exercise and wonder if that has to be that
way...but you can't win them all!
@ratfactor
Copy link
Owner

After hemming and hawing over this for a while, I agree that changing the default value in the definition to null will help a lot with making this exercise less confusing! Thanks again @charlieman for this observation.

@ratfactor
Copy link
Owner

Thanks @ifreund ! This exercise and some additional semantic issues that have arisen on my Zig journey recently have made it clear to me that after these struct/method exercises, we need a couple more that focus on the fundamentals of assigning and passing values (and null vs undefined).

vamega pushed a commit to vamega/ziglings that referenced this issue Jul 25, 2023
It was confusing to see

    tail... = undefined

in the struct definition and then

    if (tail == null)

later in the exercise - it appears that the mismatch would be the issue
- but that's distracting from the real issue: making the value optional!

Changing the initial value to null is still correct, but won't distract.

The only worry now is that the user will remember the undefined
definition from the previous exercise and wonder if that has to be that
way...but you can't win them all!
vamega pushed a commit to vamega/ziglings that referenced this issue Jul 25, 2023
mskarbek pushed a commit to mskarbek/ziglings that referenced this issue Dec 3, 2023
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

3 participants