digitalmars.D - Movement against float.init being nan
- Hipreme (21/21) Aug 19 2022 As someone coming from Java to use D, I find it myself quite
- bachmeier (6/10) Aug 19 2022 That would be a disaster. If you're computing a product, 0 is
- IGotD- (3/7) Aug 19 2022 Question: Can the x86 be set to trap when an operation with NaN
- Adam D Ruppe (4/6) Aug 19 2022 Yes, that's called the signaling nan. D actually used to use that
- Basile B. (7/29) Aug 19 2022 It's not a mistake, default initialization in D is not designed
- Steven Schveighoffer (21/56) Aug 19 2022 This is true, it's not a mistake, it is on purpose. The original idea
- rikki cattermole (2/2) Aug 19 2022 Shame its not as simple as writing:
- bachmeier (11/13) Aug 19 2022 It would be awful to choose an arbitrary, often incorrect value
- Steven Schveighoffer (22/36) Aug 19 2022 The problem is that most people declare a number like `int x` and expect...
- Walter Bright (11/23) Aug 19 2022 It is not useless. NaN's have many uses, one of which is to not have sil...
- Steven Schveighoffer (32/63) Aug 19 2022 Knowing that somewhere, in some code, someone didn't initialize a
- Walter Bright (21/49) Aug 19 2022 I don't see how. Any operation with a NaN produces a NaN result. If you'...
- Hipreme (10/43) Aug 20 2022 Drawing with float is required a lot on modern drawing API. What
- Walter Bright (9/13) Aug 20 2022 x * NaN => NaN
- Walter Bright (3/3) Aug 20 2022 I forgot to add that 0.0 is such a common floating point value, its erro...
- claptrap (20/23) Aug 21 2022 This is a complete misrepresentation. It's not that you find 0s
- Walter Bright (22/26) Aug 21 2022 If the computed answer is 1.7239 rather than 1.7230 because of an errone...
- claptrap (10/30) Aug 21 2022 Go through all the math functions in phobos and see what would
- Dark Hole (11/25) Aug 21 2022 Imagine, we have nullable int (int?) in language.
- Paul Backus (10/20) Aug 21 2022 We have this in the standard library already:
- Dark Hole (9/31) Aug 21 2022 My point is making this by default for all primitive types. This
- Timon Gehr (5/14) Oct 08 2023 I think a better way to approach this problem is to have a language
- monkyyy (5/20) Oct 09 2023 ~~definitely not bumping this thread to keep it alive~~
- drug007 (3/20) Aug 21 2022 I totally agree that NaN is really useful because makes it easier to
- Walter Bright (3/4) Aug 20 2022 I find this surprising. My experience with floating point coordinates is...
- Mike Parker (5/10) Aug 20 2022 Graphics APIs have been using floating point for decades now.
- jordan4ibanez (5/16) Aug 20 2022 Yes this is exactly the truth. GLSL has integer, but no matter
- Walter Bright (2/12) Aug 21 2022 I guess I stand corrected :-)
- IGotD- (8/11) Aug 21 2022 That's the whole point. In graphics and especially 3D graphics
- claptrap (3/8) Aug 21 2022 Modern drawing APIs have sub pixel positioning & antialising.
- Dukc (6/12) Aug 20 2022 On the other hand, the programmer could explicitly initialise the
- Nick Treleaven (8/12) Aug 20 2022 Actually, you can use `is`:
- Adam D Ruppe (4/12) Aug 20 2022 That works for float.init specifically, but if you've done some
- Nick Treleaven (8/22) Aug 20 2022 Then compare it with real.nan - smaller types will be promoted to
- Adam D Ruppe (16/18) Aug 20 2022 It isn't about size, but rather the nans can come in different
- Nick Treleaven (9/22) Aug 20 2022 Thanks. The above is infinity though.
- Adam D Ruppe (3/5) Aug 20 2022 yes, thanks!
- IGotD- (4/12) Aug 20 2022 I never understood why the IEEE standard decided to include
- Paul Backus (15/35) Aug 20 2022 I was curious about this too, so I did some searching. The
- Nick Treleaven (3/17) Aug 20 2022 Sorry, so there are other kinds of NaN than T.nan? How do you
- Walter Bright (4/7) Aug 20 2022 I.e. a "payload" can be put in the mantissa bits of a NaN, which can be ...
- =?UTF-8?Q?Ali_=c3=87ehreli?= (5/9) Aug 20 2022 I heard about it either at a meetup or at a DConf. The speaker was
- Walter Bright (7/13) Aug 21 2022 BTW, this influences code generation, too. For example:
- mw (16/40) Oct 08 2023 Just learnt from here:
- Walter Bright (3/4) Oct 25 2023 Interestingly, the nan boxing in tinylisp exposed a subtle code gen prob...
- Bastiaan Veelo (14/17) Aug 22 2022 I had some fun with `isNaN` the other day. We used it to check
- jmh530 (2/14) Aug 22 2022 Is there a simple example of this behavior?
- Bastiaan Veelo (11/21) Aug 25 2022 Yes:
- max haughton (5/28) Aug 25 2022 One of the nice things about UDAs and so on is that you can use
- Bastiaan Veelo (9/13) Aug 25 2022 Yes, that is the only responsible way to use this power. The
- =?UTF-8?Q?Ali_=c3=87ehreli?= (35/59) Aug 25 2022 I found documentation on --fast-math here:
- Paul Backus (10/20) Aug 25 2022 It is not just "contrary to Walter's understanding", it is
- Walter Bright (4/5) Aug 28 2022 https://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-ac...
- Guillaume Piolat (8/13) Aug 30 2022 +1
- rikki cattermole (10/13) Aug 30 2022 I've talked about this quite a bit with Bruce.
- Guillaume Piolat (5/9) Aug 30 2022 Well I wasn't talking about manual vectorization vs
- Dom Disc (11/13) Aug 20 2022 But it should be!
- Paul Backus (4/18) Aug 20 2022 By the way, you don't have to write this yourself; you can use
- mw (7/10) Aug 20 2022 BTW, where to report Dlang website (doc) bug?
- rikki cattermole (3/3) Aug 20 2022 issues.dlang.org
- Paul Backus (2/9) Aug 20 2022 Report it on issues.dlang.org as a bug in dlang.org.
- Dom Disc (6/14) Aug 20 2022 I know. I like my implementation better, but that's not the point.
- Walter Bright (3/15) Aug 20 2022 As soon as an operation is done on it, it isn't int.min anymore. It has ...
- Dom Disc (5/11) Aug 21 2022 It's no problem to implement saveint so, that int.min stays at
- Walter Bright (3/6) Aug 25 2022 This may be what you're looking for:
- kdevel (6/9) Aug 20 2022 The code point OxFF = U+00FF is ÿ:
- claptrap (17/30) Aug 19 2022 Any default value is an incorrect value unless it by luck happens
- zjh (2/3) Aug 19 2022 The compiler should prohibit such `statements`.
- Walter Bright (2/5) Aug 19 2022 D allows the setting of the default initializer for fields of a struct.
- Steven Schveighoffer (8/14) Aug 19 2022 Yes, and then you aren't forced to initialize the big struct. Which is
- Walter Bright (3/5) Aug 25 2022 The difference is it must be intentionally set for a field's value, and ...
- Nick Treleaven (25/32) Aug 20 2022 Maybe something like this:
- Hipreme (9/45) Aug 19 2022 Well, it **is** used as initialization substitute, if wasn't
- Basile B. (4/18) Aug 19 2022 I know it is used as substitute but people writing in D should
- Max Samukha (5/8) Aug 19 2022 0, false, null array, etc. are all identities of the "primary"
- Walter Bright (5/8) Aug 19 2022 The idea is if you're looking at code:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (20/22) Aug 19 2022 I think nan is the right choice. As Walter said, integrals are the
- Tejas (4/27) Aug 20 2022 Obligatory mention of how F# solved this with a feature called
- Salih Dincer (9/12) Aug 20 2022 If needed, units are possible at compile time using template and
- Max Samukha (7/11) Aug 20 2022 Arrays are outliars as well because .init is not an "invalid"
- Max Samukha (3/9) Aug 20 2022 *outlier
- Bastiaan Veelo (19/36) Aug 20 2022 Enter `std.typecons.Typefef`:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (7/12) Aug 20 2022 Yeah, that's a bummer. Perhaps something like this could work: "have all...
- Salih Dincer (3/19) Aug 21 2022 It's very simple and beautiful. Thank you, very delicious!
- novice2 (2/3) Aug 21 2022 except for ugly error messages :(
- Dukc (15/21) Aug 20 2022 I personally like how D does it. Once you know that floats have a
- Walter Bright (4/6) Aug 22 2022 C and C++ initialize them to garbage unless it is a global/static variab...
- Steven Schveighoffer (5/12) Aug 22 2022 Agreed that C/C++ initializing with garbage is the worst option.
- jordan4ibanez (1/1) Aug 22 2022 Did NaN replace any float/double values in memory?
- jordan4ibanez (4/4) Aug 23 2022 I have seen how polar people's view points are on this issue.
- jordan4ibanez (4/4) Aug 23 2022 I have seen how polar people's view points are on this issue.
- bauss (26/30) Aug 23 2022 The problem with this is metaprogramming will break because you
- IGotD- (10/15) Aug 23 2022 C++11 default value initialization exist. Meaning this
- =?UTF-8?Q?Ali_=c3=87ehreli?= (20/35) Aug 23 2022 At that level, it's the same in D:
- IGotD- (4/10) Aug 23 2022 It's too late for D2 but for D3 this should be taken into
- Walter Bright (2/3) Aug 24 2022 AFAIK D is unique in using NaN.
- claptrap (4/10) Aug 23 2022 Dont most C/C++ compilers have warnings for initialised
- Tejas (3/14) Aug 23 2022 Yeah, but there's also bugs in gcc, apparently
- Walter Bright (2/4) Aug 23 2022 I just tried it with gcc. No warning.
- Paul Backus (3/8) Aug 24 2022 Most of gcc's warnings, including this one, are not enabled by
- Walter Bright (3/12) Aug 24 2022 Fair enough, though that makes it clear that there are many languages ca...
- Zoadian (5/8) Aug 23 2022 I agree that NaN for uninitialized floats is the best option.
- jmh530 (13/21) Aug 23 2022 Walter makes good points in favor of NaN as a default, but I
- jordan4ibanez (17/17) Aug 20 2022 We could make it the worst of both worlds. We could have it so
- Walter Bright (30/30) Aug 21 2022 Consider the following pattern, which doesn't appear frequently, but fre...
- claptrap (6/12) Aug 21 2022 This is the problem, you suggest that if a variable is zero
- drug007 (6/23) Aug 21 2022 It will be noticed but what price? You've initialized all vars to 0 so
- apz28 (10/37) Aug 21 2022 Price for this float=NaN & char=FF
- IGotD- (8/17) Aug 21 2022 These are very good points which I agree with. Previously I was a
- drug007 (12/29) Aug 21 2022 Let me disagree to you
- Dom Disc (12/19) Aug 22 2022 No. If intentional you can explicitly leave them uninitialized (=
- claptrap (10/38) Aug 22 2022 You dont initialise all variables to zero, Ive just looked at
- drug007 (8/47) Aug 22 2022 But that is my point - not all variables initialize to zero. It is my
- claptrap (9/35) Aug 22 2022 "You've initialized all vars to 0"
- drug007 (6/42) Aug 22 2022 I'm so sorry, but you failed to reread post above carefully again. My
- Dom Disc (17/20) Aug 22 2022 So, if you rarely ever use default initialization, why do you
- claptrap (3/9) Aug 22 2022 NaN or Zero I dont really care, I just got sucked in, there's a
- zjh (6/10) Aug 21 2022 In many cases, `0` can solve that problem.
- Steven Schveighoffer (24/59) Aug 22 2022 How? No exception is thrown, no error occurs. Unless bar somehow checks
- wjoe (14/44) Aug 22 2022 Assuming this isn't a rhetoric question...
- Steven Schveighoffer (15/62) Aug 22 2022 Does it? And "at some point" it becomes obvious no matter what the error...
- Walter Bright (13/32) Aug 22 2022 The point is, since 0.0 is a common value for a floating point value to ...
- Steven Schveighoffer (37/92) Aug 22 2022 This is a highly dependent situation. It could be 0, which is 100% off.
- Walter Bright (10/31) Aug 25 2022 If you ignore the NaN value, you can hardly then blame it for missing th...
- Nick Treleaven (8/11) Aug 27 2022 We already have a back end error (only when optimization is
- drug007 (17/88) Aug 22 2022 For example, user has a callstack where called functions has these
- Steven Schveighoffer (19/75) Aug 22 2022 Callstack printouts don't look like that. Plus, what if you don't have
- drug007 (9/59) Aug 22 2022 you can use printf debugging
- =?UTF-8?Q?Ali_=c3=87ehreli?= (9/12) Aug 23 2022 Although Walter has already said it on this thread, what is missing in
- wjoe (30/37) Aug 23 2022 It could just as well be a very obvious hole, as easy to make out
- Walter Bright (23/27) Aug 23 2022 Then 1% of the time 0 is the wrong value and you never notice that the r...
- ryuukk_ (6/40) Aug 24 2022 That's the best answer possible, i used to be annoyed by float
- ryuukk_ (6/55) Aug 24 2022 I want to point out that, just like with the GC, it is not the
- ryuukk_ (5/10) Aug 24 2022 One could say, "well that's a bug anyways, and now you know you
- user1234 (4/9) Aug 24 2022 In gdb you can use `select-frame` and inspect the value of locals
- Steven Schveighoffer (3/15) Aug 24 2022 The source may not be in the call stack.
- Walter Bright (2/6) Aug 24 2022 I can't think of a case where a 0 is easier to track back to its origin.
- Walter Bright (7/13) Aug 24 2022 It's one reason why D is simply better than those other languages.
- Guillaume Piolat (3/5) Aug 21 2022 Honestly have no opinion on float.init being NaN, I don't think I
- Dave P. (24/25) Aug 23 2022 What’s great is that structs defined in C imported in D and
- =?UTF-8?Q?Ali_=c3=87ehreli?= (7/13) Aug 23 2022 Although C does not initialize variables, sometimes both C and D floats
- Steven Schveighoffer (3/5) Aug 23 2022 I'm wondering if D does not zero-initialize structs that are from import...
- Dave P. (4/16) Aug 23 2022 The default value for a struct imported via importC is all bits
- =?UTF-8?Q?Ali_=c3=87ehreli?= (8/11) Aug 23 2022 Steve said the same thing but I don't see it on the ImportC page (yet?):
- Paul Backus (7/30) Aug 23 2022 Global and static variables in C are initialized to all-zero
- Walter Bright (2/4) Aug 23 2022 Yes. It's not a bug.
- Walter Bright (15/18) Aug 23 2022 Let's have some fun with the following C program:
- Steven Schveighoffer (7/31) Aug 23 2022 Since you are looking at it, the original code is *not* a C function,
- Walter Bright (5/7) Aug 23 2022 The C rules. This is because D is importing C code, so it better behave ...
- Steven Schveighoffer (9/19) Aug 24 2022 So to paraphrase this, D does initialize local C structure values, but
- Walter Bright (28/30) Aug 24 2022 You could, but NaN default initialization is better.
- Adam D Ruppe (17/19) Aug 24 2022 oh ye of little faith!
- Walter Bright (8/29) Aug 25 2022 The cases I've heard all resulted in a smoking hole in the ground just p...
- Adam D Ruppe (15/18) Aug 25 2022 I found the story again, here's the wikipedia article on it that
- Walter Bright (9/26) Aug 25 2022 Thanks for the reference. I'm always interested in these kinds of things...
- zjh (2/3) Aug 24 2022 Now Boeing is a fighter among missiles.
- Steven Schveighoffer (22/61) Aug 24 2022 No, you are completely misunderstanding what I'm saying.
- bauss (21/24) Aug 25 2022 IMHO this is the better solution and not even an exception, but
- user1234 (3/22) Aug 25 2022 I'm shocked by this idea. What if I want high performance nothrow
- bauss (3/30) Aug 25 2022 It could be optimized away in release code and/or be optional to
- max haughton (4/31) Aug 25 2022 Turn the check off. The hardware basically already supports doing
- Paul Backus (10/42) Aug 25 2022 Looks like D allows you to enable floating-point exceptions using
- Paul Backus (23/33) Aug 25 2022 Unfortunately, it looks like this will not work in practice,
- IGotD- (7/13) Aug 25 2022 Which is strange because HW wise it is trivial to check if the
- Walter Bright (11/17) Aug 25 2022 There's nothing to be afraid of in getting a NaN in the output. One shou...
- Timon Gehr (3/28) Aug 29 2022 Which is why asserts can introduce new _undefined behavior_?
- Walter Bright (3/5) Aug 30 2022 DMD has a switch to insert a halt instruction upon assertion failures.
- Timon Gehr (13/22) Aug 30 2022 Let's assume whoever is compiling my code does not want to spend
- Adam D Ruppe (5/6) Aug 30 2022 It actually uses UD2 now (I've been complaining about this for
- H. S. Teoh (9/12) Aug 30 2022 Hmm. I was pretty sure the convention, at least on x86 architectures, is
- user1234 (3/12) Aug 25 2022 We agree there, we talk about a check that does not even exist
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (5/8) Aug 25 2022 One big advantage of having everything default to 0 would be if
- Walter Bright (3/5) Aug 25 2022 Seriously, *when* is 0 better than that?
- kdevel (20/23) Aug 25 2022 To make decisions?
- Steven Schveighoffer (15/23) Aug 25 2022 Very few programs have a purpose to print an actual floating point
- Walter Bright (13/14) Aug 25 2022 0 is equal or worse than NaN. It is true that sometimes 0 is equal. But ...
- Steven Schveighoffer (15/28) Aug 26 2022 I fully don't ever expect any changes to come from this discussion. But
- Walter Bright (12/19) Aug 26 2022 The most important part is discovering that I *have* a problem.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (5/9) Aug 26 2022 Microsoft's C++ compiler used to do and probably still does that. Newly
- IGotD- (10/15) Aug 26 2022 I don't think it would do that in release mode. However, in debug
- Paulo Pinto (6/23) Aug 27 2022 Except Windows is actually compiled in release mode with local
- Timon Gehr (2/8) Aug 29 2022 D's assert semantics may turn a reproducible bug into a heisenbug.
- Tejas (4/14) Aug 30 2022 Uh, can you please elaborate on what you mean by this? How do
- Adam D Ruppe (2/3) Aug 30 2022 I pity the fool who uses -release.
- wjoe (2/5) Aug 30 2022 Is this true for asserts w/o side effects?
- Adam D Ruppe (13/22) Aug 30 2022 Yes. -release should seriously *never* be used for a lot of
- wjoe (3/20) Aug 30 2022 That would make for a nice note in the spec :) Thanks for
- bauss (3/6) Aug 30 2022 Arguably the only thing -release should ever have done is
- Steven Schveighoffer (3/11) Aug 30 2022 debug statements are not used by default.
- Walter Bright (3/4) Aug 30 2022 -release is for people who do speed benchmarks.
- Adam D Ruppe (3/4) Aug 30 2022 The documentation should outright say then "never use this unless
- Salih Dincer (5/9) Aug 30 2022 -release says use me in terms of meaning, but masters says don't
- Walter Bright (3/13) Aug 30 2022 It's not dire. It's just necessary to understand what's happening. Peopl...
- Timon Gehr (12/29) Aug 30 2022 I think the term is fitting. Contracts are meant to support correctness,...
- H. S. Teoh (5/10) Aug 30 2022 It should be renamed to -optimize-for-benchmark. ;-)
- cc (16/28) Oct 12 2023 At the end of the day, the answer is: Default initializing floats
- apz28 (4/9) Aug 26 2022 This seem be another string auto-decode problem to a basic type.
- Dukc (6/15) Aug 26 2022 In hindsight, the robust way to solve this would be that trying
- ryuukk_ (6/8) Aug 25 2022 How to kill a language, put exceptions everywhere, specially in
- bauss (4/12) Aug 25 2022 That's why my response to it said it should be Error and not
- Walter Bright (4/6) Aug 26 2022 NaN has another use. If, say, your data collection is incomplete (like h...
- IGotD- (5/9) Aug 26 2022 I think what he's meaning is that a HW exception happens on NaN.
- Steven Schveighoffer (11/22) Aug 26 2022 I'm not asking for this, I'm saying without having some sort of "fail
- Walter Bright (8/13) Aug 30 2022 If you don't look for errors in the output, you are even less likely to ...
- jmh530 (3/7) Aug 30 2022 I feel like there aren't a lot of people here who do data
As someone coming from Java to use D, I find it myself quite annoying that float and double are initialized to `nan`. This is really bad, it is hard to detect for newcomers, there is no flag by default to throw an exception when some operation on nan is done. It can be misleading if you're not paying a lot of attention to what you're doing. What I suggest is what any sane people would: use 0 as the start for float and double. 0 is the most common sense as a starting point for everything, and, there are 2 options we could go: 1: Emit a compilation error that every variable must be initialized (I thought D were trying to avoid runtime errors) 2: 0 init all types, so, none is actually invalid before use Even `char` took me as surprise to know it actually starts as 0xff, I lost a bit of time trying to find that bug because it is so common that variables init as zero. Although the `char` is a bit different beast in terms of breaking change, I really *can't see* anyone actually depending that your float is being initialized with `nan`, so I really would like to know how much people agree with this idea. It is so common to stumble on that problem that it is starting to feel as a real mistake.
Aug 19 2022
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:What I suggest is what any sane people would: use 0 as the start for float and double. 0 is the most common sense as a starting point for everything, and, there are 2 options we could go:That would be a disaster. If you're computing a product, 0 is horrible, and there's nothing to suggest you're doing something wrong. At least nan is going to tell you that you've screwed up. The reasonable fix is to either make it a compilation error (my preference) or an error when compiled with a particular flag.
Aug 19 2022
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:This is really bad, it is hard to detect for newcomers, there is no flag by default to throw an exception when some operation on nan is done. It can be misleading if you're not paying a lot of attention to what you're doing.Question: Can the x86 be set to trap when an operation with NaN is detected?
Aug 19 2022
On Friday, 19 August 2022 at 13:58:28 UTC, IGotD- wrote:Question: Can the x86 be set to trap when an operation with NaN is detected?Yes, that's called the signaling nan. D actually used to use that for init and it was changed a few years ago: https://forum.dlang.org/thread/nsp1ql$ivu$1 digitalmars.com
Aug 19 2022
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:As someone coming from Java to use D, I find it myself quite annoying that float and double are initialized to `nan`. This is really bad, it is hard to detect for newcomers, there is no flag by default to throw an exception when some operation on nan is done. It can be misleading if you're not paying a lot of attention to what you're doing. What I suggest is what any sane people would: use 0 as the start for float and double. 0 is the most common sense as a starting point for everything, and, there are 2 options we could go: 1: Emit a compilation error that every variable must be initialized (I thought D were trying to avoid runtime errors) 2: 0 init all types, so, none is actually invalid before use Even `char` took me as surprise to know it actually starts as 0xff, I lost a bit of time trying to find that bug because it is so common that variables init as zero. Although the `char` is a bit different beast in terms of breaking change, I really *can't see* anyone actually depending that your float is being initialized with `nan`, so I really would like to know how much people agree with this idea. It is so common to stumble on that problem that it is starting to feel as a real mistake.It's not a mistake, default initialization in D is not designed to be an initialization substitute, it's designed in a way that missing initialization is easily detectable but not UB. However, thruth is that this only works for character and floating point types. Changing that design would require a DIP I think.
Aug 19 2022
On 8/19/22 12:34 PM, Basile B. wrote:On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:This is true, it's not a mistake, it is on purpose. The original idea behind default values is to correct so many mistakes from C where values are not initialized but just "happen" to work until it doesn't. But practically, it is now used as de-facto initialization, it's just too convenient. In that mindset, floats defaulting to NaN are an outlier. However, in my recent efforts to port a decently sized C library to D, one thing I don't have a good answer for is code like: ```c ReallyLargeStruct foo = { 0 }; ``` There just is no equivalent in D. In order to set all fields to 0, I would have to specify a complete layout of the entire thing. This could probably be done via introspection. But I just don't like it even in that case. The easier thing to do is to default the `float` and `double` fields to 0 in the type definition, and then use default initialization to achieve the same. So I think in some cases, it's much nicer to just rely on the default initialization. I also would prefer that all floats/doubles default to 0 instead of NaN. -SteveAs someone coming from Java to use D, I find it myself quite annoying that float and double are initialized to `nan`. This is really bad, it is hard to detect for newcomers, there is no flag by default to throw an exception when some operation on nan is done. It can be misleading if you're not paying a lot of attention to what you're doing. What I suggest is what any sane people would: use 0 as the start for float and double. 0 is the most common sense as a starting point for everything, and, there are 2 options we could go: 1: Emit a compilation error that every variable must be initialized (I thought D were trying to avoid runtime errors) 2: 0 init all types, so, none is actually invalid before use Even `char` took me as surprise to know it actually starts as 0xff, I lost a bit of time trying to find that bug because it is so common that variables init as zero. Although the `char` is a bit different beast in terms of breaking change, I really *can't see* anyone actually depending that your float is being initialized with `nan`, so I really would like to know how much people agree with this idea. It is so common to stumble on that problem that it is starting to feel as a real mistake.It's not a mistake, default initialization in D is not designed to be an initialization substitute, it's designed in a way that missing initialization is easily detectable but not UB. However, thruth is that this only works for character and floating point types. Changing that design would require a DIP I think.
Aug 19 2022
Shame its not as simple as writing: foo.tupleof = 0;
Aug 19 2022
On Friday, 19 August 2022 at 17:14:35 UTC, Steven Schveighoffer wrote:I also would prefer that all floats/doubles default to 0 instead of NaN.It would be awful to choose an arbitrary, often incorrect value in order to give the appearance that your program is running. It would be absurd to silently set the value of `z` to 1.0 in this code: ``` double w; double z = w*2.5 + 1; ``` Defaulting to 0 is no better than defaulting to a random number.
Aug 19 2022
On 8/19/22 2:04 PM, bachmeier wrote:On Friday, 19 August 2022 at 17:14:35 UTC, Steven Schveighoffer wrote:The problem is that most people declare a number like `int x` and expect it to default to 0. Because that's what D does. For a float (number), they expect the same thing. But it defaults to a completely useless value (NaN). This is unexpected, and commonly leads to hours of head-scratching (see Adam's Ruppe's 2020 live coding session, where he couldn't figure out for much of the stream why his game wasn't working).I also would prefer that all floats/doubles default to 0 instead of NaN.It would be awful to choose an arbitrary, often incorrect value in order to give the appearance that your program is running.It would be absurd to silently set the value of `z` to 1.0 in this code: ``` double w; double z = w*2.5 + 1; ```Not absurd at all. if `w` defaults to 0, I would expect `z` to be `2.5 * 0 + 1`. Change it to `int`, and see if it looks absurd to you. You just aren't used to it. D used default values to prevent errors in not initializing values, but default initialization to a very commonly-expected value turns to be incredibly useful. The design choices for float/double were made based on the fact that a value that means "this isn't initialized" existed. It didn't for int, so meh, 0 was chosen. Walter could have easily have just chosen int.min or something, and then we would possibly not ever be used to it. But now we are used to it, so it has become irksome that doubles/floats are the outlier here. -Steve
Aug 19 2022
On 8/19/2022 12:09 PM, Steven Schveighoffer wrote:But it defaults to a completely useless value (NaN).It is not useless. NaN's have many uses, one of which is to not have silent bugs where you forgot to initialize a double.This is unexpected, and commonly leads to hours of head-scratching (see Adam's Ruppe's 2020 live coding session, where he couldn't figure out for much of the stream why his game wasn't working).It's fewer hours then tracking down why it is 0 instead of 6, because 0 doesn't leave a trail.D used default values to prevent errors in not initializing values, but default initialization to a very commonly-expected value turns to be incredibly useful.I've lost days in debugging issues with forgetting to initialize a variable.The design choices for float/double were made based on the fact that a value that means "this isn't initialized" existed. It didn't for int, so meh, 0 was chosen. Walter could have easily have just chosen int.min or something, and then we would possibly not ever be used to it. But now we are used to it, so it has become irksome that doubles/floats are the outlier here.If there was a NaN value for int, I would have used it as the default. int.min is not really a NaN. The NaN value for char is 0xFF, and for pointers is null. Both work well. (0xFF is specified as an illegal code point in Unicode.) It's integers that are the outliers :-)
Aug 19 2022
On 8/19/22 9:01 PM, Walter Bright wrote:On 8/19/2022 12:09 PM, Steven Schveighoffer wrote:Knowing that somewhere, in some code, someone didn't initialize a double, is not useful. And that's if you notice it. In fact, NaN creates silent bugs.But it defaults to a completely useless value (NaN).It is not useless. NaN's have many uses, one of which is to not have silent bugs where you forgot to initialize a double.That's not what happens. You see, when you do `DrawSquare(x, y)`, nothing happens. No exception thrown, no "Bad Square" drawn to the screen, it's like your function didn't get called. You start questioning just about every other aspect of your code (Am I calling the function? Is the library calling my function? Is there a bug in the library?). You don't get any indication that x is NaN. Whereas, if it's zero, and that's *wrong*, you see a square in the wrong spot, and fix it. In other words, NaN is silent. You can't even `assert(x != double.init)`. You have to use an esoteric function `isNaN` for that. But all the code that *does* expect 0 to be the default would become useful. So there's upsides both ways -- the silent nature of NaN bugs goes away, and now your code doesn't have to always assign a value to a float buried in a struct.This is unexpected, and commonly leads to hours of head-scratching (see Adam's Ruppe's 2020 live coding session, where he couldn't figure out for much of the stream why his game wasn't working).It's fewer hours then tracking down why it is 0 instead of 6, because 0 doesn't leave a trail.I mostly do not initialize variables when I know the default value is correct. But even having NaN as a default is classes above C where it not only might not have the correct value, the value can be *garbage*. That can cause days of searching.D used default values to prevent errors in not initializing values, but default initialization to a very commonly-expected value turns to be incredibly useful.I've lost days in debugging issues with forgetting to initialize a variable.Why not just require initialization? I'm mostly curious, because I don't think it's possible to do now, but why didn't you do that originally?The design choices for float/double were made based on the fact that a value that means "this isn't initialized" existed. It didn't for int, so meh, 0 was chosen. Walter could have easily have just chosen int.min or something, and then we would possibly not ever be used to it. But now we are used to it, so it has become irksome that doubles/floats are the outlier here.If there was a NaN value for int, I would have used it as the default. int.min is not really a NaN.The NaN value for char is 0xFF, and for pointers is null. Both work well. (0xFF is specified as an illegal code point in Unicode.) It's integers that are the outliers :-)the default for char is odd, but mostly esoteric. It crops up with things like static char arrays, which are not common. Honestly, having a default of 0 would be better there too, because of C's requirement to null-terminate. But that value isn't terrible (and it doesn't have the problems of NaN, e.g. ++ on it will not just leave it at 0xff). But the default for pointers being null is perfect. Using a null pointer is immediately obvious since it crashes the program where it is used. -Steve
Aug 19 2022
On 8/19/2022 8:12 PM, Steven Schveighoffer wrote:On 8/19/22 9:01 PM, Walter Bright wrote:I don't see how. Any operation with a NaN produces a NaN result. If you've got a NaN result, it can be traced back to its source. This is hard with 0 initialization.On 8/19/2022 12:09 PM, Steven Schveighoffer wrote:Knowing that somewhere, in some code, someone didn't initialize a double, is not useful. And that's if you notice it. In fact, NaN creates silent bugs.But it defaults to a completely useless value (NaN).It is not useless. NaN's have many uses, one of which is to not have silent bugs where you forgot to initialize a double.I don't know why floating point for drawing coordinates? Besides, when I wonder if a function is being called, I put a printf in it. Or set a breakpoint in the debugger. This is routine debugging work. Then I'll look at the values of the parameters. Again, routine. Back in the olden days, I'd have the embedded system click the speaker to see if it entered a function :-)It's fewer hours then tracking down why it is 0 instead of 6, because 0 doesn't leave a trail.That's not what happens. You see, when you do `DrawSquare(x, y)`, nothing happens. No exception thrown, no "Bad Square" drawn to the screen, it's like your function didn't get called. You start questioning just about every other aspect of your code (Am I calling the function? Is the library calling my function? Is there a bug in the library?). You don't get any indication that x is NaN. Whereas, if it's zero, and that's *wrong*, you see a square in the wrong spot, and fix it.In other words, NaN is silent. You can't even `assert(x != double.init)`. You have to use an esoteric function `isNaN` for that.It is not silent. Every single usage of NaN produces a NaN result. If printing a NaN value, the result is "NaN".But all the code that *does* expect 0 to be the default would become useful. So there's upsides both ways -- the silent nature of NaN bugs goes away, and now your code doesn't have to always assign a value to a float buried in a struct.struct S { float x = 0; }Why not just require initialization? I'm mostly curious, because I don't think it's possible to do now, but why didn't you do that originally?Because I've seen what happens with that. The compiler complains about no initializer, and the programmer just puts in "0" to shut up the compiler. He does not make the effort to figure out what it should be initialized to. The reviewer wastes time trying to figure why it is uselessly initialized to zero. This is an especial problem when the initialized value is never used. The reviewer is left wondering if it is a bug. D is designed this way so that explicit initializations to a value are *intentional* rather than a side effect of compiler error messages. This is all part of D's design to encourage writing code that is easier to debug, review and maintain. Even if it takes a little more writing up front.
Aug 19 2022
On Saturday, 20 August 2022 at 05:18:20 UTC, Walter Bright wrote:On 8/19/2022 8:12 PM, Steven Schveighoffer wrote:Drawing with float is required a lot on modern drawing API. What motivated me doing that post was firstly because I was sending OpenGL NaN coordinates, which resulted in needing a gpu debugger for that. I don't see how easier it is to track a nan. Division by zero causes exception which is the best thing ever. Multiplication produces a zero result, which is pretty obvious to track. If the number does not change you will pretty much print both values and you'll easily find the 0 there.[...]I don't see how. Any operation with a NaN produces a NaN result. If you've got a NaN result, it can be traced back to its source. This is hard with 0 initialization.[...]I don't know why floating point for drawing coordinates? Besides, when I wonder if a function is being called, I put a printf in it. Or set a breakpoint in the debugger. This is routine debugging work. Then I'll look at the values of the parameters. Again, routine. Back in the olden days, I'd have the embedded system click the speaker to see if it entered a function :-)[...]It is not silent. Every single usage of NaN produces a NaN result. If printing a NaN value, the result is "NaN".[...]struct S { float x = 0; }[...]Because I've seen what happens with that. The compiler complains about no initializer, and the programmer just puts in "0" to shut up the compiler. He does not make the effort to figure out what it should be initialized to. The reviewer wastes time trying to figure why it is uselessly initialized to zero. This is an especial problem when the initialized value is never used. The reviewer is left wondering if it is a bug. D is designed this way so that explicit initializations to a value are *intentional* rather than a side effect of compiler error messages. This is all part of D's design to encourage writing code that is easier to debug, review and maintain. Even if it takes a little more writing up front.
Aug 20 2022
On 8/20/2022 6:19 AM, Hipreme wrote:I don't see how easier it is to track a nan. Division by zero causes exception which is the best thing ever. Multiplication produces a zero result, which is pretty obvious to track. If the number does not change you will pretty much print both values and you'll easily find the 0 there.x * NaN => NaN x / NaN => NaN x + NaN => NaN x - NaN => NaN -Nan => NaN cos(NaN) => NaN exp(NaN) => NaN Only a subset of this is true for 0.
Aug 20 2022
I forgot to add that 0.0 is such a common floating point value, its erroneous use cannot be reliably distinguished from valid uses. Just finding a 0 is not good enough, but finding a NaN is.
Aug 20 2022
On Sunday, 21 August 2022 at 03:41:55 UTC, Walter Bright wrote:I forgot to add that 0.0 is such a common floating point value, its erroneous use cannot be reliably distinguished from valid uses. Just finding a 0 is not good enough, but finding a NaN is.This is a complete misrepresentation. It's not that you find 0s and say oh well it shouldn't be zero here. It's that your results are wrong, stuff on screen isn't where it should be, your data plots are off, it's not doing what it should be etc.. If you're doing some numerical computation and you cant tell when the results are wrong then you almost always doing you're doing something wrong anyway. The point is, at least in my experience, and I do a lot of DSP and statistics stuff, you know the result is wrong and you just chase it backwards, its the same process whether it's a NaN or just a wrong result. And the fact is if you'd just disallowed default initialisation it would have caught this bug every time for me, and I wouldn't have just stuck zero in, because the bug is that I forgot to set the value, not that I didn't know what it was. So from my experience the rational is based on two fallacies. 1. That using zero as default init would hide the bug. 2. That people will just stick zero in because they don't know what it should be.
Aug 21 2022
On 8/21/2022 2:01 AM, claptrap wrote:So from my experience the rational is based on two fallacies. 1. That using zero as default init would hide the bug.If the computed answer is 1.7239 rather than 1.7230 because of an erroneous 0 input, how would you know it is wrong? But if the computed answer is NaN, you *know* it is wrong.2. That people will just stick zero in because they don't know what it should be.I know *you* wouldn't do it (I wouldn't either), but like I wrote, I've seen it happen. I've also seen cases of: double x = 0; ... no uses of x ... x = 5; ... where the initialization was put in to shut the compiler up. But to one unfortunate enough to be reviewing unfamiliar code, this double initialization has a smell about it - which initialization is the correct one? Why was it initialized to 0 when that makes no sense for the algorithm? It is also why if it is desirable for a variable to be uninitialized, the double x = void; form must be used, as that is highly unlikely to be written by accident. I.e. this is all designed to encourage the programmer to write code intentionally, rather than accidentally. BTW, I've done user support (helping them debug problems with their code) for 40 years now. I've talked a lot with team managers about what problems they experience with code. A lot of D's unusual features come from this experience.
Aug 21 2022
On Sunday, 21 August 2022 at 15:26:54 UTC, Walter Bright wrote:On 8/21/2022 2:01 AM, claptrap wrote:Go through all the math functions in phobos and see what would happen if you zeroed out some random local variables, you wont get results that are a tiny fraction of a percent out, it'll be way off 99 times out of 100. Im not saying it cant happen, but that it's vastly exaggerated how likely it is that an erroneous zero init wont be obvious.So from my experience the rational is based on two fallacies. 1. That using zero as default init would hide the bug.If the computed answer is 1.7239 rather than 1.7230 because of an erroneous 0 input, how would you know it is wrong? But if the computed answer is NaN, you *know* it is wrong.Id still rather have the compiler error, that is more helpful to me that preventing somebody else writing crappy but *working* code.2. That people will just stick zero in because they don't know what it should be.I know *you* wouldn't do it (I wouldn't either), but like I wrote, I've seen it happen. I've also seen cases of: double x = 0; ... no uses of x ... x = 5; ... where the initialization was put in to shut the compiler up. But to one unfortunate enough to be reviewing unfamiliar code, this double initialization has a smell about it - which initialization is the correct one? Why was it initialized to 0 when that makes no sense for the algorithm?
Aug 21 2022
On Sunday, 21 August 2022 at 03:25:57 UTC, Walter Bright wrote:On 8/20/2022 6:19 AM, Hipreme wrote:Imagine, we have nullable int (int?) in language. ```d int? x => null x * null => null x / null => null x + null => null x - null => null -cast(int?)null => null ``` Seems like perfect solution (except performance costs)I don't see how easier it is to track a nan. Division by zero causes exception which is the best thing ever. Multiplication produces a zero result, which is pretty obvious to track. If the number does not change you will pretty much print both values and you'll easily find the 0 there.x * NaN => NaN x / NaN => NaN x + NaN => NaN x - NaN => NaN -Nan => NaN cos(NaN) => NaN exp(NaN) => NaN Only a subset of this is true for 0.
Aug 21 2022
On Sunday, 21 August 2022 at 11:13:02 UTC, Dark Hole wrote:Imagine, we have nullable int (int?) in language. ```d int? x => null x * null => null x / null => null x + null => null x - null => null -cast(int?)null => null ``` Seems like perfect solution (except performance costs)We have this in the standard library already: import std.checkedint; Checked!(int, WithNaN) n; assert(n.isNaN); assert((123 * n).isNaN); assert((123 / n).isNaN); assert((123 + n).isNaN); assert((123 - n).isNaN); assert((-n).isNaN);
Aug 21 2022
On Sunday, 21 August 2022 at 13:47:43 UTC, Paul Backus wrote:On Sunday, 21 August 2022 at 11:13:02 UTC, Dark Hole wrote:My point is making this by default for all primitive types. This will be consistent and simple: ```d bool x; // Error, use bool? or init it something meaningful struct Foo { bool x; } // Error too ``` So we have no problem "programmers make meaningless 0" and have no problem to determine init for most of types.Imagine, we have nullable int (int?) in language. ```d int? x => null x * null => null x / null => null x + null => null x - null => null -cast(int?)null => null ``` Seems like perfect solution (except performance costs)We have this in the standard library already: import std.checkedint; Checked!(int, WithNaN) n; assert(n.isNaN); assert((123 * n).isNaN); assert((123 / n).isNaN); assert((123 + n).isNaN); assert((123 - n).isNaN); assert((-n).isNaN);
Aug 21 2022
On 8/21/22 16:09, Dark Hole wrote:My point is making this by default for all primitive types. This will be consistent and simple: ```d bool x; // Error, use bool? or init it something meaningful struct Foo { bool x; } // Error too ``` So we have no problem "programmers make meaningless 0" and have no problem to determine init for most of types.I think a better way to approach this problem is to have a language where people are not tempted to declare a variable into which they have no sensible value to put in the first place. If you have no value at a given point in the program, you should not need a variable to hold one.
Oct 08 2023
On Monday, 9 October 2023 at 00:03:24 UTC, Timon Gehr wrote:On 8/21/22 16:09, Dark Hole wrote:~~definitely not bumping this thread to keep it alive~~ Im pretty sure that declaration before use needs to be a thing cause compilers are still bad at knowing where memory sure go and I need my goto and global scope variables.My point is making this by default for all primitive types. This will be consistent and simple: ```d bool x; // Error, use bool? or init it something meaningful struct Foo { bool x; } // Error too ``` So we have no problem "programmers make meaningless 0" and have no problem to determine init for most of types.I think a better way to approach this problem is to have a language where people are not tempted to declare a variable into which they have no sensible value to put in the first place. If you have no value at a given point in the program, you should not need a variable to hold one.
Oct 09 2023
On 8/21/22 06:25, Walter Bright wrote:On 8/20/2022 6:19 AM, Hipreme wrote:I totally agree that NaN is really useful because makes it easier to find the reason for the NaN resultI don't see how easier it is to track a nan. Division by zero causes exception which is the best thing ever. Multiplication produces a zero result, which is pretty obvious to track. If the number does not change you will pretty much print both values and you'll easily find the 0 there.x * NaN => NaN x / NaN => NaN x + NaN => NaN x - NaN => NaN -Nan => NaN cos(NaN) => NaN exp(NaN) => NaN Only a subset of this is true for 0.
Aug 21 2022
On 8/20/2022 6:19 AM, Hipreme wrote:Drawing with float is required a lot on modern drawing API.I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Aug 20 2022
On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:On 8/20/2022 6:19 AM, Hipreme wrote:Graphics APIs have been using floating point for decades now. GPUs are optimized for it. You'll still see 2D APIs around now and again with an integer-based public API, but internally they're sending floats to the GPU.Drawing with float is required a lot on modern drawing API.I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Aug 20 2022
On Sunday, 21 August 2022 at 06:23:39 UTC, Mike Parker wrote:On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:Yes this is exactly the truth. GLSL has integer, but no matter what you do, no matter how hard you try, When you go to the final output it will always be sent out as a floating point with ``gl_Position``.On 8/20/2022 6:19 AM, Hipreme wrote:Graphics APIs have been using floating point for decades now. GPUs are optimized for it. You'll still see 2D APIs around now and again with an integer-based public API, but internally they're sending floats to the GPU.Drawing with float is required a lot on modern drawing API.I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Aug 20 2022
On 8/20/2022 11:23 PM, Mike Parker wrote:On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:I guess I stand corrected :-)On 8/20/2022 6:19 AM, Hipreme wrote:Graphics APIs have been using floating point for decades now. GPUs are optimized for it. You'll still see 2D APIs around now and again with an integer-based public API, but internally they're sending floats to the GPU.Drawing with float is required a lot on modern drawing API.I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Aug 21 2022
On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.That's the whole point. In graphics and especially 3D graphics use floating point in order to achieve sub pixel accuracy. That means it uses the fractional part to draw more accurate lines for example. It can be used for anti antialiasing calculations and so on. Without subpixel accuracy we would experience more "steppy" movement in 3D games for example. This can be observed in early 3D games which only used integer calculations.
Aug 21 2022
On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:On 8/20/2022 6:19 AM, Hipreme wrote:Modern drawing APIs have sub pixel positioning & antialising. GDI+ had that, at that was XP i think, so what 20 years ago maybe?Drawing with float is required a lot on modern drawing API.I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Aug 21 2022
On Saturday, 20 August 2022 at 05:18:20 UTC, Walter Bright wrote:Because I've seen what happens with that. The compiler complains about no initializer, and the programmer just puts in "0" to shut up the compiler. He does not make the effort to figure out what it should be initialized to. The reviewer wastes time trying to figure why it is uselessly initialized to zero.On the other hand, the programmer could explicitly initialise the variable to `float.nan`. The problem is that so few people coming from other languages know that trick. D educates us, making me annoyed when other languages use zero as the default and force me to explicitly initialise to NaN :).
Aug 20 2022
On Saturday, 20 August 2022 at 03:12:43 UTC, Steven Schveighoffer wrote:You can't even `assert(x != double.init)`. You have to use an esoteric function `isNaN` for that.Actually, you can use `is`: ```d static assert(float() is float.nan); ``` From the spec:For struct objects and floating point values, identity is defined as the bits in the operands being identical.I'm making a pull to add a spec example so it's more obvious.
Aug 20 2022
On Saturday, 20 August 2022 at 10:26:08 UTC, Nick Treleaven wrote:On Saturday, 20 August 2022 at 03:12:43 UTC, Steven Schveighoffer wrote:That works for float.init specifically, but if you've done some operation on it and ended up with a nan, that will not necessarily be true since nans come in several bit patterns.You can't even `assert(x != double.init)`. You have to use an esoteric function `isNaN` for that.Actually, you can use `is`: ```d static assert(float() is float.nan); ```
Aug 20 2022
On Saturday, 20 August 2022 at 11:51:13 UTC, Adam D Ruppe wrote:On Saturday, 20 August 2022 at 10:26:08 UTC, Nick Treleaven wrote:Then compare it with real.nan - smaller types will be promoted to real: ```d static assert(float() is real.nan); static assert(double() is real.nan); static assert(real() is real.nan); ```On Saturday, 20 August 2022 at 03:12:43 UTC, Steven Schveighoffer wrote:That works for float.init specifically, but if you've done some operation on it and ended up with a nan, that will not necessarily be true since nans come in several bit patterns.You can't even `assert(x != double.init)`. You have to use an esoteric function `isNaN` for that.Actually, you can use `is`: ```d static assert(float() is float.nan); ```
Aug 20 2022
On Saturday, 20 August 2022 at 12:02:17 UTC, Nick Treleaven wrote:Then compare it with real.nan - smaller types will be promoted to real:It isn't about size, but rather the nans can come in different forms. Consider: --- void main() { float f = 7.0; f /= 0; import core.stdc.stdio; printf("%d\n", *cast(int*)&f); if(f is float.init) printf("nan\n"); } --- That's a different nan than the float.init pattern. I don't know if you can start with a float.init and come up with a different pattern though, but i expect you can.
Aug 20 2022
On Saturday, 20 August 2022 at 12:53:28 UTC, Adam D Ruppe wrote:--- void main() { float f = 7.0; f /= 0; import core.stdc.stdio; printf("%d\n", *cast(int*)&f); if(f is float.init) printf("nan\n"); } --- That's a different nan than the float.init pattern. I don't know if you can start with a float.init and come up with a different pattern though, but i expect you can.Thanks. The above is infinity though. f = 1.0; f /= 0; assert(f is f.infinity); This produces a different NaN: float f = 0; f /= 0; assert(f is f.nan); //fails
Aug 20 2022
On Saturday, 20 August 2022 at 13:06:49 UTC, Nick Treleaven wrote:Thanks. The above is infinity though.oh yeah i forgot about that ruleThis produces a different NaN:yes, thanks!
Aug 20 2022
On Saturday, 20 August 2022 at 13:06:49 UTC, Nick Treleaven wrote:Thanks. The above is infinity though. f = 1.0; f /= 0; assert(f is f.infinity); This produces a different NaN: float f = 0; f /= 0; assert(f is f.nan); //failsI never understood why the IEEE standard decided to include infinity. What were they trying to achieve? Indeterminate maths with floating point?
Aug 20 2022
On Saturday, 20 August 2022 at 18:59:40 UTC, IGotD- wrote:I never understood why the IEEE standard decided to include infinity. What were they trying to achieve? Indeterminate maths with floating point?I was curious about this too, so I did some searching. The Wikipedia page on floating-point arithmetic has a section titled "IEEE 754 design rationale" [1], which cites as one of its sources "Why do we need a floating-point arithmetic standard?" [2], a 1981 paper by William Kahan, one of the designers of IEEE 754. In that paper (on page 31), Kahan gives the following rationale for including values like NaN and infinities:the proposed standard specifies rules for creating and manipulating sym- bols like ±0, ±∞ and NaN – the symbol “NaN ” stands for “Not a Number”. These rules are designed so that a programmer may frequently omit tests and branches that were previously obligatory because computers treated exceptions in unpredictable or capricious ways. [...] At the same time as NaN is created a flag called Invalid Operation is raised. Subse- quently the calling program may infer either from this flag or from the NaN that an emergency arose and may cope with it automatically rather than abortSo the point is to simplify error handling, and to allow error handling to be deferred. [1] https://en.wikipedia.org/wiki/Floating-point_arithmetic#IEEE_754_design_rationale [2] https://people.eecs.berkeley.edu/~wkahan/ieee754status/why-ieee.pdf
Aug 20 2022
On Saturday, 20 August 2022 at 11:51:13 UTC, Adam D Ruppe wrote:On Saturday, 20 August 2022 at 10:26:08 UTC, Nick Treleaven wrote:Sorry, so there are other kinds of NaN than T.nan? How do you produce them? `0F/0F is float.nan` is true.On Saturday, 20 August 2022 at 03:12:43 UTC, Steven Schveighoffer wrote:That works for float.init specifically, but if you've done some operation on it and ended up with a nan, that will not necessarily be true since nans come in several bit patterns.You can't even `assert(x != double.init)`. You have to use an esoteric function `isNaN` for that.Actually, you can use `is`: ```d static assert(float() is float.nan); ```
Aug 20 2022
On 8/20/2022 4:51 AM, Adam D Ruppe wrote:That works for float.init specifically, but if you've done some operation on it and ended up with a nan, that will not necessarily be true since nans come in several bit patterns.I.e. a "payload" can be put in the mantissa bits of a NaN, which can be used to provide more information about the NaN. I've never seen anyone use this, though, but someone might, so isNaN() is the robust approach.
Aug 20 2022
On 8/20/22 20:44, Walter Bright wrote:I.e. a "payload" can be put in the mantissa bits of a NaN, which can be used to provide more information about the NaN.I think it is called "nan boxing."I've never seen anyone use this, though, but someone mightI heard about it either at a meetup or at a DConf. The speaker was explaining that exact technique. Ali
Aug 20 2022
On 8/20/2022 10:03 PM, Ali Çehreli wrote:On 8/20/22 20:44, Walter Bright wrote: > I.e. a "payload" can be put in the mantissa bits of a NaN, which can be > used to provide more information about the NaN. I think it is called "nan boxing."BTW, this influences code generation, too. For example: x = 0; y = NaN; z = x + y; z gets assigned a NaN. But which NaN? The NaN that was assigned to x. I.e. the specific NaN values get propagated.
Aug 21 2022
On Sunday, 21 August 2022 at 05:03:43 UTC, Ali Çehreli wrote:On 8/20/22 20:44, Walter Bright wrote:Just learnt from here: https://github.com/Robert-van-Engelen/tinylisp/issues/12#issuecomment-1752142467I.e. a "payload" can be put in the mantissa bits of a NaN,which can beused to provide more information about the NaN.I think it is called "nan boxing."I've never seen anyone use this, though, but someone mightI heard about it either at a meetup or at a DConf. The speaker was explaining that exact technique.I think I understand it now, the benefits of using NaN boxing is that: in a 64-bit double all the doubles are still fully represented use 48 bit as pointer can still address 262,144 GB memory, that is good enough for any computer today only integer's range gets shrunk: from 64-bit to 48-bit (49 with sign bit depends on if we choose to use it), that's good for most purpose, and if one really need > 48-bit integer type, then use the fat BigInt (class / struct) then (which will be treated as object pointer type). (1) and (3) means all the scalar types are stored as scalar, not pointers to some other representations. That's very compact design indeed.Another question I want ask is: the NaN boxing trick is OK, but why it's needed here (for education purpose Lisp implementation, this trick I think actually distracted learners from learning Lisp)? Why cannot we just use bit fields or a small struct as tagged union? Also by using NaN boxing, are we actually wasting 13 bits for each double?Lots of modern PL implementations use NaN boxing instead of tagged structs/unions. Nothing gets wasted, because a cell has to be a fixed size anyway, which is the larger size of all possible values it can hold. Adding a tag therefore makes the cell structure larger by a byte, at least, to hold a tag. That also makes addressing less efficient, since cells are no longer guaranteed to be 32 bit aligned (or the tag has to be 32 bits, which wasts more bits).
Oct 08 2023
On 10/8/2023 12:47 PM, mw wrote:That's very compact design indeed.Interestingly, the nan boxing in tinylisp exposed a subtle code gen problem with dmd (fixed now).
Oct 25 2023
On Saturday, 20 August 2022 at 03:12:43 UTC, Steven Schveighoffer wrote:In other words, NaN is silent. You can't even `assert(x != double.init)`. You have to use an esoteric function `isNaN` for that.I had some fun with `isNaN` the other day. We used it to check for initialisation in an access function to cache an expensive computation. This worked brilliantly until we noticed a malfunction in the release version. It took a while until I realised that I had given the LDC `fastmath` option to the release build, which assumes NaN does not occur, which makes `isNaN` misbehave. What I learned from this is to not use this flag globally, and add select attributes to select functions instead. And instead of using NaN I now use `std.typecons.Nullable` to signal a dirty cache. — Bastiaan.
Aug 22 2022
On Monday, 22 August 2022 at 20:29:57 UTC, Bastiaan Veelo wrote:On Saturday, 20 August 2022 at 03:12:43 UTC, Steven Schveighoffer wrote:Is there a simple example of this behavior?In other words, NaN is silent. You can't even `assert(x != double.init)`. You have to use an esoteric function `isNaN` for that.I had some fun with `isNaN` the other day. We used it to check for initialisation in an access function to cache an expensive computation. This worked brilliantly until we noticed a malfunction in the release version. It took a while until I realised that I had given the LDC `fastmath` option to the release build, which assumes NaN does not occur, which makes `isNaN` misbehave.
Aug 22 2022
On Monday, 22 August 2022 at 22:11:23 UTC, jmh530 wrote:On Monday, 22 August 2022 at 20:29:57 UTC, Bastiaan Veelo wrote:Yes: ```d import std; void main() { assert(isNaN(double.nan)); } ``` Compile with LDC and options `--ffast-math -O`. -- Bastiaan.I had some fun with `isNaN` the other day. We used it to check for initialisation in an access function to cache an expensive computation. This worked brilliantly until we noticed a malfunction in the release version. It took a while until I realised that I had given the LDC `fastmath` option to the release build, which assumes NaN does not occur, which makes `isNaN` misbehave.Is there a simple example of this behavior?
Aug 25 2022
On Thursday, 25 August 2022 at 18:05:36 UTC, Bastiaan Veelo wrote:On Monday, 22 August 2022 at 22:11:23 UTC, jmh530 wrote:One of the nice things about UDAs and so on is that you can use them to opt into specific optimizations LLVM can do without opting into the blatantly dangerous ones. http://johanengelen.github.io/ldc/2016/10/11/Math-performance-LDC.htmlOn Monday, 22 August 2022 at 20:29:57 UTC, Bastiaan Veelo wrote:Yes: ```d import std; void main() { assert(isNaN(double.nan)); } ``` Compile with LDC and options `--ffast-math -O`. -- Bastiaan.I had some fun with `isNaN` the other day. We used it to check for initialisation in an access function to cache an expensive computation. This worked brilliantly until we noticed a malfunction in the release version. It took a while until I realised that I had given the LDC `fastmath` option to the release build, which assumes NaN does not occur, which makes `isNaN` misbehave.Is there a simple example of this behavior?
Aug 25 2022
On Thursday, 25 August 2022 at 18:11:11 UTC, max haughton wrote:One of the nice things about UDAs and so on is that you can use them to opt into specific optimizations LLVM can do without opting into the blatantly dangerous ones. http://johanengelen.github.io/ldc/2016/10/11/Math-performance-LDC.htmlYes, that is the only responsible way to use this power. The individual flags are these: https://llvm.org/docs/LangRef.html#fast-math-flags to be used with this UDA: https://wiki.dlang.org/LDC-specific_language_changes#.40.28ldc.attributes.llvmFastMathFlag.28.22flag.22.29.29. Examples can be seen in Mir: http://mir-core.libmir.org/mir_math_common.html — Bastiaan.
Aug 25 2022
On 8/25/22 11:05, Bastiaan Veelo wrote:On Monday, 22 August 2022 at 22:11:23 UTC, jmh530 wrote:I found documentation on --fast-math here: https://clang.llvm.org/docs/UsersManual.html It includes "compiler make[s] [...] assumptions [...] Operands to floating-point operations are not equal to NaN and Inf" This is contrary to Walter's understanding, which I understand as "operations on NaN stay NaN". LLVM (at least Clang) seems to have a different take on NaN. And here is Phobos' isNaN implementation in math/traits.d: bool isNaN(X)(X x) nogc trusted pure nothrow if (isFloatingPoint!(X)) { version (all) { return x != x; } else { /* Code kept for historical context. At least on Intel, the simple test x != x uses one dedicated instruction (ucomiss/ucomisd) that runs in one cycle. Code for 80- and 128-bits is larger but still smaller than the integrals-based solutions below. Future revisions may enable the code below conditionally depending on hardware. */ // ... Removed by Ali } } LLVM must be thinking x != x is not a valid operation on NaN. Could we use a bit pattern check instead? Or write it as an asm block? AliOn Monday, 22 August 2022 at 20:29:57 UTC, Bastiaan Veelo wrote:Yes: ```d import std; void main() { assert(isNaN(double.nan)); } ``` Compile with LDC and options `--ffast-math -O`. -- Bastiaan.I had some fun with `isNaN` the other day. We used it to check for initialisation in an access function to cache an expensive computation. This worked brilliantly until we noticed a malfunction in the release version. It took a while until I realised that I had given the LDC `fastmath` option to the release build, which assumes NaN does not occur, which makes `isNaN` misbehave.Is there a simple example of this behavior?
Aug 25 2022
On Thursday, 25 August 2022 at 19:21:08 UTC, Ali Çehreli wrote:I found documentation on --fast-math here: https://clang.llvm.org/docs/UsersManual.html It includes "compiler make[s] [...] assumptions [...] Operands to floating-point operations are not equal to NaN and Inf" This is contrary to Walter's understanding, which I understand as "operations on NaN stay NaN". LLVM (at least Clang) seems to have a different take on NaN.It is not just "contrary to Walter's understanding", it is contrary to the IEEE 754 standard. Here is an article that goes into more detail about it: https://simonbyrne.github.io/notes/fastmath/LLVM must be thinking x != x is not a valid operation on NaN. Could we use a bit pattern check instead? Or write it as an asm block?LLVM with fast-math assumes that all floating-point operands are finite, which means that it can optimize `x != x` to `false` at compile time. A sufficiently smart optimizer could in principle perform the same optimization on a bit pattern check, if it recognized the bit pattern for NaN.
Aug 25 2022
On 8/25/2022 11:05 AM, Bastiaan Veelo wrote:Compile with LDC and options `--ffast-math -O`.https://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-actually-do I'd stay away from fast-math. If you want to use it, however, you're on your own as D assumes IEEE math.
Aug 28 2022
On Sunday, 28 August 2022 at 18:31:37 UTC, Walter Bright wrote:On 8/25/2022 11:05 AM, Bastiaan Veelo wrote:+1 "fast math" it also different from compiler to compiler, and sometimes makes things slower! Do you even need it for performance? Not sure, as just working on your vectorization, be it automatic or explicit, will leads to way better results. At least, that's my experience using the LLVM backend.Compile with LDC and options `--ffast-math -O`.https://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-actually-do I'd stay away from fast-math. If you want to use it, however, you're on your own as D assumes IEEE math.
Aug 30 2022
On 30/08/2022 10:23 PM, Guillaume Piolat wrote:Do you even need it for performance? Not sure, as just working on your vectorization, be it automatic or explicit, will leads to way better results. At least, that's my experience using the LLVM backend.I've talked about this quite a bit with Bruce. Our conclusion has been that explicit vectorization is usually the wrong path to take. It eats up developer time and provides very little benefit in majority of cases. If you feel like you need to reach for it, you probably haven't communicated to the backend enough information _to vectorize_. One bit of information that both LLVM and GCC can take advantage of ``assert(arg1 !is arg2);`` such a simple assert! Yet very valuable aliasing information in it. I love asserts.
Aug 30 2022
On Tuesday, 30 August 2022 at 16:01:24 UTC, rikki cattermole wrote:I've talked about this quite a bit with Bruce. Our conclusion has been that explicit vectorization is usually the wrong path to take. It eats up developer time and provides very little benefit in majority of cases.Well I wasn't talking about manual vectorization vs autovectorization, but about fastMath. That is another debate, and I'm of a different opinion, FWIW.
Aug 30 2022
On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:If there was a NaN value for int, I would have used it as the default. int.min is not really a NaN.But it should be! int.min is a notorious bogus value. You can't even use abs() on it: it will either give you a different type or return garbage. There is not even a working literal for it (at least for long.min). So it should never have been a valid value from beginning. The first thing I include in every of my programs is a module that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.
Aug 20 2022
On Saturday, 20 August 2022 at 18:05:59 UTC, Dom Disc wrote:On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:By the way, you don't have to write this yourself; you can use Checked!(int, WithNaN) [1] from std.checkedint. [1] https://phobos.dpldocs.info/std.checkedint.WithNaN.htmlIf there was a NaN value for int, I would have used it as the default. int.min is not really a NaN.But it should be! int.min is a notorious bogus value. You can't even use abs() on it: it will either give you a different type or return garbage. There is not even a working literal for it (at least for long.min). So it should never have been a valid value from beginning. The first thing I include in every of my programs is a module that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.
Aug 20 2022
By the way, you don't have to write this yourself; you can use Checked!(int, WithNaN) [1] from std.checkedint. [1] https://phobos.dpldocs.info/std.checkedint.WithNaN.htmlBTW, where to report Dlang website (doc) bug? https://dlang.org/phobos/std_experimental_checkedint.html This module is now deprecated, use std.experimental instead. <== should be std.checkedint The link is also wrong: https://dlang.org/phobos/std_experimental.html Oh No! Page Not Found
Aug 20 2022
issues.dlang.org For spec dlang.org otherwise for phobos/druntime their respective categories.
Aug 20 2022
On Saturday, 20 August 2022 at 21:38:13 UTC, mw wrote:BTW, where to report Dlang website (doc) bug? https://dlang.org/phobos/std_experimental_checkedint.html This module is now deprecated, use std.experimental instead. <== should be std.checkedint The link is also wrong: https://dlang.org/phobos/std_experimental.html Oh No! Page Not FoundReport it on issues.dlang.org as a bug in dlang.org.
Aug 20 2022
On Saturday, 20 August 2022 at 18:47:29 UTC, Paul Backus wrote:On Saturday, 20 August 2022 at 18:05:59 UTC, Dom Disc wrote:I know. I like my implementation better, but that's not the point. My point is: I include this in EVERY of my programs and never use other signed integers (unsigned values I use for bit-manipulation, not for calculations). checkedint should simply BE the int type, not a module.The first thing I include in every of my programs is a module that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.By the way, you don't have to write this yourself; you can use Checked!(int, WithNaN) [1] from std.checkedint. [1] https://phobos.dpldocs.info/std.checkedint.WithNaN.html
Aug 20 2022
On 8/20/2022 11:05 AM, Dom Disc wrote:On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:As soon as an operation is done on it, it isn't int.min anymore. It has some characteristics of a NaN, but not enough.If there was a NaN value for int, I would have used it as the default. int.min is not really a NaN.But it should be! int.min is a notorious bogus value. You can't even use abs() on it: it will either give you a different type or return garbage. There is not even a working literal for it (at least for long.min). So it should never have been a valid value from beginning. The first thing I include in every of my programs is a module that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.
Aug 20 2022
On Sunday, 21 August 2022 at 03:46:13 UTC, Walter Bright wrote:On 8/20/2022 11:05 AM, Dom Disc wrote:It's no problem to implement saveint so, that int.min stays at that value for all operations (except direct assignment). Ok, as library this may cost a little performance, but I think it's worth it.that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.As soon as an operation is done on it, it isn't int.min anymore. It has some characteristics of a NaN, but not enough.
Aug 21 2022
On 8/21/2022 2:00 AM, Dom Disc wrote:It's no problem to implement saveint so, that int.min stays at that value for all operations (except direct assignment). Ok, as library this may cost a little performance, but I think it's worth it.This may be what you're looking for: https://dlang.org/phobos/std_checkedint.html
Aug 25 2022
On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:The NaN value for char is 0xFF [...]. [...] (0xFF is specified as an illegal code point in Unicode.)The code point OxFF = U+00FF is ÿ: <https://codepoints.net/U+00FF>. It is the code unit [1]: "In valid UTF-8, the bytes 0xF5..0xFF cannot occur." [1] https://stackoverflow.com/questions/1319022/really-good-bad-utf-8-example-test-data
Aug 20 2022
On Friday, 19 August 2022 at 18:04:46 UTC, bachmeier wrote:On Friday, 19 August 2022 at 17:14:35 UTC, Steven Schveighoffer wrote:Any default value is an incorrect value unless it by luck happens to be what the programmer intended it to be. So while zero will often be incorrect I would argue that NaN is almost guaranteed to be incorrect. And here's the thing, you find some numerical code you've written and change some variable to zero init in instead of whatever it was. Your program wont appear to run properly, it'll give incorrect results, things wont work. There's this whole fallacy underpinning the default to NaN argument that using zero init will somehow leave programming appearing to run fine with no obvious problems. its nonsense.I also would prefer that all floats/doubles default to 0 instead of NaN.It would be awful to choose an arbitrary, often incorrect value in order to give the appearance that your program is running.It would be absurd to silently set the value of `z` to 1.0 in this code: ``` double w; double z = w*2.5 + 1; ``` Defaulting to 0 is no better than defaulting to a random number.What's absurd that the whole point of using NaN as an init value is to catch a bug that could much more easily be caught by requiring explicit initialisation of floats. double w; // compiler says NO!
Aug 19 2022
On Friday, 19 August 2022 at 23:11:35 UTC, claptrap wrote:double w; // compiler says NO!The compiler should prohibit such `statements`.
Aug 19 2022
On 8/19/2022 10:14 AM, Steven Schveighoffer wrote:```c ReallyLargeStruct foo = { 0 }; ```D allows the setting of the default initializer for fields of a struct.
Aug 19 2022
On 8/19/22 8:49 PM, Walter Bright wrote:On 8/19/2022 10:14 AM, Steven Schveighoffer wrote:Yes, and then you aren't forced to initialize the big struct. Which is what I did. But if I forget to initialize a float somewhere in there, then it's ruined. I suppose I can write a unittest to test that it's all zeroes. But I also find it ironic that you are promoting using the struct's init value as a feature, but not a basic type's init value. -Steve```c ReallyLargeStruct foo = { 0 }; ```D allows the setting of the default initializer for fields of a struct.
Aug 19 2022
On 8/19/2022 8:15 PM, Steven Schveighoffer wrote:But I also find it ironic that you are promoting using the struct's init value as a feature, but not a basic type's init value.The difference is it must be intentionally set for a field's value, and it is only for that field's value. It is not the default.
Aug 25 2022
On Friday, 19 August 2022 at 17:14:35 UTC, Steven Schveighoffer wrote:```c ReallyLargeStruct foo = { 0 }; ``` There just is no equivalent in D. In order to set all fields to 0, I would have to specify a complete layout of the entire thing. This could probably be done via introspection. But I just don't like it even in that case.Maybe something like this: ```d template ZeroInit(T) { union U { byte[T.sizeof] a; T zeroed; } enum ZeroInit = U().zeroed; } struct S { float f; float[2] a; } void main() { S s = ZeroInit!S; assert(s.f == 0); assert(s.a == [0,0]); } ```
Aug 20 2022
On Friday, 19 August 2022 at 16:34:59 UTC, Basile B. wrote:On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:Well, it **is** used as initialization substitute, if wasn't meant to be a substitute, not initializing a variable should be a compilation error. There's a lot of developers which uses bool and int because they make sense, when dealing with floating point they forget about that they do not make sense. I've never had any problem with float defaulting to 0 on Java. If the error happens, I get at max division by 0 exception. NaN does not cause this exception which actually makes the bug harder to find.As someone coming from Java to use D, I find it myself quite annoying that float and double are initialized to `nan`. This is really bad, it is hard to detect for newcomers, there is no flag by default to throw an exception when some operation on nan is done. It can be misleading if you're not paying a lot of attention to what you're doing. What I suggest is what any sane people would: use 0 as the start for float and double. 0 is the most common sense as a starting point for everything, and, there are 2 options we could go: 1: Emit a compilation error that every variable must be initialized (I thought D were trying to avoid runtime errors) 2: 0 init all types, so, none is actually invalid before use Even `char` took me as surprise to know it actually starts as 0xff, I lost a bit of time trying to find that bug because it is so common that variables init as zero. Although the `char` is a bit different beast in terms of breaking change, I really *can't see* anyone actually depending that your float is being initialized with `nan`, so I really would like to know how much people agree with this idea. It is so common to stumble on that problem that it is starting to feel as a real mistake.It's not a mistake, default initialization in D is not designed to be an initialization substitute, it's designed in a way that missing initialization is easily detectable but not UB. However, thruth is that this only works for character and floating point types. Changing that design would require a DIP I think.
Aug 19 2022
On Friday, 19 August 2022 at 18:57:25 UTC, Hipreme wrote:On Friday, 19 August 2022 at 16:34:59 UTC, Basile B. wrote:I know it is used as substitute but people writing in D should keep in mind that this is not the spirit of default init.On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:Well, it **is** used as initialization substitute, if wasn't meant to be a substitute, not initializing a variable should be a compilation error. [...][...]It's not a mistake, default initialization in D is not designed to be an initialization substitute, it's designed in a way that missing initialization is easily detectable but not UB. However, thruth is that this only works for character and floating point types. Changing that design would require a DIP I think.
Aug 19 2022
On Friday, 19 August 2022 at 18:57:25 UTC, Hipreme wrote:Well, it **is** used as initialization substitute, if wasn't meant to be a substitute, not initializing a variable should be a compilation error.0, false, null array, etc. are all identities of the "primary" operation on the type, so people intuitively expect them to be the default initial value. I believe that's why most think nan is unnatural.
Aug 19 2022
On 8/19/2022 9:34 AM, Basile B. wrote:It's not a mistake, default initialization in D is not designed to be an initialization substitute, it's designed in a way that missing initialization is easily detectable but not UB.The idea is if you're looking at code: double d; is `d` expected to be initialized to 0.0, or did the programmer just forget to initialize it? D removes that ambiguity.
Aug 19 2022
On 8/19/22 06:42, Hipreme wrote:that float and double are initialized to `nan`.I think nan is the right choice. As Walter said, integrals are the outliers because there is not non equivalent for them.This is really badAlthough we are all guilty, what is worse is using fundamental types directly. I think the following is a solution to nan being inappropriate e.g. for Distance: struct initted(T, T initValue) { T value = initValue; alias value this; } alias Distance = initted!(double, 0); void main() { Distance d; // Not a nan ;) d += 1.5; d /= 2; assert(d == 0.75); } However, it is not type-safe enough because one can mix and match Distance with e.g. Temperature, which may not be correct for the program. Ali
Aug 19 2022
On Saturday, 20 August 2022 at 04:04:08 UTC, Ali Çehreli wrote:On 8/19/22 06:42, Hipreme wrote:`units of measure` https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measurethat float and double are initialized to `nan`.I think nan is the right choice. As Walter said, integrals are the outliers because there is not non equivalent for them.This is really badAlthough we are all guilty, what is worse is using fundamental types directly. I think the following is a solution to nan being inappropriate e.g. for Distance: struct initted(T, T initValue) { T value = initValue; alias value this; } alias Distance = initted!(double, 0); void main() { Distance d; // Not a nan ;) d += 1.5; d /= 2; assert(d == 0.75); } However, it is not type-safe enough because one can mix and match Distance with e.g. Temperature, which may not be correct for the program. Ali
Aug 20 2022
On Saturday, 20 August 2022 at 07:08:50 UTC, Tejas wrote:`units of measure` https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measureIf needed, units are possible at compile time using template and enumerator. Walter showed much better in DConf'22: **Title:** Using Enums to Generate Scoped List of Names, p.32 **Source:** https://github.com/dlang/dconf.org/blob/master/2022/slides/bright.pdf Thanks to Andrey Zherikov SDB 79
Aug 20 2022
On Saturday, 20 August 2022 at 04:04:08 UTC, Ali Çehreli wrote:On 8/19/22 06:42, Hipreme wrote:Arrays are outliars as well because .init is not an "invalid" value of them. string s; string s2 = s ~ "foo"; // omg, s2 now is a valid string! And any aggregation of the outliars is also an outlier. And now there are too many of them to be called outliars.that float and double are initialized to `nan`.I think nan is the right choice. As Walter said, integrals are the outliers because there is not non equivalent for them.
Aug 20 2022
On Saturday, 20 August 2022 at 09:53:58 UTC, Max Samukha wrote:Arrays are outliars as well because .init is not an "invalid" value of them. string s; string s2 = s ~ "foo"; // omg, s2 now is a valid string! And any aggregation of the outliars is also an outlier. And now there are too many of them to be called outliars.*outlier I don't know why my brain did it to me.
Aug 20 2022
On Saturday, 20 August 2022 at 04:04:08 UTC, Ali Çehreli wrote:I think the following is a solution to nan being inappropriate e.g. for Distance: struct initted(T, T initValue) { T value = initValue; alias value this; } alias Distance = initted!(double, 0); void main() { Distance d; // Not a nan ;) d += 1.5; d /= 2; assert(d == 0.75); } However, it is not type-safe enough because one can mix and match Distance with e.g. Temperature, which may not be correct for the program. AliEnter `std.typecons.Typefef`: ```d import std; alias Distance = Typedef!(double, 0.0, "distance"); alias Temperature = Typedef!(double, 0.0, "temperature"); void main() { Temperature t; Distance d; d += 4.5; // t = d; // does not compile } ``` However, type information can get lost in intermediate results: ```d t = 0.5 + d; // result is double ``` — Bastiaan
Aug 20 2022
On 8/20/22 14:07, Bastiaan Veelo wrote:alias Distance = Typedef!(double, 0.0, "distance");Great! :)However, type information can get lost in intermediate results: ```d t = 0.5 + d; // result is double ```Yeah, that's a bummer. Perhaps something like this could work: "have all the functionality of a double but don't implicitly convert to one." (Ironically, alias this is the implicit conversion tool.) And what do I mean? Only when being passed to a function? I don't know... :/ Ali
Aug 20 2022
On Saturday, 20 August 2022 at 21:07:33 UTC, Bastiaan Veelo wrote:```d import std; alias Distance = Typedef!(double, 0.0, "distance"); alias Temperature = Typedef!(double, 0.0, "temperature"); void main() { Temperature t; Distance d; d += 4.5; // t = d; // does not compile } ``` However, type information can get lost in intermediate results: ```d t = 0.5 + d; // result is double ```It's very simple and beautiful. Thank you, very delicious! SDB 79
Aug 21 2022
On Monday, 22 August 2022 at 01:09:53 UTC, Salih Dincer wrote:It's very simple and beautiful. Thank you, very delicious!except for ugly error messages :(
Aug 21 2022
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:Although the `char` is a bit different beast in terms of breaking change, I really *can't see* anyone actually depending that your float is being initialized with `nan`, so I really would like to know how much people agree with this idea. It is so common to stumble on that problem that it is starting to feel as a real mistake.I personally like how D does it. Once you know that floats have a "nothing" value, it's very convenient that it's the initialisation value, for the same reason `null` is a convenient initialisation value for pointers and class references. But I can see that if I didn't know about NaNs, this would be annoying. The probably many other languages) do so one is easily surprised. However, the big philosophy behind it is that D *always* uses an "empty" value as the initialisation value if there is one, so for D this is the right thing to do. Using 0 as float `.init` would be inconsistent with rest of the language. Whether this underlying philosophy is a good idea is debatable though. Personally I think the philosophy has it's ups and downs but easy to like once you get used to it.
Aug 20 2022
On 8/20/2022 3:17 PM, Dukc wrote:probably many other languages) do so one is easily surprised.C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.
Aug 22 2022
On 8/22/22 8:50 PM, Walter Bright wrote:On 8/20/2022 3:17 PM, Dukc wrote:Agreed that C/C++ initializing with garbage is the worst option. I'm curious what all languages do that actually use an initial value? -Stevedo so one is easily surprised.C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.
Aug 22 2022
Did NaN replace any float/double values in memory?
Aug 22 2022
I have seen how polar people's view points are on this issue. This is why I have created a library to solve this. Now people who wish floating points init to 0 can have it! https://code.dlang.org/packages/j_init
Aug 23 2022
I have seen how polar people's view points are on this issue. This is why I have created a library to solve this. Now people who wish floating points init to 0 can have it! https://code.dlang.org/packages/j_init
Aug 23 2022
On Tuesday, 23 August 2022 at 08:03:44 UTC, jordan4ibanez wrote:I have seen how polar people's view points are on this issue. This is why I have created a library to solve this. Now people who wish floating points init to 0 can have it! https://code.dlang.org/packages/j_initThe problem with this is metaprogramming will break because you will need to handle your Float/Double type apart from float/double. Ex. ```d // This function might not be something we can modify auto add(Number)(Number x, Number y) if (is(Number == float) || is(Number == double)) { return x + y; } void main() { Float f1; Float f2; // Error: // writeln(add(f1, f2)); // To fix it: writeln(add(cast(float)f1, f2)); } ``` By using your struct implementation then one has to handle those two types as well, otherwise it will break from stuff like shown above. So there's really no actual good way to override default initialization values.
Aug 23 2022
On Tuesday, 23 August 2022 at 01:19:35 UTC, Steven Schveighoffer wrote:Agreed that C/C++ initializing with garbage is the worst option. I'm curious what all languages do that actually use an initial value? -SteveC++11 default value initialization exist. Meaning this ```c++ double x{}; ``` is going to be initialized to zero. D is really an outlier here with default initialization to NaN. I would rephrase you initial question to a challenge, find a language other than D that default initializes floats to NaN.
Aug 23 2022
On 8/23/22 01:07, IGotD- wrote:On Tuesday, 23 August 2022 at 01:19:35 UTC, Steven Schveighoffer wrote:At that level, it's the same in D: // Garbage value: double x = void; // D double x; // C++ // Zero value: double x = 0; // D double x{}; // C++ However, there is a difference with members: struct S { double x; } // Add ; here for C++ S(); // S.x is double.nan in D S{}; // S.x is 0 in C++Agreed that C/C++ initializing with garbage is the worst option. I'm curious what all languages do that actually use an initial value? -SteveC++11 default value initialization exist. Meaning this ```c++ double x{}; ```find a language other than D that default initializes floats to NaN.I failed with a quick search. However, I still think initial value being nan is not an issue even if it does not meet programmer expectations. For example, D could not leave the value as garbage as C++ programmers comfortably expect so. And I am pretty sure the default value cannot be changed for D at this time. Ali
Aug 23 2022
On Tuesday, 23 August 2022 at 15:27:05 UTC, Ali Çehreli wrote:However, I still think initial value being nan is not an issue even if it does not meet programmer expectations. For example, D could not leave the value as garbage as C++ programmers comfortably expect so. And I am pretty sure the default value cannot be changed for D at this time. AliIt's too late for D2 but for D3 this should be taken into consideration. We are starting to acquire a big list of things that can be done for D3 now.
Aug 23 2022
On 8/22/2022 6:19 PM, Steven Schveighoffer wrote:I'm curious what all languages do that actually use an initial value?AFAIK D is unique in using NaN.
Aug 24 2022
On Tuesday, 23 August 2022 at 00:50:21 UTC, Walter Bright wrote:On 8/20/2022 3:17 PM, Dukc wrote:Dont most C/C++ compilers have warnings for initialised variables? I'm sure MSVC did when I was using it, but its 15 years ago now.languages) do so one is easily surprised.C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.
Aug 23 2022
On Tuesday, 23 August 2022 at 09:00:59 UTC, claptrap wrote:On Tuesday, 23 August 2022 at 00:50:21 UTC, Walter Bright wrote:Yeah, but there's also bugs in gcc, apparently https://stackoverflow.com/questions/14132898/gcc-wuninitialized-wmaybe-uninitialized-issuesOn 8/20/2022 3:17 PM, Dukc wrote:Dont most C/C++ compilers have warnings for initialised variables? I'm sure MSVC did when I was using it, but its 15 years ago now.languages) do so one is easily surprised.C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.
Aug 23 2022
On 8/23/2022 2:00 AM, claptrap wrote:Dont most C/C++ compilers have warnings for initialised variables? I'm sure MSVC did when I was using it, but its 15 years ago now.I just tried it with gcc. No warning.
Aug 23 2022
On Wednesday, 24 August 2022 at 05:57:38 UTC, Walter Bright wrote:On 8/23/2022 2:00 AM, claptrap wrote:Most of gcc's warnings, including this one, are not enabled by default. If you compile with -Wall, you will get a warning.Dont most C/C++ compilers have warnings for initialised variables? I'm sure MSVC did when I was using it, but its 15 years ago now.I just tried it with gcc. No warning.
Aug 24 2022
On 8/24/2022 5:17 AM, Paul Backus wrote:On Wednesday, 24 August 2022 at 05:57:38 UTC, Walter Bright wrote:Fair enough, though that makes it clear that there are many languages called C, and Standard C does not complain about it.On 8/23/2022 2:00 AM, claptrap wrote:Most of gcc's warnings, including this one, are not enabled by default. If you compile with -Wall, you will get a warning.Dont most C/C++ compilers have warnings for initialised variables? I'm sure MSVC did when I was using it, but its 15 years ago now.I just tried it with gcc. No warning.
Aug 24 2022
On Tuesday, 23 August 2022 at 00:50:21 UTC, Walter Bright wrote:C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.I agree that NaN for uninitialized floats is the best option. However, can we get a switch to force initialization of floats? it would be of great help to quickly find the place where one forgot to initialize a variable.
Aug 23 2022
On Tuesday, 23 August 2022 at 11:08:36 UTC, Zoadian wrote:On Tuesday, 23 August 2022 at 00:50:21 UTC, Walter Bright wrote:Walter makes good points in favor of NaN as a default, but I agree this would be useful for identifying the source of the problem, so long as it is primarily used for debugging purposes. For instance, if we could do something like `debug(force-float-initialization, VALUE)` where VALUE defaults to zero but represents the value that uninitialized floats would get initialized to, then that would be helpful (a pragma might be an alternative to a debug statement). After all, if you are writing a function that unexpectedly returns a NaN, then you can put that up top and see if it returns something else. Being able to modify the VALUE would help identify the issue in more complicated functions.C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.I agree that NaN for uninitialized floats is the best option. However, can we get a switch to force initialization of floats? it would be of great help to quickly find the place where one forgot to initialize a variable.
Aug 23 2022
We could make it the worst of both worlds. We could have it so sometimes an unitialized float or double is NaN and make it be the garbage data that was the memory address depending on if a random number is below 0.5 or not. I'm kidding. I would actually prefer it to throw an error if you did not initialize a variable. :) This would make programming more explicit upfront but prevent you from tearing out your hair in a few months where a part of a library you're using suddenly starts throwing weird errors out and you are left with a cup full of tears. This goes for all variables of primitive type to use Java speak. This would not only solve the issue of "OI IT SHOULD BE ZERO!!" and "OI IT SHOULD BE NAN!!!". No way Jose, it should be what you tell it to be because the computer should do what you told it to do when creating those values, not guess. Because it can only tell how you're trying to do it, not what you're trying to do. It's not a soothsayer, it's a glorified calculator.
Aug 20 2022
Consider the following pattern, which doesn't appear frequently, but frequently enough: double x; if (condition) { x = 5; ... } ... // (1) if (condition) { foo(x); } Imagine there's a lot more code omitted which obscures the pattern. This code is correct. Now, maintainer adds `bar(x)` at (1). The scenarios: 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem. 2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed. 3. compiler complains that `double x;` needs an initializer. To shut up the compiler, the user initializes it to 0, without putting much thought into it. bar(0) may exhibit problems, but these won't necessarily be noticed. 4. compiler complains that `double x;` needs an initializer. Coder just schlepps in a 0. Yes, this happens. Maintainer wastes time wondering why x is initialized to 0, as that may be a nonsense value for x. Maintainer wonders if this unused initialization has a purpose, maybe it is the result of a bad refactoring? Wastes more time investigating it. D chose option 1. BTW, option 1 is very analogous to the common "Optional" types which can be either an error value or a valid value. Optional types propagate just like NaNs do.
Aug 21 2022
On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:Consider the following pattern, which doesn't appear 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem. 2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed.This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.
Aug 21 2022
On 8/21/22 20:28, claptrap wrote:On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong? To detect it you should track down manually checking the intermediate results that is manually calculate results and compare to what you get. It takes much more time than checking if the value is NaN.Consider the following pattern, which doesn't appear 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem. 2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed.This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.
Aug 21 2022
On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:On 8/21/22 20:28, claptrap wrote:Price for this float=NaN & char=FF 1. Runtime bloat -> all struct/class with (float or char) need special initializer 2. Slow -> all struct/class not able to utilize zero initialized from memory manager 3. Inconsistent with other value types (all zero bits) 4. Aggregated/Sum float var should start with zero So -> Better error when var is not initialized than this special valueOn Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong? To detect it you should track down manually checking the intermediate results that is manually calculate results and compare to what you get. It takes much more time than checking if the value is NaN.Consider the following pattern, which doesn't appear 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem. 2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed.This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.
Aug 21 2022
On Sunday, 21 August 2022 at 19:57:52 UTC, apz28 wrote:Price for this float=NaN & char=FF 1. Runtime bloat -> all struct/class with (float or char) need special initializer 2. Slow -> all struct/class not able to utilize zero initialized from memory manager 3. Inconsistent with other value types (all zero bits) 4. Aggregated/Sum float var should start with zero So -> Better error when var is not initialized than this special valueThese are very good points which I agree with. Previously I was a bit it didn't matter for me (either Nan or 0.0) but with these my mind tipped over in favor of zero for both char and floats. It is a better design because of the consistency as well it enables the optimizer to use large moves in order to initialize the memory. However, will it be the real use case after optimizing away unused values, that is the question.
Aug 21 2022
On 8/21/22 22:57, apz28 wrote:Let me disagree to you 1) Every struct/class needs special initializer because datatypes definitely are different. According to your logic user should initialize all fields to zero and only zero. No other values are possible. It is really strange point. 2) Again you argue against non-zero initialized fields in aggregate types. 3) Once again - not all types should be zero initialized. For example, covariance matrix in Kalman Filter should NOT be initialized to zero. In other case the filter won't work at all. 4) No, you are wrong again. sum accumulator should not start with zero, in other case sum algorithm has no this argument at all, right?It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong? To detect it you should track down manually checking the intermediate results that is manually calculate results and compare to what you get. It takes much more time than checking if the value is NaN.Price for this float=NaN & char=FF 1. Runtime bloat -> all struct/class with (float or char) need special initializer 2. Slow -> all struct/class not able to utilize zero initialized from memory manager 3. Inconsistent with other value types (all zero bits) 4. Aggregated/Sum float var should start with zero So -> Better error when var is not initialized than this special value
Aug 21 2022
On Sunday, 21 August 2022 at 19:57:52 UTC, apz28 wrote:Price for this float=NaN & char=FF 1. Runtime bloat -> all struct/class with (float or char) need special initializerNo. If intentional you can explicitly leave them uninitialized (= void)2. Slow -> all struct/class not able to utilize zero initialized from memory managerFill with specific pattern is _really_ fast, so very very low performance lost - and only once as you shouldn't do initialization in a loop, do you?3. Inconsistent with other value types (all zero bits)I agree to this, but you choose the wrong solution. Correct would be to initialize the remaining types also with an invalid value instead of zero.4. Aggregated/Sum float var should start with zeroWhy? For this to be an argument on its own, it should not refer to (1)..(3) So: no argument left. Too bad.
Aug 22 2022
On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:On 8/21/22 20:28, claptrap wrote:You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised. You're just inventing nonsense scenarios. And seriously if you're looking a variable and dont know what value it should be initialised too you literally *dont know what your doing*.On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong?Consider the following pattern, which doesn't appear 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem. 2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed.This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.To detect it you should track down manually checking the intermediate results that is manually calculate results and compare to what you get. It takes much more time than checking if the value is NaN.Occasionally you might have to do a bit of mental arithmetic, but not often, I'm seriously wondering why you think it's so hard?
Aug 22 2022
On 8/22/22 18:04, claptrap wrote:On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:But that is my point - not all variables initialize to zero. It is my statement that this is nonsense scenarios. Reread the post carefully.On 8/21/22 20:28, claptrap wrote:You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised. You're just inventing nonsense scenarios.On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong?Consider the following pattern, which doesn't appear 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem. 2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed.This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.And seriously if you're looking a variable and dont know what value it should be initialised too you literally *dont know what your doing*.Just because I've done math calculations before? And no, I didn't mean mental arithmetic. I meant numerical matrix operations from inputs to outputs just to track down where was wrong zero initialization. In some cases zero initialization is invalid, for example covariance of random variables. But NaN is invalid always. That is its advantage.To detect it you should track down manually checking the intermediate results that is manually calculate results and compare to what you get. It takes much more time than checking if the value is NaN.Occasionally you might have to do a bit of mental arithmetic, but not often, I'm seriously wondering why you think it's so hard?
Aug 22 2022
On Monday, 22 August 2022 at 15:56:16 UTC, drug007 wrote:On 8/22/22 18:04, claptrap wrote:"You've initialized all vars to 0" I can only respond to what you write, (which was a nonsense scenario.)On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:But that is my point - not all variables initialize to zero. It is my statement that this is nonsense scenarios. Reread the post carefully.On 8/21/22 20:28, claptrap wrote:You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised. You're just inventing nonsense scenarios.On Sunday, 21 August 2022 at 16:51:51 UTC, Walter BrightIt will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong?I've been programming for over 30 years, mostly DSP and some numerical stuff, statistical analysis. My experience is that its not a big deal. My point is people are massively overselling how much of a problem bad inits are to track down.Occasionally you might have to do a bit of mental arithmetic, but not often, I'm seriously wondering why you think it's so hard?Just because I've done math calculations before? And no, I didn't mean mental arithmetic. I meant numerical matrix operations from inputs to outputs just to track down where was wrong zero initialization. In some cases zero initialization is invalid, for example covariance of random variables. But NaN is invalid always. That is its advantage.
Aug 22 2022
On 8/23/22 02:08, claptrap wrote:On Monday, 22 August 2022 at 15:56:16 UTC, drug007 wrote:I'm so sorry, but you failed to reread post above carefully again. My point is not all data initialize zero. That is the reason why floating point number should be defaulted as NaN. Because you clearly can see what data hasn't been initialized at all.On 8/22/22 18:04, claptrap wrote:"You've initialized all vars to 0" I can only respond to what you write, (which was a nonsense scenario.)On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:But that is my point - not all variables initialize to zero. It is my statement that this is nonsense scenarios. Reread the post carefully.On 8/21/22 20:28, claptrap wrote:You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised. You're just inventing nonsense scenarios.On Sunday, 21 August 2022 at 16:51:51 UTC, Walter BrightIt will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong?My experience is it is a big deal enough.I've been programming for over 30 years, mostly DSP and some numerical stuff, statistical analysis. My experience is that its not a big deal.Occasionally you might have to do a bit of mental arithmetic, but not often, I'm seriously wondering why you think it's so hard?Just because I've done math calculations before? And no, I didn't mean mental arithmetic. I meant numerical matrix operations from inputs to outputs just to track down where was wrong zero initialization. In some cases zero initialization is invalid, for example covariance of random variables. But NaN is invalid always. That is its advantage.My point is people are massively overselling how much of a problem bad inits are to track down.
Aug 22 2022
On Monday, 22 August 2022 at 15:04:25 UTC, claptrap wrote:You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised.So, if you rarely ever use default initialization, why do you care to which value it might be initialized? For the analysis which default value is the better one, only the cases where it is used matters. You need only count how often is a variable not initialized, and of those how many times is this (a) a bug or (b) intended. Now imagine you review code from someone else (e.g. at an assessment). In this case you have to carefully check every case of uninitialized variable. If the code always explicitly say =void or =0, there are no such cases, so you might save a LOT of time. So better get used to ALWAYS initialize explicitly and consider EVERY occurrence of uninitialized variable to be a bug. And bogus code should NEVER result in a value that could also occur as a valid result, so the compiler should help as much as it can by using an invalid value if one is available.
Aug 22 2022
On Monday, 22 August 2022 at 19:49:02 UTC, Dom Disc wrote:On Monday, 22 August 2022 at 15:04:25 UTC, claptrap wrote:NaN or Zero I dont really care, I just got sucked in, there's a fair amount of BS floating around.You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised.So, if you rarely ever use default initialization, why do you care to which value it might be initialized?
Aug 22 2022
On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:3. compiler complains that `double x;` needs an initializer. To shut up the compiler, the user initializes it to 0, without putting much thought into it. bar(0) may exhibit problems, but these won't necessarily be noticed.In many cases, `0` can solve that problem. The real problem is that sometimes it is not appropriate to initialize with 0. The compiler should collect these 0 initialization locations to better track possible `mistakes`.
Aug 21 2022
On 8/21/22 12:51 PM, Walter Bright wrote:Consider the following pattern, which doesn't appear frequently, but frequently enough: double x; if (condition) { x = 5; ... } ... // (1) if (condition) { foo(x); } Imagine there's a lot more code omitted which obscures the pattern. This code is correct. Now, maintainer adds `bar(x)` at (1). The scenarios: 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem.How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed.Just like NaN.3. compiler complains that `double x;` needs an initializer. To shut up the compiler, the user initializes it to 0, without putting much thought into it. bar(0) may exhibit problems, but these won't necessarily be noticed. 4. compiler complains that `double x;` needs an initializer. Coder just schlepps in a 0. Yes, this happens. Maintainer wastes time wondering why x is initialized to 0, as that may be a nonsense value for x. Maintainer wonders if this unused initialization has a purpose, maybe it is the result of a bad refactoring? Wastes more time investigating it.Huh? Why are there 2 identical situations here? I'll also point out that not initializing an integer is sometimes intentionally done (because it's equivalent to initializing to 0). If I see someone didn't assign a value to an int, I don't question if it was an accident, I expect that they meant it. Also, you forgot: 5. Maintainer expected x to default to 0 (because that's what most types do), and expected bar to be called with 0 or 5. Now, since bar saved the result of it's calculation elsewhere, and then far away from this code, the result is used in some computation that finally makes its way to output in some fashion (and possibly not a specific printing of the value), now there's a puzzle to solve, and no way to know it can be traced back to x without hours/days of searching.D chose option 1.And there's probably no way that it changes. But in my mind the correct answer is to intialize to 0. -Steve
Aug 22 2022
On Monday, 22 August 2022 at 11:41:33 UTC, Steven Schveighoffer wrote:On 8/21/22 12:51 PM, Walter Bright wrote:Assuming this isn't a rhetoric question... It's not as convenient as a segfault but at some point, the error becomes obvious. I would start there to inspect variables, identify the NaNs. Then I would trace them in a debugger and go up the call chain until I find the location where it became NaN. Then I would identify the source which introduced the NaN and trace that back until I found its origin. The advantage I see in NaN is that it's always (instead of only almost always) immediately obvious that it's wrong whereas 0.0 can be valid or invalid so you need to figure out which one it is which requires an extra step.Consider the following pattern, which doesn't appear frequently, but frequently enough: double x; if (condition) { x = 5; ... } ... // (1) if (condition) { foo(x); } Imagine there's a lot more code omitted which obscures the pattern. This code is correct. Now, maintainer adds `bar(x)` at (1). The scenarios: 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem.How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?
Aug 22 2022
On 8/22/22 9:17 AM, wjoe wrote:On Monday, 22 August 2022 at 11:41:33 UTC, Steven Schveighoffer wrote:It's not.On 8/21/22 12:51 PM, Walter Bright wrote:Assuming this isn't a rhetoric question...Consider the following pattern, which doesn't appear frequently, but frequently enough: double x; if (condition) { x = 5; ... } ... // (1) if (condition) { foo(x); } Imagine there's a lot more code omitted which obscures the pattern. This code is correct. Now, maintainer adds `bar(x)` at (1). The scenarios: 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem.How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?It's not as convenient as a segfault but at some point, the error becomes obvious.Does it? And "at some point" it becomes obvious no matter what the error you made.I would start there to inspect variables, identify the NaNs.What if you can't? What if it only happens randomly, and you don't just happen to have a debugger attached? I'm not saying it's easier with 0, but just not any different.Then I would trace them in a debugger and go up the call chain until I find the location where it became NaN. Then I would identify the source which introduced the NaN and trace that back until I found its origin.If you have a chance to use a debugger and it happens at that time.The advantage I see in NaN is that it's always (instead of only almost always) immediately obvious that it's wrong whereas 0.0 can be valid or invalid so you need to figure out which one it is which requires an extra step.It might be noticed that it's NaN. It also might not. It depends on how it's used. Either way, you need to find the source, and NaN doesn't help unless you want to start either instrumenting *all* code (possibly including code you don't control), or use a debugger (which isn't always possible). Can we have some kind of linting system that identifies NaNs that are used? -Steve
Aug 22 2022
On 8/22/2022 7:06 AM, Steven Schveighoffer wrote:The point is, since 0.0 is a common value for a floating point value to be, just when does it become obvious that it is wrong? Are you really going to notice if your computation is 5% off? Isn't it a *lot* more obvious that it is wrong if it is NaN?It's not as convenient as a segfault but at some point, the error becomes obvious.Does it? And "at some point" it becomes obvious no matter what the error you made.0.0 is hardly a rare value, even in correct calculations. NaN is always wrong.I would start there to inspect variables, identify the NaNs.What if you can't? What if it only happens randomly, and you don't just happen to have a debugger attached? I'm not saying it's easier with 0, but just not any different.0 initialization wouldn't make it better.Then I would trace them in a debugger and go up the call chain until I find the location where it became NaN. Then I would identify the source which introduced the NaN and trace that back until I found its origin.If you have a chance to use a debugger and it happens at that time.NaN propagates. 0.0 does not.The advantage I see in NaN is that it's always (instead of only almost always) immediately obvious that it's wrong whereas 0.0 can be valid or invalid so you need to figure out which one it is which requires an extra step.It might be noticed that it's NaN. It also might not. It depends on how it's used.Either way, you need to find the source, and NaN doesn't help unless you want to start either instrumenting *all* code (possibly including code you don't control), or use a debugger (which isn't always possible).Such a situation is objectively worse with 0.0. Is instrumenting all the code to detect 0.0 going to work? Nope, too many false positives, as 0.0 is a common value for floating point numbers.Can we have some kind of linting system that identifies NaNs that are used?I have no objection to a linter that flags default initializations of floating point values. It shouldn't be part of the D compiler, though.
Aug 22 2022
On 8/22/22 8:46 PM, Walter Bright wrote:On 8/22/2022 7:06 AM, Steven Schveighoffer wrote:This is a highly dependent situation. It could be 0, which is 100% off. It could be 5%. It could be 0.0001% off, which might actually not be a problem that is noticed. So I have an actual true story. One of the calculation spreadsheets we use had a fudge factor that someone inserted. Essentially, they added a value of 0.35 to a cost field (which is in the tens of thousands of dollars range). Given this is Excel we have no way of knowing who did it or when (probably to make it match some utility-provided tool value). But we didn't catch it for months. Only until we had a job where the cost was 100% covered by the utility, and the cost came out to $0.35, we caught it. This happened because it added 0.35 to 0 (the default value of an empty cell). If instead it printed NaN I would have ignored that price, and just put 0 in *at a later calculation* to prevent errors showing up in the final proposal. Then I would have missed the fudge factor someone sneaked in. The situations are completely dependent on the situation for *finding a problem*, for *diagnosing a problem* and for *fixing the problem*. It's impossible to predict how people will behave or how they will write code to cope with the situation they have. I think it's a wash in using either 0 or NaN for a default value when that value is incorrect. But I think in terms of *frequency*, a default value of 0 for a float that isn't explicitly initialized is 99% of the time correct, which means you will have *less of these problems to find*.The point is, since 0.0 is a common value for a floating point value to be, just when does it become obvious that it is wrong? Are you really going to notice if your computation is 5% off? Isn't it a *lot* more obvious that it is wrong if it is NaN?It's not as convenient as a segfault but at some point, the error becomes obvious.Does it? And "at some point" it becomes obvious no matter what the error you made.It's not rare because it's a very very common initial value.0.0 is hardly a rare value, even in correct calculations. NaN is always wrong.I would start there to inspect variables, identify the NaNs.What if you can't? What if it only happens randomly, and you don't just happen to have a debugger attached? I'm not saying it's easier with 0, but just not any different.I will concede that if you have a debugger attached and can watch the things change in real time, seeing NaN show up can give you a better clue as to where the problem came from.0 initialization wouldn't make it better.Then I would trace them in a debugger and go up the call chain until I find the location where it became NaN. Then I would identify the source which introduced the NaN and trace that back until I found its origin.If you have a chance to use a debugger and it happens at that time.Someone has to look at it, to "obviously" see that it's wrong.NaN propagates. 0.0 does not.The advantage I see in NaN is that it's always (instead of only almost always) immediately obvious that it's wrong whereas 0.0 can be valid or invalid so you need to figure out which one it is which requires an extra step.It might be noticed that it's NaN. It also might not. It depends on how it's used.Either way, it's a mess. Better to just logically trace it based on where it's assigned from, instead of instrumenting, and trying to find NaNs in random places.Either way, you need to find the source, and NaN doesn't help unless you want to start either instrumenting *all* code (possibly including code you don't control), or use a debugger (which isn't always possible).Such a situation is objectively worse with 0.0. Is instrumenting all the code to detect 0.0 going to work? Nope, too many false positives, as 0.0 is a common value for floating point numbers.Something with semantic capabilities has to be used to prove it's not set before being used. Is there anything besides the compiler front end that can do this? -SteveCan we have some kind of linting system that identifies NaNs that are used?I have no objection to a linter that flags default initializations of floating point values. It shouldn't be part of the D compiler, though.
Aug 22 2022
On 8/22/2022 6:16 PM, Steven Schveighoffer wrote:Of course. And NaN is always wrong.The point is, since 0.0 is a common value for a floating point value to be, just when does it become obvious that it is wrong? Are you really going to notice if your computation is 5% off? Isn't it a *lot* more obvious that it is wrong if it is NaN?This is a highly dependent situation. It could be 0, which is 100% off. It could be 5%. It could be 0.0001% off, which might actually not be a problem that is noticed.If instead it printed NaN I would have ignored that price, and just put 0 in *at a later calculation* to prevent errors showing up in the final proposal. Then I would have missed the fudge factor someone sneaked in.If you ignore the NaN value, you can hardly then blame it for missing the fudge factor.But I think in terms of *frequency*, a default value of 0 for a float that isn't explicitly initialized is 99% of the time correct, which means you will have *less of these problems to find*.See my other post about having code work by happenstance 99% of the time being not what D is about.0.0 a commonplace value everywhere.0.0 is hardly a rare value, even in correct calculations. NaN is always wrong.It's not rare because it's a very very common initial value.If you never look at the output, no bugs will be noticed in it anyway.NaN propagates. 0.0 does not.Someone has to look at it, to "obviously" see that it's wrong.Something with semantic capabilities has to be used to prove it's not set before being used. Is there anything besides the compiler front end that can do this?You need data flow analysis for that. I didn't put DFA in the front end because that makes it slow for little benefit.
Aug 25 2022
On Tuesday, 23 August 2022 at 00:46:31 UTC, Walter Bright wrote:I have no objection to a linter that flags default initializations of floating point values. It shouldn't be part of the D compiler, though.We already have a back end error (only when optimization is enabled) that detects null-dereference (or anything < address 4096): Object o; o.toHash; // Error: null dereference in function _Dmain Perhaps we could have a similar error for use of a default initialized floating-point variable?
Aug 27 2022
On 8/22/22 14:41, Steven Schveighoffer wrote:On 8/21/22 12:51 PM, Walter Bright wrote:For example, user has a callstack where called functions has these return values: float.init == 0 float.init == NaN 13 <== wrong result detected here ==> NaN 0 NaN 39 NaN 56 NaN 9 <== wrong initialization here ==> NaN 12 12 0 0 0 0 In which case you find the reason faster?Consider the following pattern, which doesn't appear frequently, but frequently enough: double x; if (condition) { x = 5; ... } ... // (1) if (condition) { foo(x); } Imagine there's a lot more code omitted which obscures the pattern. This code is correct. Now, maintainer adds `bar(x)` at (1). The scenarios: 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem.How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?No. NaN is not a number but zero is a number. zero may be both wrong and right value. NaN is never right result. To check if zero is right result you need manually calculate it. In case of NaN all you need is to take a look at it.2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed.Just like NaN.3. compiler complains that `double x;` needs an initializer. To shut up the compiler, the user initializes it to 0, without putting much thought into it. bar(0) may exhibit problems, but these won't necessarily be noticed. 4. compiler complains that `double x;` needs an initializer. Coder just schlepps in a 0. Yes, this happens. Maintainer wastes time wondering why x is initialized to 0, as that may be a nonsense value for x. Maintainer wonders if this unused initialization has a purpose, maybe it is the result of a bad refactoring? Wastes more time investigating it.Huh? Why are there 2 identical situations here? I'll also point out that not initializing an integer is sometimes intentionally done (because it's equivalent to initializing to 0). If I see someone didn't assign a value to an int, I don't question if it was an accident, I expect that they meant it. Also, you forgot: 5. Maintainer expected x to default to 0 (because that's what most types do), and expected bar to be called with 0 or 5. Now, since bar saved the result of it's calculation elsewhere, and then far away from this code, the result is used in some computation that finally makes its way to output in some fashion (and possibly not a specific printing of the value), now there's a puzzle to solve, and no way to know it can be traced back to x without hours/days of searching.D chose option 1.And there's probably no way that it changes. But in my mind the correct answer is to intialize to 0. -Steve
Aug 22 2022
On 8/22/22 9:33 AM, drug007 wrote:On 8/22/22 14:41, Steven Schveighoffer wrote:Callstack printouts don't look like that. Plus, what if you don't have the call stack available for inspection? And even if you do, that 9 might be just as obviously wrong as the NaN, negating any real benefit. One thing that everyone seems to be ignoring is that 99% of the time, when I find out I didn't initialize a float and it's NaN, it's because I didn't correctly initialize it to 0. So yes, when a lack of initialization somewhere in some code has happened *and is a mistake*, a NaN starting value can make things slightly easier, as long as you have everything instrumented, and can use a debugger. But *when* it happens is reduced to near zero if the default value is the expected 0.On 8/21/22 12:51 PM, Walter Bright wrote:For example, user has a callstack where called functions has these return values: float.init == 0 float.init == NaN 13 <== wrong result detected here ==> NaN 0 NaN 39 NaN 56 NaN 9 <== wrong initialization here ==> NaN 12 12 0 0 0 0 In which case you find the reason faster?Consider the following pattern, which doesn't appear frequently, but frequently enough: double x; if (condition) { x = 5; ... } ... // (1) if (condition) { foo(x); } Imagine there's a lot more code omitted which obscures the pattern. This code is correct. Now, maintainer adds `bar(x)` at (1). The scenarios: 1. x is default initialized to NaN. bar(x) produces a NaN result on everything dependent on x. User knows there's a problem.How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?As I've mentioned, you don't always see the NaN, just like you don't always see the 0. Imagine you are making a 3-d model, and one vertex out of 100k is NaN. How will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious. -SteveNo. NaN is not a number but zero is a number. zero may be both wrong and right value. NaN is never right result. To check if zero is right result you need manually calculate it. In case of NaN all you need is to take a look at it.2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed.Just like NaN.
Aug 22 2022
On 8/22/22 17:16, Steven Schveighoffer wrote:On 8/22/22 9:33 AM, drug007 wrote:Of course it is not a real call stackFor example, user has a callstack where called functions has these return values: float.init == 0 float.init == NaN 13 <== wrong result detected here ==> NaN 0 NaN 39 NaN 56 NaN 9 <== wrong initialization here ==> NaN 12 12 0 0 0 0 In which case you find the reason faster?Callstack printouts don't look like that. Plus, what if you don't havethe call stack available for inspection? And even if you do, that 9you can use printf debuggingmight be just as obviously wrong as the NaN, negating any real benefit.Yes, that's the point! 9 might be obviously. But NaN would be obviously.One thing that everyone seems to be ignoring is that 99% of the time, when I find out I didn't initialize a float and it's NaN, it's because I didn't correctly initialize it to 0.I don't agree. There are cases where default initialization is non-zero.So yes, when a lack of initialization somewhere in some code has happened *and is a mistake*, a NaN starting value can make things slightly easier, as long as you have everything instrumented, and can use a debugger. But *when* it happens is reduced to near zero if the default value is the expected 0.you are exaggregating a little. instrumentation is not required and printf debugging is always availableYes, in this specific case you right. But what if some of your valid vertices might be zero too?As I've mentioned, you don't always see the NaN, just like you don't always see the 0. Imagine you are making a 3-d model, and one vertex out of 100k is NaN. How will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious.No. NaN is not a number but zero is a number. zero may be both wrong and right value. NaN is never right result. To check if zero is right result you need manually calculate it. In case of NaN all you need is to take a look at it.2. x is default initialized to 0. bar(0) may exhibit problems, but these problems won't necessarily be noticed.Just like NaN.-Steve
Aug 22 2022
On 8/22/22 07:16, Steven Schveighoffer wrote:One thing that everyone seems to be ignoring is that 99% of the time, when I find out I didn't initialize a float and it's NaN, it's because I didn't correctly initialize it to 0.Although Walter has already said it on this thread, what is missing in this picture is, 63% of the time we would not even know we had bugs if D picked the default value to be 0.0.[1] I bet I can find bugs related to initialization in 12% of production C++ programs that use floating point variables. Ali [1] Yes, I made 63% up. [2] I made that up as well but I am more confident in that figure. :o)
Aug 23 2022
On Monday, 22 August 2022 at 14:16:14 UTC, Steven Schveighoffer wrote:Imagine you are making a 3-d model, and one vertex out of 100k is NaN. How will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious. -SteveIt could just as well be a very obvious hole, as easy to make out as that spike. Also that number may not end up being 0 so the spike may be very subtle. If I wouldn't notice, i.e. neither visibly nor due to a performance impact, I probably wouldn't even start looking. I've seen these spikes due to errors in hardware or operating it outside specifications (over clocking, under volting), too. But the artifact needn't necessarily be a triangle. Could be a color or transparency channel. A NaN value is incorrect - would you know the same if it's any real number ? Or would you have to ask the artist ? Would you even notice ? It may be off by just 0.35 in the blue channel - the eye is very insensitive to blue. It may not be obvious because of color blindness, or the monitor isn't calibrated to the color space, or any amount of different reasons. But someone else may notice and send a bug report and when you start investigating, a NaN will tell you the truth even if you can't visually see it yourself. In shapes it may be more obvious but anything in art goes and NaN is still always wrong. It's like a math professor asking their students to name the highest number they know and professor is going to provide a higher number. Next thing that happens is that someone calls "infinity" - infinity isn't a number. Maybe the situation could be improved in that the compiler adds checks for NaN akin to bounds checking and throws a NaN_Error. This way the error could be caught even before sending wrong data to the GPU - or whatever API.
Aug 23 2022
On 8/22/2022 7:16 AM, Steven Schveighoffer wrote:One thing that everyone seems to be ignoring is that 99% of the time, when I find out I didn't initialize a float and it's NaN, it's because I didn't correctly initialize it to 0.Then 1% of the time 0 is the wrong value and you never notice that the resulting calculation is off. Whereas with NaN you notice that when there's "NaN" in the printed result, it's not hiding.Imagine you are making a 3-d model, and one vertex out of 100k is NaN. Howwill you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious. C89 did not take NaNs into account for the floating point parts of the C standard library. But C99 did, and if the program tries to calculate: sin(NaN) the result will be NaN, guaranteed by the C99 Standard. If the graphics library cannot handle certain floating point values, such as NaN or Infinity, then that should be checked for as part of the call. At least in debug builds. It'll be a lot easier than looking for an out of place triangle. Most graphical displays seem to have an awful lot of tiny triangles. If I was writing code that, say, calculated a trajectory of a space craft, there is no way it would be acceptable to have default 0 initialization. Even if it's right 99% of the time. Because 1% of the time having a hull loss is not acceptable. P.S. graphics software generally doesn't care about making mistakes. I've seen plenty of buggy graphics in video games, and it doesn't matter because it doesn't affect game play. But people doing science, engineering, accounting, flight controls, etc., care very much about getting 100% correct results. 1% going awry is not acceptable.
Aug 23 2022
On Wednesday, 24 August 2022 at 05:54:59 UTC, Walter Bright wrote:On 8/22/2022 7:16 AM, Steven Schveighoffer wrote:That's the best answer possible, i used to be annoyed by float not being 0 by default, but as i learn more and read different takes on it, it makes sense, and i don't mind anymore The main issue is to get used to it, it takes time if you use other languages that defaults to 0One thing that everyone seems to be ignoring is that 99% of the time, when I find out I didn't initialize a float and it's NaN, it's because I didn't correctly initialize it to 0.Then 1% of the time 0 is the wrong value and you never notice that the resulting calculation is off. Whereas with NaN you notice that when there's "NaN" in the printed result, it's not hiding.Imagine you are making a 3-d model, and one vertex out of100k is NaN. How will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious. C89 did not take NaNs into account for the floating point parts of the C standard library. But C99 did, and if the program tries to calculate: sin(NaN) the result will be NaN, guaranteed by the C99 Standard. If the graphics library cannot handle certain floating point values, such as NaN or Infinity, then that should be checked for as part of the call. At least in debug builds. It'll be a lot easier than looking for an out of place triangle. Most graphical displays seem to have an awful lot of tiny triangles. If I was writing code that, say, calculated a trajectory of a space craft, there is no way it would be acceptable to have default 0 initialization. Even if it's right 99% of the time. Because 1% of the time having a hull loss is not acceptable. P.S. graphics software generally doesn't care about making mistakes. I've seen plenty of buggy graphics in video games, and it doesn't matter because it doesn't affect game play. But people doing science, engineering, accounting, flight controls, etc., care very much about getting 100% correct results. 1% going awry is not acceptable.
Aug 24 2022
On Wednesday, 24 August 2022 at 18:11:57 UTC, ryuukk_ wrote:On Wednesday, 24 August 2022 at 05:54:59 UTC, Walter Bright wrote:I want to point out that, just like with the GC, it is not the panacea, if you have a NaN in your result, good luck finding what is the root of the issue/bug in your program, or library.. it is during moments like that that i still prefer it being 0 by default, so everyone is on the same pageOn 8/22/2022 7:16 AM, Steven Schveighoffer wrote:That's the best answer possible, i used to be annoyed by float not being 0 by default, but as i learn more and read different takes on it, it makes sense, and i don't mind anymore The main issue is to get used to it, it takes time if you use other languages that defaults to 0One thing that everyone seems to be ignoring is that 99% of the time, when I find out I didn't initialize a float and it's NaN, it's because I didn't correctly initialize it to 0.Then 1% of the time 0 is the wrong value and you never notice that the resulting calculation is off. Whereas with NaN you notice that when there's "NaN" in the printed result, it's not hiding.Imagine you are making a 3-d model, and one vertex out of100k is NaN. How will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious. C89 did not take NaNs into account for the floating point parts of the C standard library. But C99 did, and if the program tries to calculate: sin(NaN) the result will be NaN, guaranteed by the C99 Standard. If the graphics library cannot handle certain floating point values, such as NaN or Infinity, then that should be checked for as part of the call. At least in debug builds. It'll be a lot easier than looking for an out of place triangle. Most graphical displays seem to have an awful lot of tiny triangles. If I was writing code that, say, calculated a trajectory of a space craft, there is no way it would be acceptable to have default 0 initialization. Even if it's right 99% of the time. Because 1% of the time having a hull loss is not acceptable. P.S. graphics software generally doesn't care about making mistakes. I've seen plenty of buggy graphics in video games, and it doesn't matter because it doesn't affect game play. But people doing science, engineering, accounting, flight controls, etc., care very much about getting 100% correct results. 1% going awry is not acceptable.
Aug 24 2022
On Wednesday, 24 August 2022 at 18:15:53 UTC, ryuukk_ wrote:I want to point out that, just like with the GC, it is not the panacea, if you have a NaN in your result, good luck finding what is the root of the issue/bug in your program, or library.. it is during moments like that that i still prefer it being 0 by default, so everyone is on the same pageOne could say, "well that's a bug anyways, and now you know you got a bug in your program", and that's why NaN wins over 0, it's annoying, but it is useful (sorry for 3 successive reply)
Aug 24 2022
On Wednesday, 24 August 2022 at 18:15:53 UTC, ryuukk_ wrote:I want to point out that, just like with the GC, it is not the panacea, if you have a NaN in your result, good luck finding what is the root of the issue/bug in your program, or library.. it is during moments like that that i still prefer it being 0 by default, so everyone is on the same pageIn gdb you can use `select-frame` and inspect the value of locals of the **whole** call stack. Also just `bt` can help as that shows the call args values.
Aug 24 2022
On 8/24/22 4:07 PM, user1234 wrote:On Wednesday, 24 August 2022 at 18:15:53 UTC, ryuukk_ wrote:The source may not be in the call stack. -SteveI want to point out that, just like with the GC, it is not the panacea, if you have a NaN in your result, good luck finding what is the root of the issue/bug in your program, or library.. it is during moments like that that i still prefer it being 0 by default, so everyone is on the same pageIn gdb you can use `select-frame` and inspect the value of locals of the **whole** call stack. Also just `bt` can help as that shows the call args values.
Aug 24 2022
On 8/24/2022 11:15 AM, ryuukk_ wrote:I want to point out that, just like with the GC, it is not the panacea, if you have a NaN in your result, good luck finding what is the root of the issue/bug in your program, or library.. it is during moments like that that i still prefer it being 0 by default, so everyone is on the same pageI can't think of a case where a 0 is easier to track back to its origin.
Aug 24 2022
On 8/24/2022 11:11 AM, ryuukk_ wrote:That's the best answer possible, i used to be annoyed by float not being 0 by default, but as i learn more and read different takes on it, it makes sense, and i don't mind anymore The main issue is to get used to it, it takes time if you use other languages that defaults to 0It's one reason why D is simply better than those other languages. (Not many language designers have experience doing commercial floating point work, and it shows. I was an early member of NCEG (Numerical C Extensions Group) which worked hard to add proper floating point support to the C Standard, including exacting support for NaN. I implemented it in Zortech C/C++ years before anyone else did.)
Aug 24 2022
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:As someone coming from Java to use D, I find it myself quite annoying that float and double are initialized to `nan`.Honestly have no opinion on float.init being NaN, I don't think I would care either way.
Aug 21 2022
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:[...]What’s great is that structs defined in C imported in D and structs defined in D imported in D will have completely different initial values despite being syntactically identical! ```D // foo_c.c struct Foo { float x; }; // foo_d.d struct Foo { float x; }; // main.d import foo_d; import foo_c; import std.stdio: writeln; void main(){ foo_d.Foo f_d; foo_c.Foo f_c; writeln(f_d); // Foo(nan) writeln(f_c); // Foo(0) } ```
Aug 23 2022
On 8/23/22 13:44, Dave P. wrote:On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:[...]will have completely different initial valuesAlthough C does not initialize variables, sometimes both C and D floats can have the same exact bit pattern.despite being syntactically identical!C and D are different languages.writeln(f_d); // Foo(nan)That will always be the case.writeln(f_c); // Foo(0)And yes, 0 happens to be a valid garbage value. Ali
Aug 23 2022
On 8/23/22 5:24 PM, Ali Çehreli wrote:Although C does not initialize variables, sometimes both C and D floats can have the same exact bit pattern.I'm wondering if D does not zero-initialize structs that are from importC? -Steve
Aug 23 2022
On Tuesday, 23 August 2022 at 21:24:10 UTC, Ali Çehreli wrote:On 8/23/22 13:44, Dave P. wrote:This is a struct defined in C being used in D via ImportC.On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:[...]will have completely different initial valuesAlthough C does not initialize variables, sometimes both C and D floats can have the same exact bit pattern.despite being syntactically identical!C and D are different languages.The default value for a struct imported via importC is all bits 0. This is not a “garbage value”.writeln(f_d); // Foo(nan)That will always be the case.writeln(f_c); // Foo(0)And yes, 0 happens to be a valid garbage value.
Aug 23 2022
On 8/23/22 14:40, Dave P. wrote:Steve said the same thing but I don't see it on the ImportC page (yet?): https://dlang.org/spec/importc.html I wonder why D would do that.And yes, 0 happens to be a valid garbage value.The default value for a struct imported via importC is all bits 0.This is not a “garbage value”.D could set all bits to any other value and it would still be fine because either C's initialization function would be called on the object (some programmers call memset), or the programmer did not care. Ali
Aug 23 2022
On Tuesday, 23 August 2022 at 21:53:35 UTC, Ali Çehreli wrote:On 8/23/22 14:40, Dave P. wrote:Global and static variables in C are initialized to all-zero bits, regardless of type. Here's the relevant paragraph from the C11 standard:bits 0. Steve said the same thing but I don't see it on the ImportC page (yet?): https://dlang.org/spec/importc.html I wonder why D would do that.And yes, 0 happens to be a valid garbage value.The default value for a struct imported via importC is allIf an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static or thread storage duration is not initialized explicitly, then: if it has pointer type, it is initialized to a null pointer; if it has arithmetic type, it is initialized to (positive or unsigned) zero; if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits; if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;Presumably this behavior was implemented in an attempt to conform to this part of the C standard.
Aug 23 2022
On 8/23/2022 4:35 PM, Paul Backus wrote:Presumably this behavior was implemented in an attempt to conform to this part of the C standard.Yes. It's not a bug.
Aug 23 2022
On 8/23/2022 1:44 PM, Dave P. wrote:What’s great is that structs defined in C imported in D and structs defined in D imported in D will have completely different initial values despite being syntactically identical!Let's have some fun with the following C program: ----------- #include <stdio.h> struct Foo { float x; }; int main() { struct Foo f; printf("%g\n", f.x); } gcc test.c ./a.out 2.12133e-15 ------------- Oh well!
Aug 23 2022
On 8/23/22 6:33 PM, Walter Bright wrote:On 8/23/2022 1:44 PM, Dave P. wrote:Since you are looking at it, the original code is *not* a C function, it's a D function using a struct defined using C (imported via ImportC). What happens in that case? On one hand, it's a C struct. But on the other hand, it's a D function. Who's rules are used? -SteveWhat’s great is that structs defined in C imported in D and structs defined in D imported in D will have completely different initial values despite being syntactically identical!Let's have some fun with the following C program: ----------- #include <stdio.h> struct Foo { float x; }; int main() { struct Foo f; printf("%g\n", f.x); } gcc test.c ./a.out 2.12133e-15 ------------- Oh well!
Aug 23 2022
On 8/23/2022 5:00 PM, Steven Schveighoffer wrote:On one hand, it's a C struct. But on the other hand, it's a D function. Who's rules are used?The C rules. This is because D is importing C code, so it better behave like C code. C code does initialize floats and doubles to 0.0 if they are placed in static data. It is not reasonable that D would leave imported C structures uninitialized when C does, and so initializing them to 0.0 is a reasonable choice.
Aug 23 2022
On 8/24/22 1:14 AM, Walter Bright wrote:On 8/23/2022 5:00 PM, Steven Schveighoffer wrote:So to paraphrase this, D does initialize local C structure values, but initializes doubles/floats to 0 to be consistent with C static initialization. In other words, it *doesn't* use the C rules of not initializing locals that have no explicit initialization. But it *does* use the C rules of what value to initialize with. I actually proved this too with a test, so that's good news! Maybe I just need to define all my structs using C :P -SteveOn one hand, it's a C struct. But on the other hand, it's a D function. Who's rules are used?The C rules. This is because D is importing C code, so it better behave like C code. C code does initialize floats and doubles to 0.0 if they are placed in static data. It is not reasonable that D would leave imported C structures uninitialized when C does, and so initializing them to 0.0 is a reasonable choice.
Aug 24 2022
On 8/24/2022 7:03 AM, Steven Schveighoffer wrote:I actually proved this too with a test, so that's good news! Maybe I just need to define all my structs using C :PYou could, but NaN default initialization is better. I inferred that you relied on detecting a wrong 0 initialization by looking for unexpected behavior. This is less reliable than looking for a NaN in the output. When the behavior of a mistake being most of the time it will work out ok, is not acceptable because there's that case where it won't be ok and could be very costly. It should not be "the output looks sort of right, so assume it is right." It should *be* right, or be *obviously* wrong. People should have to explicitly work at getting it wrong. These are more of those lessons I picked up from working on flight controls at Boeing. For example, hydraulic actuators (rams) drive the flight control surfaces back and forth. The actuators have a hydraulic fluid input port, and an output port. If the hydraulic lines are hooked to the wrong ports, the airplane will be uncontrollable and will crash. This has happened many times in the past. Boeing's solution is to: 1. the ports are different sizes 2. one is a left-hand thread, the other is a right-hand thread 3. the lines and ports are color-coded 4. the lines are laid out so the hydraulic lines are not long enough to connect to the wrong port 5. inspectors have to sign off on it 6. the flight controls are tested for correct operation as part of the pre-flight checklist This has stopped the problem. Note how hard a mechanic would have to work to get it wrong, and if he succeeded it would be *obviously* wrong to the inspector. I try to infuse this philosophy into D's design where ever it fits.
Aug 24 2022
On Thursday, 25 August 2022 at 01:19:55 UTC, Walter Bright wrote:If the hydraulic lines are hooked to the wrong ports, the airplane will be uncontrollable and will crash.oh ye of little faith! I read about a story where this happened. The pilots quickly found the plane uncontrollable to the point where they asked for vectors to ditch into the ocean so the crash wouldn't hurt anybody on the ground at least... but they couldn't even control it well enough to successfully navigate out there. They kept flying in random directions and ended up over ground again, but had enough altitude to keep trying again. After quite some time though, they actually recognized the "random, uncontrollable" aircraft actually was responding to their inputs in a predictable pattern, it was just all messed up. As they figured it out and learned how to fly with these bizarro controls, their initial panic subsided and they were able to successfully return to the airport for a safe landing! (of course there are other similar stories without the happy ending so your point is good, but i like this story)
Aug 24 2022
On 8/24/2022 6:30 PM, Adam D Ruppe wrote:On Thursday, 25 August 2022 at 01:19:55 UTC, Walter Bright wrote:The cases I've heard all resulted in a smoking hole in the ground just past the end of the runway. When the airplane does the wrong thing as the result of a control input, the natural pilot reflex is to push it harder, not try the other way. When you're a few feet off the ground, that means smacking it hard into the ground. Your anecdote was surely not the elevators or ailerons. It might have been the rudder, where the pilots would have more of a chance.If the hydraulic lines are hooked to the wrong ports, the airplane will be uncontrollable and will crash.oh ye of little faith! I read about a story where this happened. The pilots quickly found the plane uncontrollable to the point where they asked for vectors to ditch into the ocean so the crash wouldn't hurt anybody on the ground at least... but they couldn't even control it well enough to successfully navigate out there. They kept flying in random directions and ended up over ground again, but had enough altitude to keep trying again. After quite some time though, they actually recognized the "random, uncontrollable" aircraft actually was responding to their inputs in a predictable pattern, it was just all messed up. As they figured it out and learned how to fly with these bizarro controls, their initial panic subsided and they were able to successfully return to the airport for a safe landing! (of course there are other similar stories without the happy ending so your point is good, but i like this story)
Aug 25 2022
On Thursday, 25 August 2022 at 16:36:41 UTC, Walter Bright wrote:Your anecdote was surely not the elevators or ailerons. It might have been the rudder, where the pilots would have more of a chance.I found the story again, here's the wikipedia article on it that has its references too: https://en.wikipedia.org/wiki/Air_Astana_Flight_1388 "The investigation revealed that the aileron cables were installed incorrectly." Only a few years ago too, in 2018! There's youtube videos too talking about it too: https://www.youtube.com/watch?v=5ywaMkMTwWk (this guy generally goes over the incident report with some nice animations to explain it too) https://www.youtube.com/watch?v=kIc8Rr-cKd8 (atc recording part 1) https://www.youtube.com/watch?v=evYLkhxoP3U (part 2) i know im pretty far off topic but i just enjoy these aviation things.
Aug 25 2022
Thanks for the reference. I'm always interested in these kinds of things. I'm surprised blame wasn't also placed on the design for making it possible to reverse the controls. I'm amazed they managed to land it successfully. Those pilots ought to get a medal for flying skill, along with the brickbats for failing to preflight the airplane properly. Probably the only reason they didn't crash it was the spoilers were set up correctly, and countered some of the aileron bad movement. On 8/25/2022 10:32 AM, Adam D Ruppe wrote:I found the story again, here's the wikipedia article on it that has its references too: https://en.wikipedia.org/wiki/Air_Astana_Flight_1388 "The investigation revealed that the aileron cables were installed incorrectly." Only a few years ago too, in 2018! There's youtube videos too talking about it too: https://www.youtube.com/watch?v=5ywaMkMTwWk (this guy generally goes over the incident report with some nice animations to explain it too) https://www.youtube.com/watch?v=kIc8Rr-cKd8 (atc recording part 1) https://www.youtube.com/watch?v=evYLkhxoP3U (part 2) i know im pretty far off topic but i just enjoy these aviation things.
Aug 25 2022
On Thursday, 25 August 2022 at 01:19:55 UTC, Walter Bright wrote:Boeing.Now Boeing is a fighter among missiles.
Aug 24 2022
On 8/24/22 9:19 PM, Walter Bright wrote:On 8/24/2022 7:03 AM, Steven Schveighoffer wrote:No, you are completely misunderstanding what I'm saying. What I was saying is that NaN is not that much different from 0 when the outputs you have aren't "val = NaN". I.e. most of the time. Once you have determined there is a problem, I don't really think NaN helps much finding the source -- the source can be long gone by the time you attach a debugger. The correct mechanism is to look at what possible places the value could be written, and trace it back to the incorrect value. But what I *am* saying is that I frequently omit initialization of numbers I expect to start at 0. I forget that double is NaN by default, and then I have to find and fix that. The only thing NaN has ever done for me is found places where I forgot to initialize to 0.I actually proved this too with a test, so that's good news! Maybe I just need to define all my structs using C :PYou could, but NaN default initialization is better. I inferred that you relied on detecting a wrong 0 initialization by looking for unexpected behavior. This is less reliable than looking for a NaN in the output. When the behavior of a mistake being most of the time it will work out ok, is not acceptable because there's that case where it won't be ok and could be very costly.It should not be "the output looks sort of right, so assume it is right." It should *be* right, or be *obviously* wrong. People should have to explicitly work at getting it wrong. These are more of those lessons I picked up from working on flight controls at Boeing.NaN fails at that. It's silently swallowed by just about everything. Only when a human looks at some printout does it become obvious. A better option would be to throw an exception if NaN is used in an operation.For example, hydraulic actuators (rams) drive the flight control surfaces back and forth. The actuators have a hydraulic fluid input port, and an output port. If the hydraulic lines are hooked to the wrong ports, the airplane will be uncontrollable and will crash. This has happened many times in the past. Boeing's solution is to: 1. the ports are different sizes 2. one is a left-hand thread, the other is a right-hand thread 3. the lines and ports are color-coded 4. the lines are laid out so the hydraulic lines are not long enough to connect to the wrong port 5. inspectors have to sign off on it 6. the flight controls are tested for correct operation as part of the pre-flight checklist This has stopped the problem. Note how hard a mechanic would have to work to get it wrong, and if he succeeded it would be *obviously* wrong to the inspector. I try to infuse this philosophy into D's design where ever it fits.I understand, but NaN is woefully inadequate for the task. NaN is more like if you hooked up the ports wrong, a dye is added to the fluid, which isn't visible through the tubes. You have to extract and examine the fluid to realize something is wrong. Then you have to find the source of the dye (and it could come from anywhere in the system). -Steve
Aug 24 2022
On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:A better option would be to throw an exception if NaN is used in an operation. -SteveIMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.) This will solve all problems because: - You will never have a NaN value propagate throughout your program, making it much easier to track it back to its roots. - NaN strictly tells you that some value is wrong before it's even being used - There's no way to workaround it effectively, meaning you must actually fix any places where NaN is possible.
Aug 25 2022
On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:I'm shocked by this idea. What if I want high performance nothrow FP code ?A better option would be to throw an exception if NaN is used in an operation. -SteveIMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.)
Aug 25 2022
On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:It could be optimized away in release code and/or be optional to disable (should be enabled by default.)On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:I'm shocked by this idea. What if I want high performance nothrow FP code ?A better option would be to throw an exception if NaN is used in an operation. -SteveIMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.)
Aug 25 2022
On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:Turn the check off. The hardware basically already supports doing this (NaNs don't have to be quiet) but almost no one uses it - it's quite hard to trigger at all on a modern system.On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:I'm shocked by this idea. What if I want high performance nothrow FP code ?A better option would be to throw an exception if NaN is used in an operation. -SteveIMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.)
Aug 25 2022
On Thursday, 25 August 2022 at 11:38:22 UTC, max haughton wrote:On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:Looks like D allows you to enable floating-point exceptions using the [`std.math.hardware.FloatingPointControl`][1] interface. Of course, these are hardware exceptions, so you will get SIGFPE rather than a thrown Error with a backtrace. To turn them into D Errors you'd need to set up a signal handler, like how `etc.linux.memoryerror` does it (or whatever the equivalent is on Windows). [1]: https://phobos.dpldocs.info/std.math.hardware.FloatingPointControl.htmlOn Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:Turn the check off. The hardware basically already supports doing this (NaNs don't have to be quiet) but almost no one uses it - it's quite hard to trigger at all on a modern system.On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:I'm shocked by this idea. What if I want high performance nothrow FP code ?A better option would be to throw an exception if NaN is used in an operation. -SteveIMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.)
Aug 25 2022
On Thursday, 25 August 2022 at 14:34:52 UTC, Paul Backus wrote:Looks like D allows you to enable floating-point exceptions using the [`std.math.hardware.FloatingPointControl`][1] interface. Of course, these are hardware exceptions, so you will get SIGFPE rather than a thrown Error with a backtrace. To turn them into D Errors you'd need to set up a signal handler, like how `etc.linux.memoryerror` does it (or whatever the equivalent is on Windows). [1]: https://phobos.dpldocs.info/std.math.hardware.FloatingPointControl.htmlUnfortunately, it looks like this will not work in practice, because the "invalid" floating-point exception is raised only when a NaN is *created*, not when it's *propagated*. Since the initial NaN values of default-initialized `float`/`double` variables are created at compile time, not runtime, no exception is ever raised for them. Example program: ```d import std.math.hardware; float div(float x, float y) { return x / y; } void main() { FloatingPointControl fpctrl; fpctrl.enableExceptions(FloatingPointControl.severeExceptions); float f = float.nan; // ok - no exception float g = div(0.0f, 0.0f); // crashes with SIGFPE } ```
Aug 25 2022
On Thursday, 25 August 2022 at 16:06:43 UTC, Paul Backus wrote:Unfortunately, it looks like this will not work in practice, because the "invalid" floating-point exception is raised only when a NaN is *created*, not when it's *propagated*. Since the initial NaN values of default-initialized `float`/`double` variables are created at compile time, not runtime, no exception is ever raised for them.Which is strange because HW wise it is trivial to check if the result is NaN. To check that NaN is not based on input is of course more complicated. Then again an x86 complicated in an unhealthy way. This kind of makes another motivation to let floats default to zero, if this is correct.
Aug 25 2022
On 8/25/2022 9:16 AM, IGotD- wrote:Which is strange because HW wise it is trivial to check if the result is NaN. To check that NaN is not based on input is of course more complicated. Then again an x86 complicated in an unhealthy way. This kind of makes another motivation to let floats default to zero, if this is correct.There's nothing to be afraid of in getting a NaN in the output. One should be glad, because then one *knows* there's a bug. This thread reminds me of the threads about assert, and the contention that the program should continue after a failed assert. 1. It is not better to pretend a program is working when it is not. 2. It is not better for a language to guess at what the programmer must have meant, even if the guess is correct 99% of the time. 3. It is not better to never check the output of the program for correctness. D is a tool for helping the programmer create correct, robust, and bug-free programs.
Aug 25 2022
On 25.08.22 18:56, Walter Bright wrote:On 8/25/2022 9:16 AM, IGotD- wrote:Clearly you should throw away your computer after a failed assert.Which is strange because HW wise it is trivial to check if the result is NaN. To check that NaN is not based on input is of course more complicated. Then again an x86 complicated in an unhealthy way. This kind of makes another motivation to let floats default to zero, if this is correct.There's nothing to be afraid of in getting a NaN in the output. One should be glad, because then one *knows* there's a bug. This thread reminds me of the threads about assert, and the contention that the program should continue after a failed assert. ...1. It is not better to pretend a program is working when it is not. 2. It is not better for a language to guess at what the programmer must have meant, even if the guess is correct 99% of the time. 3. It is not better to never check the output of the program for correctness. D is a tool for helping the programmer create correct, robust, and bug-free programs.Which is why asserts can introduce new _undefined behavior_?
Aug 29 2022
On 8/29/2022 5:27 PM, Timon Gehr wrote:Clearly you should throw away your computer after a failed assert.Absolutely. My basement is full of junked computers that dared to fail.Which is why asserts can introduce new _undefined behavior_?DMD has a switch to insert a halt instruction upon assertion failures.
Aug 30 2022
On 30.08.22 17:47, Walter Bright wrote:On 8/29/2022 5:27 PM, Timon Gehr wrote:Let's assume whoever is compiling my code does not want to spend computational resources on checking my asserts. (Or invariants, etc.) My problem is that DMD seems to _lack_ switches to _safely_ disable checking (as far as I understand; it's notoriously underdocumented). The fact that something that's called "turn off checking" will introduce UB is just really bad UX design. You are nothing short of ensuring that the hydraulic lines are hooked to the wrong ports. Aside: My experience with people running into "Illegal instruction" is that they just assume the compiler has a bug and produced invalid machine code. Also, the semantics of "hlt" is not to terminate anything at all, it just waits for the next interrupt to be fired. The only reason it crashes in user space is that it requires ring 0 access.Clearly you should throw away your computer after a failed assert.Absolutely. My basement is full of junked computers that dared to fail.Which is why asserts can introduce new _undefined behavior_?DMD has a switch to insert a halt instruction upon assertion failures.
Aug 30 2022
On Wednesday, 31 August 2022 at 02:05:21 UTC, Timon Gehr wrote:Also, the semantics of "hlt" is not to terminate anything at allIt actually uses UD2 now (I've been complaining about this for years and it actually got changed in Dec 2017, so long time ago, but Walter's old habits die hard) https://github.com/dlang/dmd/pull/7391
Aug 30 2022
On Wed, Aug 31, 2022 at 04:05:21AM +0200, Timon Gehr via Digitalmars-d wrote: [...]Also, the semantics of "hlt" is not to terminate anything at all, it just waits for the next interrupt to be fired. The only reason it crashes in user space is that it requires ring 0 access.Hmm. I was pretty sure the convention, at least on x86 architectures, is that hlt in userspace is a signal to the OS that the program has terminated itself (usually abnormally, since normal termination is usually via the exit syscall, at least on Posix). T -- It won't be covered in the book. The source code has to be useful for something, after all. -- Larry Wall
Aug 30 2022
On Thursday, 25 August 2022 at 11:38:22 UTC, max haughton wrote:On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:We agree there, we talk about a check that does not even exist but that has to be disabled.On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:Turn the check off. The hardware basically already supports doing this (NaNs don't have to be quiet) but almost no one uses it - it's quite hard to trigger at all on a modern system.[...]I'm shocked by this idea. What if I want high performance nothrow FP code ?
Aug 25 2022
On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:by default, and then I have to find and fix that. The only thing NaN has ever done for me is found places where I forgot to initialize to 0.One big advantage of having everything default to 0 would be if the compiler was clever and used pre-cleared memory for arrays. That way you don't have to do any constructor work.
Aug 25 2022
On 8/24/2022 8:08 PM, Steven Schveighoffer wrote:NaN fails at that. It's silently swallowed by just about everything. Only when a human looks at some printout does it become obvious.Seriously, *when* is 0 better than that? If you aren't looking at your output, then why are you calculating the value?
Aug 25 2022
On Thursday, 25 August 2022 at 16:39:14 UTC, Walter Bright wrote:[...] If you aren't looking at your output, then why are you calculating the value?To make decisions? double compute_pop () { double pop; // forgot to implement the computation // or ran into a nan by an instable computation pop = sqrt (-1.); pop += 0.; return pop; } int main () { auto pop = compute_pop (); if (pop < .5) writeln ("It will not rain."); else writeln ("It will rain."); return 0; }
Aug 25 2022
On 8/25/22 12:39 PM, Walter Bright wrote:On 8/24/2022 8:08 PM, Steven Schveighoffer wrote:Very few programs have a purpose to print an actual floating point number as text. Instead they are used for other things. Another example, let's say you are using a FP calculation to determine some sort of timing for bandwidth limiting. You might have something like: ```d if(val > maxBW) delaySending(); ``` If `val` or `maxBW` are NaN, this will always be a false condition (because of the wonderful property that comparisons with NaN are always false), so that code effectively never executes. Note that there's no `printf` here, and the code happily compiles and runs, it just does something unexepected. 0 is no better here *but also no worse*. -SteveNaN fails at that. It's silently swallowed by just about everything. Only when a human looks at some printout does it become obvious.Seriously, *when* is 0 better than that? If you aren't looking at your output, then why are you calculating the value?
Aug 25 2022
On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:0 is no better here *but also no worse*.0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better. BTW, hex data doesn't have a NaN value. But a popular thing we'd do is initialize it to: 0xDEADBEEF which is pretty unlikely to occur in the wild. So when dumping hex data, and DEADBEEF is in there, you're very likely looking at uninitialized data getting into the output. I'd use it for both initializing malloc'd data before returning it to the caller, and setting free'd data to it. It was pretty effective at flushing out uninitialized allocated data, and use-after-free bugs. Using 0x00 was nowhere near as effective.
Aug 25 2022
On 8/25/22 9:01 PM, Walter Bright wrote:On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:I fully don't ever expect any changes to come from this discussion. But just to continue the point here, yes, it's slightly better in *some cases*. The question to answer is *how many cases*, and is the pain caused by having to go correct problems that should never have existed in the first place worth fixing those few cases where it actually helps. It's a matter of tradeoffs. There is no clear winner or loser, both have benefits and both have drawbacks. I've never encountered the benefits of NaN, so I'm biased towards initializing with 0.0 is no better here *but also no worse*.0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better.BTW, hex data doesn't have a NaN value. But a popular thing we'd do is initialize it to: 0xDEADBEEF which is pretty unlikely to occur in the wild. So when dumping hex data, and DEADBEEF is in there, you're very likely looking at uninitialized data getting into the output.That's great. Now how do you find out where the problem starts? What if DEADBEEF is in your dump, but it's just memory that isn't being used yet? Is it still a problem? Note that this solves a mostly different problem -- using dangling pointers. This isn't about initialization. -Steve
Aug 26 2022
On 8/26/2022 9:28 AM, Steven Schveighoffer wrote:I fully don't ever expect any changes to come from this discussion.True. I don't believe I've ever managed to change your mind!That's great. Now how do you find out where the problem starts?The most important part is discovering that I *have* a problem. Next, I grep for DEADBEEF in the source code. And go from there. I am not making this up for the n.g. I have a *lot* of experience with it. I'm pointing out techniques that work. DEADBEEF turns a heisenbug into a reproducible bug. If it is reproducible, it is findable and fixable.What if DEADBEEF is in your dump, but it's just memory that isn't being used yet? Is it still a problem?That depends on how you were using it.Note that this solves a mostly different problem -- using dangling pointers. This isn't about initialization.It is. The first use case I mentioned was initializing data returned from malloc to DEADBEEF. malloc returns uninitialized data, and I wanted to make sure it wasn't data that just happened to be 0 and "work", because therein lies heisenbugs and madness.
Aug 26 2022
On 8/26/22 11:30, Walter Bright wrote:It is. The first use case I mentioned was initializing data returned from malloc to DEADBEEF. malloc returns uninitialized data, and I wanted to make sure it wasn't data that just happened to be 0 and "work", because therein lies heisenbugs and madness.Microsoft's C++ compiler used to do and probably still does that. Newly allocated memory and freed memory are initialized with specific patterns. (Optionally, I think with a compiler switch.) Ali
Aug 26 2022
On Friday, 26 August 2022 at 18:53:33 UTC, Ali Çehreli wrote:Microsoft's C++ compiler used to do and probably still does that. Newly allocated memory and freed memory are initialized with specific patterns. (Optionally, I think with a compiler switch.) AliI don't think it would do that in release mode. However, in debug there are several things going on with the VC C++ compiler. I haven't checked if it patterns malloc/free memory but it certainly patterns the stack memory and puts variables apart with guard patterns in between. Upon function/frame exit it checks all this. This is dog slow but very useful and I have found many bugs thanks to this. This of course will be unacceptable in a release build. Also initialize malloc/free with pattern would be undesirable in a release build.
Aug 26 2022
On Friday, 26 August 2022 at 20:37:40 UTC, IGotD- wrote:On Friday, 26 August 2022 at 18:53:33 UTC, Ali Çehreli wrote:Except Windows is actually compiled in release mode with local variables being initialized. https://msrc-blog.microsoft.com/2020/05/13/solving-uninitialized-stack-memory-on-windows/ And Android as well, https://source.android.com/docs/security/memory-safety/zero-initialized-memory?hl=enMicrosoft's C++ compiler used to do and probably still does that. Newly allocated memory and freed memory are initialized with specific patterns. (Optionally, I think with a compiler switch.) AliI don't think it would do that in release mode. However, in debug there are several things going on with the VC C++ compiler. I haven't checked if it patterns malloc/free memory but it certainly patterns the stack memory and puts variables apart with guard patterns in between. Upon function/frame exit it checks all this. This is dog slow but very useful and I have found many bugs thanks to this. This of course will be unacceptable in a release build. Also initialize malloc/free with pattern would be undesirable in a release build.
Aug 27 2022
On 26.08.22 20:30, Walter Bright wrote:I am not making this up for the n.g. I have a *lot* of experience with it. I'm pointing out techniques that work. DEADBEEF turns a heisenbug into a reproducible bug. If it is reproducible, it is findable and fixable.D's assert semantics may turn a reproducible bug into a heisenbug.
Aug 29 2022
On Tuesday, 30 August 2022 at 00:29:14 UTC, Timon Gehr wrote:On 26.08.22 20:30, Walter Bright wrote:Uh, can you please elaborate on what you mean by this? How do `assert`s convert reproducible bugs into heisenbugs? I've never seen anyone say anything like this 😕I am not making this up for the n.g. I have a *lot* of experience with it. I'm pointing out techniques that work. DEADBEEF turns a heisenbug into a reproducible bug. If it is reproducible, it is findable and fixable.D's assert semantics may turn a reproducible bug into a heisenbug.
Aug 30 2022
On Tuesday, 30 August 2022 at 11:48:26 UTC, Tejas wrote:How do `assert`s convert reproducible bugs into heisenbugs?I pity the fool who uses -release.
Aug 30 2022
On Tuesday, 30 August 2022 at 11:55:29 UTC, Adam D Ruppe wrote:On Tuesday, 30 August 2022 at 11:48:26 UTC, Tejas wrote:Is this true for asserts w/o side effects?How do `assert`s convert reproducible bugs into heisenbugs?I pity the fool who uses -release.
Aug 30 2022
On Tuesday, 30 August 2022 at 12:07:52 UTC, wjoe wrote:Is this true for asserts w/o side effects?Yes. -release should seriously *never* be used for a lot of reasons, but read this part of the spec: https://dlang.org/spec/expression.html#assert_expressions1. The first AssignExpression must evaluate to true. If it does not, an Assert Failure has occurred and the program enters an Invalid State.Notice that it doesn't say "must evaluate to true if actually evaluated", it just says must evaluate to true. If it would have failed, even if not actually compiled in, the program has *still* entered the Invalid State.8. Undefined Behavior: Once in an Invalid State the behavior of the continuing execution of the program is undefined.Implementation Defined: Whether the first AssertExpression is evaluated or not at runtime is typically set with a compiler switch.This combines to mean an optimizer is free to assume the asserts were all true as it moves forward which can get pretty random if it was never actually tested. I'm not sure if this is what Timon had in mind but it is its own thing to watch out for.
Aug 30 2022
On Tuesday, 30 August 2022 at 12:17:36 UTC, Adam D Ruppe wrote:On Tuesday, 30 August 2022 at 12:07:52 UTC, wjoe wrote:That would make for a nice note in the spec :) Thanks for pointing this out.[...]Yes. -release should seriously *never* be used for a lot of reasons, but read this part of the spec: https://dlang.org/spec/expression.html#assert_expressions[...]Notice that it doesn't say "must evaluate to true if actually evaluated", it just says must evaluate to true. If it would have failed, even if not actually compiled in, the program has *still* entered the Invalid State.[...][...]This combines to mean an optimizer is free to assume the asserts were all true as it moves forward which can get pretty random if it was never actually tested. I'm not sure if this is what Timon had in mind but it is its own thing to watch out for.
Aug 30 2022
On Tuesday, 30 August 2022 at 11:55:29 UTC, Adam D Ruppe wrote:On Tuesday, 30 August 2022 at 11:48:26 UTC, Tejas wrote:Arguably the only thing -release should ever have done is removing debug statements. Nothing more, nothing less.How do `assert`s convert reproducible bugs into heisenbugs?I pity the fool who uses -release.
Aug 30 2022
On 8/30/22 8:15 AM, bauss wrote:On Tuesday, 30 August 2022 at 11:55:29 UTC, Adam D Ruppe wrote:debug statements are not used by default. -SteveOn Tuesday, 30 August 2022 at 11:48:26 UTC, Tejas wrote:Arguably the only thing -release should ever have done is removing debug statements. Nothing more, nothing less.How do `assert`s convert reproducible bugs into heisenbugs?I pity the fool who uses -release.
Aug 30 2022
On 8/30/2022 4:55 AM, Adam D Ruppe wrote:I pity the fool who uses -release.-release is for people who do speed benchmarks. I speak from decades of experience.
Aug 30 2022
On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:-release is for people who do speed benchmarks.The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".
Aug 30 2022
On Tuesday, 30 August 2022 at 16:16:38 UTC, Adam D Ruppe wrote:On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:-release says use me in terms of meaning, but masters says don't use it. I didn't know it had such dire consequences. This is an issue that affects contract programming. SDB 79-release is for people who do speed benchmarks.The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".
Aug 30 2022
On 8/30/2022 9:25 AM, Salih Dincer wrote:On Tuesday, 30 August 2022 at 16:16:38 UTC, Adam D Ruppe wrote:It's not dire. It's just necessary to understand what's happening. People who do speed benchmarks rarely do more than glance at the documentation, if that.On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:-release says use me in terms of meaning, but masters says don't use it. I didn't know it had such dire consequences. This is an issue that affects contract programming.-release is for people who do speed benchmarks.The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".
Aug 30 2022
On 31.08.22 00:08, Walter Bright wrote:On 8/30/2022 9:25 AM, Salih Dincer wrote:I think the term is fitting. Contracts are meant to support correctness, not to help exacerbate vulnerabilities.On Tuesday, 30 August 2022 at 16:16:38 UTC, Adam D Ruppe wrote:It's not dire.On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:-release says use me in terms of meaning, but masters says don't use it. I didn't know it had such dire consequences. This is an issue that affects contract programming.-release is for people who do speed benchmarks.The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".It's just necessary to understand what's happening.People do not understand this. People barely understand undefined behavior. E.g., there were presentations at dconf where people were like: "we tested it [the piece of code with UB] and it worked, hence it is correct". A somewhat common use case is to disable contract/assert checking. Most people just assume that's what happens because introducing UB is not reasonable behavior.People who do speed benchmarks rarely do more than glance at the documentation, if that.People who don't know how to use the language usually write slow code anyway. (And it often computes only NaNs.)
Aug 30 2022
On Tue, Aug 30, 2022 at 04:16:38PM +0000, Adam D Ruppe via Digitalmars-d wrote:On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:It should be renamed to -optimize-for-benchmark. ;-) T -- "A man's wife has more power over him than the state has." -- Ralph Emerson-release is for people who do speed benchmarks.The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".
Aug 30 2022
On Friday, 26 August 2022 at 16:28:32 UTC, Steven Schveighoffer wrote:On 8/25/22 9:01 PM, Walter Bright wrote:At the end of the day, the answer is: Default initializing floats to NaN is (very) arguably important to the niche high-expertise line of work Walter engaged in, and *fairly annoying* to the vast sea of untapped market potential and prospective programmers D may or may not sorta-kinda-hope to snag a share of someday, as its figurative hairline gradually recedes trying to determine how best to balance being the greatest wisest language in the world at certain arbitrary vanishingly minor daily debugging issues while still providing users with countless ways to freely shoot themselves in the foot and crash their planes on weekends. It's all a weighting issue, and the weight has been placed on the importance of the niche work over the some small percentage of grumbling and stubbed toes the different-from-how-everyone-else-does-it change incurs.On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:I fully don't ever expect any changes to come from this discussion. But just to continue the point here, yes, it's slightly better in *some cases*. The question to answer is *how many cases*, and is the pain caused by having to go correct problems that should never have existed in the first place worth fixing those few cases where it actually helps.0 is no better here *but also no worse*.0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better.
Oct 12 2023
On Thursday, 12 October 2023 at 09:54:33 UTC, cc wrote:On Friday, 26 August 2022 at 16:28:32 UTC, Steven Schveighoffer wrote:Niche maybe. Many other languages default initialize floats to 0 (i.e. Go). But NaN initialization on floats/double/complex did save me few times in the past, and allowed to actually be able to trace the problem, that I probably did not even knew I had otherwise. I like NaN initialization. Just like I like null initialization for pointers.On 8/25/22 9:01 PM, Walter Bright wrote:At the end of the day, the answer is: Default initializing floats to NaN is (very) arguably important to the niche high-expertise line of work Walter engaged in, and *fairly annoying* to the vast sea of untapped market potential and prospective programmers D may or may not sorta-kinda-hope to snag a share of someday, as its figurative hairline gradually recedes trying to determine how best to balance being the greatest wisest language in the world at certain arbitrary vanishingly minor daily debugging issues while still providing users with countless ways to freely shoot themselves in the foot and crash their planes on weekends. It's all a weighting issue, and the weight has been placed on the importance of the niche work over the some small percentage of grumbling and stubbed toes the different-from-how-everyone-else-does-it change incurs.On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:I fully don't ever expect any changes to come from this discussion. But just to continue the point here, yes, it's slightly better in *some cases*. The question to answer is *how many cases*, and is the pain caused by having to go correct problems that should never have existed in the first place worth fixing those few cases where it actually helps.0 is no better here *but also no worse*.0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better.
Oct 25 2023
On Thursday, 26 October 2023 at 02:42:37 UTC, Witold wrote:I like NaN initialization. Just like I like null initialization for pointers.Me too. Actually, I just tried the follwing in importC, to see how dmd will handle the init: ``` import_c.c #include <stdio.h> int main() { int i; double d; printf("%d %f\n", i, d); return 0; } ``` $ dmd import_c.c $ ./import_c 1973916528 0.000000 $ ./import_c 1108345712 0.000000 looks like it still using the C semantics. From what I read "How ImportC Works": https://dlang.org/spec/importc.html#internals " ... converts the C syntax into the same AST (Abstract Syntax Tree) that D uses". So, I'm just wondering can we add a switch: I really want the ImportC will init the variable with D's semantics. Walter, How does this sound? :-)
Oct 25 2023
On Friday, 26 August 2022 at 01:01:24 UTC, Walter Bright wrote:On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:This seem be another string auto-decode problem to a basic type. It should implement similar to CheckedInt (as CheckedFloat?) for each case usage; not shoe horn into all use-cases0 is no better here *but also no worse*.0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better. Using 0x00 was nowhere near as effective.
Aug 26 2022
On Thursday, 25 August 2022 at 17:38:25 UTC, Steven Schveighoffer wrote:```d if(val > maxBW) delaySending(); ``` If `val` or `maxBW` are NaN, this will always be a false condition (because of the wonderful property that comparisons with NaN are always false), so that code effectively never executes. Note that there's no `printf` here, and the code happily compiles and runs, it just does something unexepected. 0 is no better here *but also no worse*.In hindsight, the robust way to solve this would be that trying to compare NaN to anything would crash the program. No way to add that to D without too much breakage though, I'm afraid.
Aug 26 2022
On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:A better option would be to throw an exception if NaN is used in an operation.How to kill a language, put exceptions everywhere, specially in math operations https://pspdfkit.com/blog/2020/performance-overhead-of-exceptions-in-cpp/ I hope you were joking
Aug 25 2022
On Friday, 26 August 2022 at 00:14:49 UTC, ryuukk_ wrote:On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:That's why my response to it said it should be Error and not Exception, your program is effectively dead if you ever operate on NaN.A better option would be to throw an exception if NaN is used in an operation.How to kill a language, put exceptions everywhere, specially in math operations https://pspdfkit.com/blog/2020/performance-overhead-of-exceptions-in-cpp/ I hope you were joking
Aug 25 2022
On 8/25/2022 11:13 PM, bauss wrote:That's why my response to it said it should be Error and not Exception, your program is effectively dead if you ever operate on NaN.NaN has another use. If, say, your data collection is incomplete (like having a dead pixel in an array of sensors), giving that data point a NaN helps show what part of the results of the data analysis is dependent on the missing data.
Aug 26 2022
On Friday, 26 August 2022 at 00:14:49 UTC, ryuukk_ wrote:How to kill a language, put exceptions everywhere, specially in math operations https://pspdfkit.com/blog/2020/performance-overhead-of-exceptions-in-cpp/ I hope you were jokingI think what he's meaning is that a HW exception happens on NaN. Floating point exceptions will hardly be used anywhere and will kill the program if it happens. The good thing is that you know exactly the instruction that caused it.
Aug 26 2022
On 8/25/22 8:14 PM, ryuukk_ wrote:On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:I'm not asking for this, I'm saying without having some sort of "fail upon use" mechanism (be it a signal or an exception), it's just not effective at finding initialization problems. What it has going for it over 0 is that it's definitively a problem *if you happen to see it*. But you have to look for it, and finding the source can be long gone by the time you see it. Think about null pointers -- they cost nothing but explode as soon as you try to use them. Exactly the correct mechanism, and it should happen close to where it was initialized. -SteveA better option would be to throw an exception if NaN is used in an operation.How to kill a language, put exceptions everywhere, specially in math operations https://pspdfkit.com/blog/2020/performance-overhead-of-exceptions-in-cpp/ I hope you were joking
Aug 26 2022
On 8/26/2022 9:22 AM, Steven Schveighoffer wrote:I'm not asking for this, I'm saying without having some sort of "fail upon use" mechanism (be it a signal or an exception), it's just not effective at finding initialization problems. What it has going for it over 0 is that it's definitively a problem *if you happen to see it*. But you have to look for it, and finding the source can be long gone by the time you see it.If you don't look for errors in the output, you are even less likely to find it with 0 initialization. I've also written here that there are legitimate uses of NaN where quitting upon use is undesirable. It's analogous to the "Replacement Char" in Unicode. We have experience with throwing an exception on seeing an invalid code point. It's the wrong answer. It's so wrong it's one of the motivators for Phobos version 2.
Aug 30 2022
On Tuesday, 30 August 2022 at 15:55:27 UTC, Walter Bright wrote:[snip] I've also written here that there are legitimate uses of NaN where quitting upon use is undesirable. [snip]I feel like there aren't a lot of people here who do data analysis with missing data...NaNs all over the place...
Aug 30 2022