digitalmars.D.learn - floating point verification using is?
- Steven Schveighoffer (6/6) Dec 18 2009 If I have 2 identical floating point values, how do I ensure they are
- bearophile (6/10) Dec 18 2009 Try this inside std.math of Phobos2:
- grauzone (5/20) Dec 18 2009 No. If you use it with structs, the type's opEquals is not called. "is"
- Steven Schveighoffer (13/22) Dec 18 2009 Thanks, that seems to be what I want.
- Steven Schveighoffer (14/24) Dec 18 2009 Except it doesn't work with literals properly:
- bearophile (5/12) Dec 18 2009 Try this:
- Steven Schveighoffer (9/19) Dec 18 2009 That's great, but I'm trying to verify that my array building code
- bearophile (24/29) Dec 18 2009 I see :-) Let's try again (but next time please explain the full problem...
- bearophile (19/19) Dec 18 2009 This may be better, I have not taken a look at the resulting asm yet:
- bearophile (4/15) Dec 18 2009 You can try expressing this idea in the main D group.
- div0 (18/26) Dec 18 2009 -----BEGIN PGP SIGNED MESSAGE-----
- Steven Schveighoffer (6/23) Dec 18 2009 nan is the specific one I was trying to test for.
- BCS (3/8) Dec 18 2009 yes, IIRC NaNs can have a few bits of payload as well as there being sig...
- bearophile (17/17) Dec 18 2009 Third try, this probably compiles better:
- bearophile (34/34) Dec 18 2009 4th try, getting there, this helps if in your compiler real == double:
- bearophile (30/30) Dec 18 2009 Unfortunately the asm produced by ldc shows the call to the array equali...
- Steven Schveighoffer (8/39) Dec 18 2009 Are you still working on this? :) I think this proves my point. The
- Stewart Gordon (13/18) Dec 27 2009 I entirely agree.
- Don (14/35) Dec 28 2009 No, it was because I have write access to Phobos, but not to the compile...
- Steven Schveighoffer (16/49) Dec 28 2009 The answer is a. Whether you like it or not, the runtime must initializ...
- Don (10/68) Dec 28 2009 The key question is: is it valid to read an uninitialized variable? I
- Steven Schveighoffer (17/51) Dec 28 2009 I am not even close to a floating point expert. In fact, I try to avoid...
- Don (9/70) Dec 29 2009 The thing is, if you've written something to a memory location, it's not...
-
Stewart Gordon
(33/36)
Dec 30 2009
- Don (16/63) Dec 30 2009 Yes, but it can be a QOI issue. That is, it's always a bug, the compiler...
- =?UTF-8?B?IkrDqXLDtG1lIE0uIEJlcmdlciI=?= (9/18) Dec 29 2009 Yes, it's a bug in the *sender*. However, the *receiver* should be=20
If I have 2 identical floating point values, how do I ensure they are binary equivalents of eachother? I'm trying to write some unittest/assert code, and it's not exactly trivial. I thought 'a is b' would work, but it just morphs into a == b, which isn't helpful. Why doesn't 'is' just do a bit compare for floating points? -Steve
Dec 18 2009
Steven Schveighoffer:If I have 2 identical floating point values, how do I ensure they are binary equivalents of eachother?Try this inside std.math of Phobos2: bool isIdentical(real x, real y);I thought 'a is b' would work, but it just morphs into a == b, which isn't helpful. Why doesn't 'is' just do a bit compare for floating points?"is" is used to compare references. Bye, bearophile
Dec 18 2009
bearophile wrote:Steven Schveighoffer:No. If you use it with structs, the type's opEquals is not called. "is" is used for a lot of things. I agree that is should do a bitwise comparison for floating points. That would be a nice fix for D2.If I have 2 identical floating point values, how do I ensure they are binary equivalents of eachother?Try this inside std.math of Phobos2: bool isIdentical(real x, real y);I thought 'a is b' would work, but it just morphs into a == b, which isn't helpful. Why doesn't 'is' just do a bit compare for floating points?"is" is used to compare references.Bye, bearophile
Dec 18 2009
On Fri, 18 Dec 2009 12:34:09 -0500, bearophile <bearophileHUGS lycos.com> wrote:Steven Schveighoffer:Thanks, that seems to be what I want.If I have 2 identical floating point values, how do I ensure they are binary equivalents of eachother?Try this inside std.math of Phobos2: bool isIdentical(real x, real y);to me, is means "ignore semantic meaning, do a bitwise compare" regardless of reference status. For example comparing 2 array structs using == will check that all the data is the same, but using "is" makes it compare bitwise the structs directly. I see no difference with floating points, except you can't get at the bits easily. The existence of isIdentical could be completely replaced by one or two instructions generated by the compiler when it sees "float is float". -SteveI thought 'a is b' would work, but it just morphs into a == b, which isn't helpful. Why doesn't 'is' just do a bit compare for floating points?"is" is used to compare references.
Dec 18 2009
On Fri, 18 Dec 2009 14:16:17 -0500, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Fri, 18 Dec 2009 12:34:09 -0500, bearophile <bearophileHUGS lycos.com> wrote:Except it doesn't work with literals properly: float x; assert(isIdentical(x, float.init)); // fails This is what I'm trying to test. It has to do with the fact that float.init is a literal, and I think it's automatically converted to real.init. This code works: float x; float y; assert(isIdentical(x, y)); I'm going to file a bug on this, float is float should just work! -SteveSteven Schveighoffer:Thanks, that seems to be what I want.If I have 2 identical floating point values, how do I ensure they are binary equivalents of eachother?Try this inside std.math of Phobos2: bool isIdentical(real x, real y);
Dec 18 2009
Steven Schveighoffer:float x; assert(isIdentical(x, float.init)); // fails This is what I'm trying to test. It has to do with the fact that float.init is a literal, and I think it's automatically converted to real.init.Try this: http://www.digitalmars.com/d/2.0/phobos/std_math.html#isNaN Bye, bearophile
Dec 18 2009
On Fri, 18 Dec 2009 14:47:13 -0500, bearophile <bearophileHUGS lycos.com> wrote:Steven Schveighoffer:That's great, but I'm trying to verify that my array building code correctly appends T.init. isNaN returns true no matter what the bit representation of nan is. I want to *specifically* compare bit representations of floating point numbers to ensure the code I'm writing is doing what I think it's doing. It shouldn't be this complicated to do that. -Stevefloat x; assert(isIdentical(x, float.init)); // fails This is what I'm trying to test. It has to do with the fact that float.init is a literal, and I think it's automatically converted to real.init.Try this: http://www.digitalmars.com/d/2.0/phobos/std_math.html#isNaN
Dec 18 2009
Steven Schveighoffer:That's great, but I'm trying to verify that my array building code correctly appends T.init. isNaN returns true no matter what the bit representation of nan is. I want to *specifically* compare bit representations of floating point numbers to ensure the code I'm writing is doing what I think it's doing.I see :-) Let's try again (but next time please explain the full problem in your first post, and not a slice of it): import std.c.stdio: printf; bool isNanInit(T)(T f) if (is(T == double) || is(T == float)) { union FPInt { T f; static if (is(T == float)) uint u; static if (is(T == double)) ulong u; } static FPInt fnan, fx; fx.f = f; return fnan.u == fx.u; } void main() { printf("%d\n", isNanInit(2.5)); float x; printf("%d\n", isNanInit(x)); x = 2.5; printf("%d\n", isNanInit(x)); } Bye, bearophile
Dec 18 2009
This may be better, I have not taken a look at the resulting asm yet: import std.traits: isFloatingPoint; import std.c.stdio: printf; bool isInitNan(T)(T f) if (isFloatingPoint!T) { union FPInt { T f; ubyte[T.sizeof] a; } static FPInt fnan, fx; fx.f = f; return fnan.a == fx.a; } void main() { printf("%d\n", isInitNan(2.5)); float x; printf("%d\n", isInitNan(x)); x = 2.5; printf("%d\n", isInitNan(x)); }
Dec 18 2009
Steven Schveighoffer:to me, is means "ignore semantic meaning, do a bitwise compare" regardless of reference status. For example comparing 2 array structs using == will check that all the data is the same, but using "is" makes it compare bitwise the structs directly. I see no difference with floating points, except you can't get at the bits easily. The existence of isIdentical could be completely replaced by one or two instructions generated by the compiler when it sees "float is float".You can try expressing this idea in the main D group. Bye, bearophile
Dec 18 2009
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Steven Schveighoffer wrote:If I have 2 identical floating point values, how do I ensure they are binary equivalents of eachother? I'm trying to write some unittest/assert code, and it's not exactly trivial. I thought 'a is b' would work, but it just morphs into a == b, which isn't helpful. Why doesn't 'is' just do a bit compare for floating points? -SteveJust out of curiosity; how many cases are there where a == b and they have different bit patterns? I can only think of +-0. Otherwise you can only get that with denormalised floats; which you won't get on an x86 processor. - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iD8DBQFLK86uT9LetA9XoXwRAvtsAKDDoX6EzXj+wOIgTVHDzkRF0vXGsgCdH6tX QLvFQxYyjIwk7Qxi13VyrCI= =M18X -----END PGP SIGNATURE-----
Dec 18 2009
On Fri, 18 Dec 2009 13:49:18 -0500, div0 <div0 users.sourceforge.net> wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Steven Schveighoffer wrote:nan is the specific one I was trying to test for. From my very hazy memory, I think there can even be multiple binary representations of nan, but I'm not sure. -SteveIf I have 2 identical floating point values, how do I ensure they are binary equivalents of eachother? I'm trying to write some unittest/assert code, and it's not exactly trivial. I thought 'a is b' would work, but it just morphs into a == b, which isn't helpful. Why doesn't 'is' just do a bit compare for floating points? -SteveJust out of curiosity; how many cases are there where a == b and they have different bit patterns? I can only think of +-0. Otherwise you can only get that with denormalised floats; which you won't get on an x86 processor.
Dec 18 2009
Hello Steven,From my very hazy memory, I think there can even be multiple binary representations of nan, but I'm not sure. -Steveyes, IIRC NaNs can have a few bits of payload as well as there being signaling and non-signaling NaNs.
Dec 18 2009
Third try, this probably compiles better: bool isInitNan(T)(T f) if (isFloatingPoint!T) { union FPInt { T f; static if (is(T == float)) uint data; static if (is(T == double)) ulong data; static if (is(T == real)) ubyte[real.sizeof] data; } static FPInt fnan, fx; fx.f = f; return fnan.data == fx.data; } Bye, bearophile
Dec 18 2009
4th try, getting there, this helps if in your compiler real == double: import std.traits: isFloatingPoint; import std.c.stdio: printf; bool isInitNaN(T)(T x) if (isFloatingPoint!T) { union FPData { T f; static if (T.sizeof == uint.sizeof) uint data; else static if (T.sizeof == ulong.sizeof) ulong data; else ubyte[T.sizeof] data; } static FPData fnan, fpd; fpd.f = x; return fnan.data == fpd.data; } void main() { printf("%d\n", isInitNaN(2.5f)); printf("%d\n", isInitNaN(2.5)); printf("%d\n", isInitNaN(2.5L)); float xf; printf("%d\n", isInitNaN(xf)); xf = 2.5; printf("%d\n", isInitNaN(xf)); double xd; printf("%d\n", isInitNaN(xd)); xd = 2.5; printf("%d\n", isInitNaN(xd)); float xr; printf("%d\n", isInitNaN(xr)); xr = 2.5; printf("%d\n", isInitNaN(xr)); }
Dec 18 2009
Unfortunately the asm produced by ldc shows the call to the array equality function still. Fifth try: bool isInitNaN(T)(T x) if (isFloatingPoint!T) { union FPData { T f; static if (T.sizeof == uint.sizeof) { uint data; } else static if (T.sizeof == ulong.sizeof) { ulong data; } else static if (T.sizeof == 10) { ulong data1; ushort data2; } else static if (T.sizeof == 12) { ulong data1; uint data2; } else static if (T.sizeof == 16) { ulong data1; ulong data2; } else { ubyte[T.sizeof] data; } } static FPData fnan, fpd; fpd.f = x; static if (T.sizeof == 10 || T.sizeof == 12 || T.sizeof == 16) return fnan.data1 == fpd.data1 && fnan.data2 == fpd.data2; else return fnan.data == fpd.data; } Bye, bearophile
Dec 18 2009
On Fri, 18 Dec 2009 21:47:22 -0500, bearophile <bearophileHUGS lycos.com> wrote:Unfortunately the asm produced by ldc shows the call to the array equality function still. Fifth try: bool isInitNaN(T)(T x) if (isFloatingPoint!T) { union FPData { T f; static if (T.sizeof == uint.sizeof) { uint data; } else static if (T.sizeof == ulong.sizeof) { ulong data; } else static if (T.sizeof == 10) { ulong data1; ushort data2; } else static if (T.sizeof == 12) { ulong data1; uint data2; } else static if (T.sizeof == 16) { ulong data1; ulong data2; } else { ubyte[T.sizeof] data; } } static FPData fnan, fpd; fpd.f = x; static if (T.sizeof == 10 || T.sizeof == 12 || T.sizeof == 16) return fnan.data1 == fpd.data1 && fnan.data2 == fpd.data2; else return fnan.data == fpd.data; } Bye, bearophileAre you still working on this? :) I think this proves my point. The compiler does not provide an easy way to compare floats bitwise, so this means convoluted hard-to-write code. When we have two operators that do equality -- and one of those means bitwise compare in all other contexts -- I think this is a no-brainer. -Steve
Dec 18 2009
Steven Schveighoffer wrote: <snip>Are you still working on this? :) I think this proves my point. The compiler does not provide an easy way to compare floats bitwise, so this means convoluted hard-to-write code. When we have two operators that do equality -- and one of those means bitwise compare in all other contexts -- I think this is a no-brainer.I entirely agree. I've identified these cases in which float equality disagrees with bitwise equality: - one is +0, one is -0 - both are NaNs, identically signed - both are infinity, identically signed In each case, is just does the same as ==. Indeed, isIdentical is an ugly workaround for this, apparently created instead of sanitising the definition of is to avoid the minuscule amount of code breakage that the latter would effect. Stewart.
Dec 27 2009
Stewart Gordon wrote:Steven Schveighoffer wrote: <snip>No, it was because I have write access to Phobos, but not to the compiler... But, this isn't as simple as people are assuming. There's a problem in the original request. We need to be clear about what T.init is. Is T.init (a) the bit pattern which all variables of type T get default initialized to? Or is it (b) an arbitrary valid value for type T? In the case of floats, they are NOT "default initialized" -- they are marked as "not initialized". So there's a big question about whether semantic (a) T.init actually makes sense. Consider this code: T x; if (x==T.init) { writefln("x is uninitialized"); } Is this code valid? You are reading the value of an uninitialized variable.Are you still working on this? :) I think this proves my point. The compiler does not provide an easy way to compare floats bitwise, so this means convoluted hard-to-write code. When we have two operators that do equality -- and one of those means bitwise compare in all other contexts -- I think this is a no-brainer.I entirely agree. I've identified these cases in which float equality disagrees with bitwise equality: - one is +0, one is -0 - both are NaNs, identically signed - both are infinity, identically signed In each case, is just does the same as ==. Indeed, isIdentical is an ugly workaround for this, apparently created instead of sanitising the definition of is to avoid the minuscule amount of code breakage that the latter would effect.
Dec 28 2009
On Mon, 28 Dec 2009 06:51:30 -0500, Don <nospam nospam.com> wrote:Stewart Gordon wrote:The answer is a. Whether you like it or not, the runtime must initialize it to something, even if the value means "uninitialized". That value should always be consistent. There has to be a way to verify that the value was set properly. Otherwise, how do you verify things like communication protocols or expectations for runtime functions? It has to be a bit pattern, because all other T.init values, including those of aggregates which might contain floating points, are bit patterns.Steven Schveighoffer wrote: <snip>No, it was because I have write access to Phobos, but not to the compiler... But, this isn't as simple as people are assuming. There's a problem in the original request. We need to be clear about what T.init is. Is T.init (a) the bit pattern which all variables of type T get default initialized to? Or is it (b) an arbitrary valid value for type T? In the case of floats, they are NOT "default initialized" -- they are marked as "not initialized". So there's a big question about whether semantic (a) T.init actually makes sense.Are you still working on this? :) I think this proves my point. The compiler does not provide an easy way to compare floats bitwise, so this means convoluted hard-to-write code. When we have two operators that do equality -- and one of those means bitwise compare in all other contexts -- I think this is a no-brainer.I entirely agree. I've identified these cases in which float equality disagrees with bitwise equality: - one is +0, one is -0 - both are NaNs, identically signed - both are infinity, identically signed In each case, is just does the same as ==. Indeed, isIdentical is an ugly workaround for this, apparently created instead of sanitising the definition of is to avoid the minuscule amount of code breakage that the latter would effect.Consider this code: T x; if (x==T.init) { writefln("x is uninitialized"); } Is this code valid? You are reading the value of an uninitialized variable.Correct that to: T x; if(x is T.init) {writefln("x is uninitialized"); } Then I think it is valid. I don't care if == is hijacked away from bitwise comparison, in fact, it is necessary in many cases. But there should be a way to do bitwise comparison for verification, and 'is' fits the bill perfectly. -Steve
Dec 28 2009
Steven Schveighoffer wrote:On Mon, 28 Dec 2009 06:51:30 -0500, Don <nospam nospam.com> wrote:The key question is: is it valid to read an uninitialized variable? I would hope the compiler would flag that as an error. The use of signalling NaNs was based on the assumption that you should *never* be reading uninitialized variables. A consequence is that you should also NEVER read float.init!Stewart Gordon wrote:The answer is a. Whether you like it or not, the runtime must initialize it to something, even if the value means "uninitialized".Steven Schveighoffer wrote: <snip>No, it was because I have write access to Phobos, but not to the compiler... But, this isn't as simple as people are assuming. There's a problem in the original request. We need to be clear about what T.init is. Is T.init (a) the bit pattern which all variables of type T get default initialized to? Or is it (b) an arbitrary valid value for type T? In the case of floats, they are NOT "default initialized" -- they are marked as "not initialized". So there's a big question about whether semantic (a) T.init actually makes sense.Are you still working on this? :) I think this proves my point. The compiler does not provide an easy way to compare floats bitwise, so this means convoluted hard-to-write code. When we have two operators that do equality -- and one of those means bitwise compare in all other contexts -- I think this is a no-brainer.I entirely agree. I've identified these cases in which float equality disagrees with bitwise equality: - one is +0, one is -0 - both are NaNs, identically signed - both are infinity, identically signed In each case, is just does the same as ==. Indeed, isIdentical is an ugly workaround for this, apparently created instead of sanitising the definition of is to avoid the minuscule amount of code breakage that the latter would effect.That value should always be consistent. There has to be a way to verify that the value was set properly. Otherwise, how do you verify things like communication protocols or expectations for runtime functions?I think that sending an uninitialized variable down a communication channel is always a bug.It has to be a bit pattern, because all other T.init values, including those of aggregates which might contain floating points, are bit patterns.That does preclude a compiler from ever giving you errors/warnings about using uninitialized variables. I think it's wrong.Consider this code: T x; if (x==T.init) { writefln("x is uninitialized"); } Is this code valid? You are reading the value of an uninitialized variable.Correct that to: T x; if(x is T.init) {writefln("x is uninitialized"); } Then I think it is valid. I don't care if == is hijacked away from bitwise comparison, in fact, it is necessary in many cases. But there should be a way to do bitwise comparison for verification, and 'is' fits the bill perfectly.
Dec 28 2009
On Mon, 28 Dec 2009 21:52:24 -0500, Don <nospam nospam.com> wrote:Steven Schveighoffer wrote:I am not even close to a floating point expert. In fact, I try to avoid them like the plague. All I want to do is verify that the bit pattern being written to a memory location is the bit pattern I expect to be written. How do I do that without comparing what I expect to what I wrote?Whether you like it or not, the runtime must initialize it to something, even if the value means "uninitialized".The key question is: is it valid to read an uninitialized variable? I would hope the compiler would flag that as an error. The use of signalling NaNs was based on the assumption that you should *never* be reading uninitialized variables. A consequence is that you should also NEVER read float.init!Just wait, someone will define it :) If I want to verify that it's any value *but* T.init, how do I do that? And I don't think using <>=! %$ to do it is worth the trouble.That value should always be consistent. There has to be a way to verify that the value was set properly. Otherwise, how do you verify things like communication protocols or expectations for runtime functions?I think that sending an uninitialized variable down a communication channel is always a bug.I'm not using it in every-day code (although I don't think it's wrong to do so), I'm using it for asserts and unit tests. I'm asserting that what's happening is what I expect is happening. To make this unreasonably difficult makes no sense to me. To say "is works on everything but floating point initializers" sounds ridiculously inconsistent. Maybe preventing it is the Right Thing to do, but it is possible to do, so what harm can it cause? It wouldn't even cause an exception. Note that I don't think == should change behavior, just 'is'. -SteveIt has to be a bit pattern, because all other T.init values, including those of aggregates which might contain floating points, are bit patterns.That does preclude a compiler from ever giving you errors/warnings about using uninitialized variables. I think it's wrong.Consider this code: T x; if (x==T.init) { writefln("x is uninitialized"); } Is this code valid? You are reading the value of an uninitialized variable.Correct that to: T x; if(x is T.init) {writefln("x is uninitialized"); } Then I think it is valid. I don't care if == is hijacked away from bitwise comparison, in fact, it is necessary in many cases. But there should be a way to do bitwise comparison for verification, and 'is' fits the bill perfectly.
Dec 28 2009
Steven Schveighoffer wrote:On Mon, 28 Dec 2009 21:52:24 -0500, Don <nospam nospam.com> wrote:The thing is, if you've written something to a memory location, it's not uninitialized any more.Steven Schveighoffer wrote:I am not even close to a floating point expert. In fact, I try to avoid them like the plague. All I want to do is verify that the bit pattern being written to a memory location is the bit pattern I expect to be written. How do I do that without comparing what I expect to what I wrote?Whether you like it or not, the runtime must initialize it to something, even if the value means "uninitialized".The key question is: is it valid to read an uninitialized variable? I would hope the compiler would flag that as an error. The use of signalling NaNs was based on the assumption that you should *never* be reading uninitialized variables. A consequence is that you should also NEVER read float.init!I think we could get the behaviour you want by changing the definition of T.init. I think it should ALWAYS be a bug to read an uninitialized variable; but it should be OK to have: T x = T.init; if (x == T.init) ... Otherwise, there's no point in making T.init available.Just wait, someone will define it :) If I want to verify that it's any value *but* T.init, how do I do that? And I don't think using <>=! %$ to do it is worth the trouble.That value should always be consistent. There has to be a way to verify that the value was set properly. Otherwise, how do you verify things like communication protocols or expectations for runtime functions?I think that sending an uninitialized variable down a communication channel is always a bug.I'm not using it in every-day code (although I don't think it's wrong to do so), I'm using it for asserts and unit tests. I'm asserting that what's happening is what I expect is happening. To make this unreasonably difficult makes no sense to me. To say "is works on everything but floating point initializers" sounds ridiculously inconsistent. Maybe preventing it is the Right Thing to do, but it is possible to do, so what harm can it cause? It wouldn't even cause an exception. Note that I don't think == should change behavior, just 'is'.It has to be a bit pattern, because all other T.init values, including those of aggregates which might contain floating points, are bit patterns.That does preclude a compiler from ever giving you errors/warnings about using uninitialized variables. I think it's wrong.Consider this code: T x; if (x==T.init) { writefln("x is uninitialized"); } Is this code valid? You are reading the value of an uninitialized variable.Correct that to: T x; if(x is T.init) {writefln("x is uninitialized"); } Then I think it is valid. I don't care if == is hijacked away from bitwise comparison, in fact, it is necessary in many cases. But there should be a way to do bitwise comparison for verification, and 'is' fits the bill perfectly.
Dec 29 2009
Don wrote: <snip>I think we could get the behaviour you want by changing the definition of T.init. I think it should ALWAYS be a bug to read an uninitialized variable;<snip> All variables in D are initialized, unless overridden with a void initializer. But what would "ALWAYS be a bug" mean? (a) Trigger a compile-time error? While some C(++) compilers will warn you if they catch you trying to read a variable before it's been set, they cannot be perfect at doing so. That's probably one reason that D takes the simpler route. (b) Trigger a run-time error? This would be a performance hit, as you'd need - extra working memory, as a bit to keep track of whether each variable is set - extra code to set and check this bit when a variable is used - extra CPU cycles to execute this extra code I'd be inclined to save this kind of behaviour for scripting languages. (c) Trigger undefined behaviour? I can't see any real way of making it undefined short of going back to the C way. One of D's reasons for initializing all variables is so that bugs caused by reading variables before they're otherwise set are easier to diagnose, since the behaviour doesn't change with every execution. Another reason I can see is to avoid memory trample, possibly also GC horrors, caused by leaving pointers accidentally pointing somewhere and then trying to use them. While you could get around this by defining that reference types are initialized to null and value types are not initialized, it's simpler to define that all variables are initialized. A further complication is that, in a struct or class, some members may have default initializers set and others not. Initializing a variable of struct or class type is much simpler if the fact of being initialized applies to the whole struct rather than some of its members. (d) Be perfectly legal and defined, yet deemed immoral? Stewart.
Dec 30 2009
Stewart Gordon wrote:Don wrote: <snip>Yes, but it can be a QOI issue. That is, it's always a bug, the compiler will do the best it can to detect it at compile time, but it isn't always possible. Proof: bool arbitrarily_difficult() {} int main() { int x; if (arbitrarily_difficult()) x=7; return x; } So it's clearly an NP-hard problem. So we have run-time initialisation to catch the cases that are too hard for the compiler.I think we could get the behaviour you want by changing the definition of T.init. I think it should ALWAYS be a bug to read an uninitialized variable;<snip> All variables in D are initialized, unless overridden with a void initializer. But what would "ALWAYS be a bug" mean? (a) Trigger a compile-time error? While some C(++) compilers will warn you if they catch you trying to read a variable before it's been set, they cannot be perfect at doing so. That's probably one reason that D takes the simpler route.(b) Trigger a run-time error? This would be a performance hit, as you'd need - extra working memory, as a bit to keep track of whether each variable is set - extra code to set and check this bit when a variable is used - extra CPU cycles to execute this extra code I'd be inclined to save this kind of behaviour for scripting languages. (c) Trigger undefined behaviour? I can't see any real way of making it undefined short of going back to the C way. One of D's reasons for initializing all variables is so that bugs caused by reading variables before they're otherwise set are easier to diagnose, since the behaviour doesn't change with every execution. Another reason I can see is to avoid memory trample, possibly also GC horrors, caused by leaving pointers accidentally pointing somewhere and then trying to use them. While you could get around this by defining that reference types are initialized to null and value types are not initialized, it's simpler to define that all variables are initialized. A further complication is that, in a struct or class, some members may have default initializers set and others not. Initializing a variable of struct or class type is much simpler if the fact of being initialized applies to the whole struct rather than some of its members. (d) Be perfectly legal and defined, yet deemed immoral?The question is, are they initialized solely in order to help detect bugs, or are they initialized so that you can use them?
Dec 30 2009
Don wrote:Steven Schveighoffer wrote:That value should always be consistent. There has to be a way to=20 verify that the value was set properly. Otherwise, how do you verify =Yes, it's a bug in the *sender*. However, the *receiver* should be=20 able to handle the case gracefully (and stopping because of a=20 signalling NaN is not "gracefully" :) Jerome --=20 mailto:jeberger free.fr http://jeberger.free.fr Jabber: jeberger jabber.frthings like communication protocols or expectations for runtime functions?=20 I think that sending an uninitialized variable down a communication=20 channel is always a bug. =20
Dec 29 2009