3 ms·
Just requiring explicit assignment before first use feels like the superior approach to automatic initialization, regardless of whether the automatic initializa
by p1necone 6mo ago
Just requiring explicit assignment before first use feels like the superior approach to automatic initialization, regardless of whether the automatic initialization is with 0 or with NaN.
- WalterBright 6mo agoThat suggestion is often made. The trouble with it is a bug I've seen often. People will get an error message about an "uninitialized variable". Then they go into "just get the compiler to shut up" mode, amd pick "0" as the initializer. Then, the program compiles and runs, and silently produces the wrong answer. Code reviews will simply pass over the "0" initializer, as it looks right. With default NaN initialization, the programmer is more likely to stop and think about it, not just insert 0. Another issue with it is: float x = 0.0; setFloat(&x); void setFloat(float* px) { *px = 3.0; } For the purposes of code clarity I don't want to see a variable initialized to a value that is never used, just to shut the compiler up.
- ncurses1010 6mo agoWith the default initialization to nan, do you ever run into situations where people are searching for common sources for nan (nan literals, div by zero) and they can't find it? Or cases where only some branches but not others initialize the float?
- WalterBright 6mo agoTo leave a variable uninitialized, use the construction: int x = void; Note that nobody is going to write this by accident. And it's easy to grep for. To find the source of a NaN, it helps to know that every operation that has a NaN as an operand produces a NaN as a result. So if you see a NaN in the output, you can work backwards to where it originated.
- jcranmer 6mo ago> every operation that has a NaN as an operand produces a NaN as a result. That's not true. The minimum/maximum functions (fmin and fminimum_num variants, but not the fminimum one) treat NaN inputs as not-present, so return the non-NaN value if there is one. Similarly, hypot also treats NaN inputs as not-present. pow and compoundn will ignore NaN exponents if the base is 1.
- WalterBright 6mo agoYes, there are some functions where if one operand has no effect on the result, a NaN value will also have no effect.
- ncurses1010 6mo agoWhat do you think of kotlins approach where it has a 'todo' function that can always coerce to a type, but instead of populating the variable with a default value that's valid, it just throws
- WalterBright 6mo agoSorry, I know nothing about Kotlin.
- lmm 6mo agoYep. This is NaN as a billion dollar mistake all over again.
- WalterBright 6mo agoUnrecognized subtle errors in floating point calculations are worse problems.
- lmm 6mo agoSure, but that only matters if default-initialising to NaN significantly reduces them compared to the alternatives. IME it takes a very finely calibrated level of thoughtfulness for your argument in https://news.ycombinator.com/item?id=47928539 https://news.ycombinator.com/item?id=47928539 to work, to have a programmer who is simultaneously thoughtless enough to initialise to 0 without thinking if the compiler requires initialisation, but thoughtful enough to stop and think about it when the compiler initialises to NaN.
- WalterBright 6mo agoThe idea is to make errors obvious rather than subtle. A NaN output is far more obvious than a number that is 2% off.
- lmm 6mo agoA compilation failure is even more obvious.
- billforsternz 6mo agoHow long did you think about this before making this declaration? How long did Walter Bright think about this before making his decision when designing his language? Not saying you're wrong, just something to think about perhaps.
- electroly 6mo agoC# requires explicit assignment. If an appeal to authority sways you (it shouldn't), you can substitute Anders Hejlsberg instead of this random OP. How long do you suppose Anders Hejlsberg thought about this? But I contend it's more useful (and interesting) to think about the idea with your own mind instead of tallying up the perceived authority of its supporters and relying on trust. It was also somewhat rude to suggest that the OP had not given their idea much thought. This is a forum for discussion, isn't it?
- WalterBright 6mo agoUnfortunately, what happens with explicit assignment is programmers often enough will: 1. just insert '= 0;' to get it to compile 2. insert '= 0;' and then be puzzled by an initialization further along in the code 3. see the '= 0;' and wonder why the programmer did that as 0 was not a valid value for it A goal of D is to be able to make code more understandable. Forcing a vacuous initialization on the programmer is not conducive to that.
- electroly 6mo agoI think you are misunderstanding what C# does here, and what the original poster was suggesting. Maybe we did a poor job of describing it; I assumed people knew C#. The key words in OP's post were "before first use." It sounds like you interpreted this to mean "every variable declaration must immediately assign a value" but that's not how it works. I'll explain C#'s semantics. An assignment is required at some point before the first read, not in the declaration. It tracks assignments and usages, and it flags a compiler error if you read a variable before assigning to it for the first time. A variable that hasn't been assigned cannot be read. It means you can do "int a;" and then later in the function do "a = 5;" and the compiler guarantees that you never read the variable before the assignment in any path through the function. You cannot do "int a;" and then read from it; that's a compile-time error. It does not mean you have to assign something in the declaration. We never need "vacuous" initializations, and this solution works on all types. Indeed, we avoid vacuous initializations so that the compiler will catch use-before-assign bugs at compile time. The situation you described doesn't happen in C#. Our C# variables become readable on their first assignment, not their declaration; the declaration merely sets the scope. There's no need for a state where it's initialized to an invalid value before receiving the first intended assignment, because in C# the variable is completely inaccessible during that time.