Re: Operator overloading, structs
Leandro Lucarella wrote: Don, el 10 de junio a las 03:50 me escribiste: Leandro Lucarella wrote: Don, el 10 de junio a las 02:02 me escribiste: bearophile wrote: Leandro Lucarella: I think the more general solution is to allow multiple implicit cast operators and simply provide implicit conversion to bool for the classes you want to be able to do if (x) on. No, it's not more general. *it is* more general, that's exactly what you don't like about it =) If you consider also introduces bugs as more general... I just call that wrong g. No, I consider not specialized or limited to one class of things[1] as more general. I'm not discussing if generality makes easy to introduce bugs in this case, that is what you are implying =) I'm implying that it does NOTHING other than introduce bugs. If you want to be pedantic: it does not reduce the limitations on useful behaviour. [1] Meaning taken from here http://wordnetweb.princeton.edu/perl/webwn?s=general (I've choose the meaning that better fit what I was trying to say) C++ libraries go to a fair bit of trouble to allow if(x) without allowing x to be converted to bool. I don't think is a *disaster*, but I agree that maybe the distintion can be useful (I didn't though about that). It's very important. If you allow implicit conversion to bool, all kinds of garbage will compile. You might as well abandon static typing. Again, I think this is a little too drastic. That makes me think, why not to disable implicit cast from bool to int? It's even defined what the value of int x = true; should be? Yes. It's 1. I guess there are plenty of cases where you don't want that, but I can't think of anything now... I can't think of any case where it's a good idea. (It's required in D1 because opEquals() stupidly returns int). I don't think is *required*, you can do an explicit cast, but it wouldn't be very nice indeed. BTW, wasn't that finally changed? Or it was a D2 only change? But that still leaves the problem: bool b = x; // doesn't compile if x is a class, or an array, or an AA. But it would compile if x is a struct with implicit conversion to bool. I don't understand why that should not compile if the class/array/AA has an implicit conversion to bool defined. Of course, int to bool implicit cast should still be possible. No. It isn't legal now! Only the special case of literals 0 and 1. Which is perfect. So is: int x; // ... if (x) // .. A special case? That's odd... It's a special idiom, which you mention at the end of your post. It doesn't involve implicit conversion to bool. Thus avoiding bugs. I think it makes perfect sense to allow implicit conversion from int to bool. I don't think bool should be considered a numeric type to be concerned about the precision loss (or there is another reason not to allow that?). The only time when you want to allow an implicit conversion to bool is when you have some kind of smart bool struct which is supposed to be a drop-in replacement for bool. It's quite distinct from if(x) -- if(x!=0). The strength of my proposal is that it would allow existing code to just work without modification. You wouldn't have to think about it. To argue against it, find a situation where it would be a problem. I think implicit conversion to bool is a very common idiom to quickly ask if something is not empty. That is not correct. if(x) does NOT involve an implicit conversion to bool. That's the key issue.
Re: Operator overloading, structs
bearophile: When the complex numbers are implemented by a struct in the standard library (or as in the original case of BigInts), I may like to keep being able to write: if (x) { ... } Where x is a Complex struct or BigInt struct that defines something like an opBool. In both those situations you can write: if (x != 0) { ... } They just need to define opEquals(int). It seems I was right, C# too defines something like it, true and false operators (I don't know why they have both of them; isn't one enough?): http://www.java2s.com/Tutorial/CSharp/0160__Operator-Overload/truefalseoperatorforComplex.htm There's a certain number of C# features I'd like to see in D (like nullable types that act as nan of floating point numbers, etc). Bye, bearophile
Re: Operator overloading, structs
bearophile Wrote: There's a certain number of C# features I'd like to see in D (like nullable types that act as nan of floating point numbers, etc). Bye, bearophile C#3 also provides the null coalescring operator (??): Code snippet 1 in C#1: Address address =user.getContactAddress; if(address==null) { address=order.getShippingAddress; if(address==null) { address=user.getBillingAddress; } } Code snippet 2 in C#3 with ?? operator: Address address=user.getContactAddress?? user.getShippingAddress?? user.getBillingAddress; Regards, Sam
Re: Operator overloading, structs
bearophile, el 10 de junio a las 08:23 me escribiste: Don: It's very important. If you allow implicit conversion to bool, all kinds of garbage will compile. You might as well abandon static typing. Some half-backed ideas. opBool() can be called implicitly when it's required a truth value test, like in if(x), while(x || y), etc. So this produces a type error: bool b = x; I just can't understand why someone would not want this conversion to work without a cast. Can anyone explain to me? -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) All mail clients suck. This one just sucks less. -me, circa 1995
Re: Operator overloading, structs
Don, el 10 de junio a las 03:50 me escribiste: Leandro Lucarella wrote: Don, el 10 de junio a las 02:02 me escribiste: bearophile wrote: Leandro Lucarella: I think the more general solution is to allow multiple implicit cast operators and simply provide implicit conversion to bool for the classes you want to be able to do if (x) on. No, it's not more general. *it is* more general, that's exactly what you don't like about it =) If you consider also introduces bugs as more general... I just call that wrong g. No, I consider not specialized or limited to one class of things[1] as more general. I'm not discussing if generality makes easy to introduce bugs in this case, that is what you are implying =) [1] Meaning taken from here http://wordnetweb.princeton.edu/perl/webwn?s=general (I've choose the meaning that better fit what I was trying to say) C++ libraries go to a fair bit of trouble to allow if(x) without allowing x to be converted to bool. I don't think is a *disaster*, but I agree that maybe the distintion can be useful (I didn't though about that). It's very important. If you allow implicit conversion to bool, all kinds of garbage will compile. You might as well abandon static typing. Again, I think this is a little too drastic. That makes me think, why not to disable implicit cast from bool to int? It's even defined what the value of int x = true; should be? Yes. It's 1. I guess there are plenty of cases where you don't want that, but I can't think of anything now... I can't think of any case where it's a good idea. (It's required in D1 because opEquals() stupidly returns int). I don't think is *required*, you can do an explicit cast, but it wouldn't be very nice indeed. BTW, wasn't that finally changed? Or it was a D2 only change? But that still leaves the problem: bool b = x; // doesn't compile if x is a class, or an array, or an AA. But it would compile if x is a struct with implicit conversion to bool. I don't understand why that should not compile if the class/array/AA has an implicit conversion to bool defined. Of course, int to bool implicit cast should still be possible. No. It isn't legal now! Only the special case of literals 0 and 1. Which is perfect. So is: int x; // ... if (x) // .. A special case? That's odd... I think it makes perfect sense to allow implicit conversion from int to bool. I don't think bool should be considered a numeric type to be concerned about the precision loss (or there is another reason not to allow that?). The only time when you want to allow an implicit conversion to bool is when you have some kind of smart bool struct which is supposed to be a drop-in replacement for bool. It's quite distinct from if(x) -- if(x!=0). The strength of my proposal is that it would allow existing code to just work without modification. You wouldn't have to think about it. To argue against it, find a situation where it would be a problem. I think implicit conversion to bool is a very common idiom to quickly ask if something is not empty. Most languages do that... -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) De las generaciones venideras espero, nada más, que vengan. -- Ricardo Vaporeso
Re: Operator overloading, structs
Don: That is, if x is a struct, convert if(x) into if(x==0) and convert if(!x) into if(x!=0). Usual rules would then apply, so any opEquals with a parameter which could be implicitly cast from 0 would work. That wouldn't allow smart-pointer structs to implement if (x) without requiring them to allow comparisons with integers, so it might be necessary to add a second step: try if(x==null) instead. I don't like this solution, because it relies on a bit of invisible magic, and you too have seen it needs extensions because it's not general. If you want to use if (x) where x doesn't represent a number but something else like a collection, they you have to add even more special cases like add a third step: if(x.length == 0) etc. So this is not a good solution. Alternatively, introduce a bool opNull() member function for structs. A similar method (we can discuss its name, that must be related to its semantic(*)) requires no invisible magic, it's clean and easy to use and implement, and it works on all three cases we have shown. This is a better solution. (*) I have suggested a name like bool opBool(), so if you perform a cast(bool)x this is the method that is called. But someone has said that in the case of if(x) that's not the method that is implicitly called... But it may be better to call it instead. So for me it's better to leave this to someone more expert than me. Bye, bearophile
Re: Operator overloading, structs
bearophile, el 9 de junio a las 08:19 me escribiste: Don: That is, if x is a struct, convert if(x) into if(x==0) and convert if(!x) into if(x!=0). Usual rules would then apply, so any opEquals with a parameter which could be implicitly cast from 0 would work. That wouldn't allow smart-pointer structs to implement if (x) without requiring them to allow comparisons with integers, so it might be necessary to add a second step: try if(x==null) instead. I don't like this solution, because it relies on a bit of invisible magic, and you too have seen it needs extensions because it's not general. If you want to use if (x) where x doesn't represent a number but something else like a collection, they you have to add even more special cases like add a third step: if(x.length == 0) etc. So this is not a good solution. I think the more general solution is to allow multiple implicit cast operators and simply provide implicit conversion to bool for the classes you want to be able to do if (x) on. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05)
Re: Operator overloading, structs
Leandro Lucarella: I think the more general solution is to allow multiple implicit cast operators and simply provide implicit conversion to bool for the classes you want to be able to do if (x) on. Yes, that's a more general solution, but I think Don thinks that solution is also less safe. I don't have enough experience on this to be able to tell, but generally the less invisible magic there is, the more clear the programs are. So better to limit the magic the few places where it's very useful (and where people know very well it can be present). Bye, bearophile
Re: Operator overloading, structs
bearophile wrote: Leandro Lucarella: I think the more general solution is to allow multiple implicit cast operators and simply provide implicit conversion to bool for the classes you want to be able to do if (x) on. No, it's not more general. You do NOT want to allow conversion to bool. The reason is that bool can itself be implicitly converted, eg this compiles: bool b = true; int y = b; -- And that's a disaster: struct Foo { bool opImplicitCast() { return true; } } Foo x; if (x) { ... } // OK int y = x; // This would compile C++ libraries go to a fair bit of trouble to allow if(x) without allowing x to be converted to bool.
Re: Operator overloading, structs
Don, el 10 de junio a las 02:02 me escribiste: bearophile wrote: Leandro Lucarella: I think the more general solution is to allow multiple implicit cast operators and simply provide implicit conversion to bool for the classes you want to be able to do if (x) on. No, it's not more general. *it is* more general, that's exactly what you don't like about it =) You do NOT want to allow conversion to bool. The reason is that bool can itself be implicitly converted, eg this compiles: bool b = true; int y = b; -- And that's a disaster: struct Foo { bool opImplicitCast() { return true; } } Foo x; if (x) { ... } // OK int y = x; // This would compile C++ libraries go to a fair bit of trouble to allow if(x) without allowing x to be converted to bool. I don't think is a *disaster*, but I agree that maybe the distintion can be useful (I didn't though about that). That makes me think, why not to disable implicit cast from bool to int? It's even defined what the value of int x = true; should be? I guess there are plenty of cases where you don't want that, but I can't think of anything now... Of course, int to bool implicit cast should still be possible. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) Le pedí que me enseñe a usar el mouse Pero solo quiere hablarme del Bauhaus Le pregunté si era chorra o rockera Me dijo Gertrude Stein era re-tortillera Me hizo mucho mal la cumbiera intelectual
Re: Operator overloading, structs
Leandro Lucarella wrote: Don, el 10 de junio a las 02:02 me escribiste: bearophile wrote: Leandro Lucarella: I think the more general solution is to allow multiple implicit cast operators and simply provide implicit conversion to bool for the classes you want to be able to do if (x) on. No, it's not more general. *it is* more general, that's exactly what you don't like about it =) If you consider also introduces bugs as more general... I just call that wrong g. You do NOT want to allow conversion to bool. The reason is that bool can itself be implicitly converted, eg this compiles: bool b = true; int y = b; -- And that's a disaster: struct Foo { bool opImplicitCast() { return true; } } Foo x; if (x) { ... } // OK int y = x; // This would compile C++ libraries go to a fair bit of trouble to allow if(x) without allowing x to be converted to bool. I don't think is a *disaster*, but I agree that maybe the distintion can be useful (I didn't though about that). It's very important. If you allow implicit conversion to bool, all kinds of garbage will compile. You might as well abandon static typing. That makes me think, why not to disable implicit cast from bool to int? It's even defined what the value of int x = true; should be? Yes. It's 1. I guess there are plenty of cases where you don't want that, but I can't think of anything now... I can't think of any case where it's a good idea. (It's required in D1 because opEquals() stupidly returns int). But that still leaves the problem: bool b = x; // doesn't compile if x is a class, or an array, or an AA. But it would compile if x is a struct with implicit conversion to bool. Of course, int to bool implicit cast should still be possible. No. It isn't legal now! Only the special case of literals 0 and 1. Which is perfect. The only time when you want to allow an implicit conversion to bool is when you have some kind of smart bool struct which is supposed to be a drop-in replacement for bool. It's quite distinct from if(x) -- if(x!=0). The strength of my proposal is that it would allow existing code to just work without modification. You wouldn't have to think about it. To argue against it, find a situation where it would be a problem.
Re: Operator overloading, structs
Don: On second thoughts, y = x.toLong or y = to!(long)(x) is probably better. Casts are evil, implicit casts even more so. I have seen you have added opEquals(int) and the like, thank you. But I don't see an efficient way to convert to int/long yet. Bye, bearophile
Re: Operator overloading, structs
Denis Koroskin wrote: On Thu, 04 Jun 2009 22:10:58 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Max Samukha wrote: On Thu, 04 Jun 2009 10:41:31 -0500, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: You are mistakenly presupposing that if() takes a bool. In reality if() accepts a bool, an integral, a floating-point type, a pointer, an array, or a class reference. or delegate I was sure I forgot something... and hash too. Anything that can be compared against 0 or null. Andrei Is it considered a good practice? Technically, the following construct is not exactly portable: float f = ..; if (f) { } because C (nor D) standard doesn't guaranty that float(0) will be implemented as all bits set to 0 on target platform (although it currently holds true). That _is_ guaranteed. Even on not-quite-conformant systems. Actually, -0.0 is not implemented as all-bits-zero, yet this works: void main(){ float f = -0.0; if (f) assert(0); } There's no portability problem here. To fix the original issue, we'd just need to allow something like: struct S { bool opEquals(int x) { return (x!=0); } } void main() { S x; if (x) assert(0); } That is, if x is a struct, convert if(x) into if(x==0) and convert if(!x) into if(x!=0). Usual rules would then apply, so any opEquals with a parameter which could be implicitly cast from 0 would work. That wouldn't allow smart-pointer structs to implement if (x) without requiring them to allow comparisons with integers, so it might be necessary to add a second step: try if(x==null) instead. Alternatively, introduce a bool opNull() member function for structs. Both solutions are easy to implement.
Re: Operator overloading, structs
On Thu, 04 Jun 2009 13:10:58 -0500, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Max Samukha wrote: On Thu, 04 Jun 2009 10:41:31 -0500, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: You are mistakenly presupposing that if() takes a bool. In reality if() accepts a bool, an integral, a floating-point type, a pointer, an array, or a class reference. or delegate I was sure I forgot something... and hash too. Anything that can be compared against 0 or null. Andrei Yeah. If anybody doesn't know, it works like this: IfStatement::semantic checks Expression::checkToBoolean, which for delete, assignment etc issues an error and for other expressions calls Type::checkBoolean, which for most types except arrays, class references etc. calls isscalar().
Re: Operator overloading, structs
bearophile wrote: Yigal Chripun: what's more readable, my version or yours? Mine, ihmo :-) Less things to remember. And the code is shorter and less noisy. Java programmers seems to ignore how much noisy is their code. empty collections are false is easy. You don't have to write code like: string s; if (s == null) ... if (s == ) ... if (s.length == 0) ... if (s.length) ... Or even: if (s is null) ... And few other variants I have seen in D code or snippets. Such things Do confuse d newbies (see digitalmars.D.learn). (If a collection is a class, and the object doesn't exists yet, and the variable is just a null reference, then it's false anyway the collection is empty still. Do you like this?). is a bad pattern. Why? it is even more problematic with floats. I think I have never had troubles from zero testing of floats/double/reals in D. If you want to try to convince other people (and I don't think D will change on this) you have to start listing some downsides of the current design, some real bugs it leads to, and so on. Bye, bearophile for starters, null and empty are two distinct concepts and sometimes it is important to know the difference. if (s is null) ... if (s == ) ... // NOT same thing as above also, with your version you need to remember _more_ things when reading code. I agree that the code is shorter but this is insignificant in this case. Java code has nothing to do with this and this is NOT the reason why Java code can be noisy.
Re: Operator overloading, structs
Andrei Alexandrescu wrote: Yigal Chripun wrote: your abstraction inversion example doesn't apply here. The problem I see is the narrowing implicit cast, i.e. int values behave like booleans. I have no problem with the reverse which is what your example is about. An int does not convert to bool implicitly. An int can be tested with if, which is a different thing. Andrei that is an implicit cast. what I'm saying is that: int a = .. ; if (a) { .. } this should be a compiler error IMO.
Re: Operator overloading, structs
Yigal Chripun: that is an implicit cast. what I'm saying is that: int a = .. ; if (a) { .. } this should be a compiler error IMO. I think the opposite is good: that empty collections are false, so the following ones print X: int[] a; if (!a) printf(X); Set!(int) s; if (!s) printf(X); int[string] aa; if (!aa) printf(X); Bye, bearophile
Re: Operator overloading, structs
On Thu, 04 Jun 2009 10:06:45 +0300, Yigal Chripun wrote: Andrei Alexandrescu wrote: Yigal Chripun wrote: your abstraction inversion example doesn't apply here. The problem I see is the narrowing implicit cast, i.e. int values behave like booleans. I have no problem with the reverse which is what your example is about. An int does not convert to bool implicitly. An int can be tested with if, which is a different thing. Andrei that is an implicit cast. what I'm saying is that: int a = .. ; if (a) { .. } this should be a compiler error IMO. I'm not agreeing with you, Yigal. I think that the idiom you described is not equivalent to if (a == TRUE) { .. } but really if (a != 0) { .. } when 'a' is an integer of any size or sign. This should *not* be a compiler error as it is a convenient shorthand for some coders. Personally, I try not to code this idiom because I find it misleading in terms of self documentation ... but then I'm against using goto as well ;-) -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Re: Operator overloading, structs
Yigal Chripun wrote: Andrei Alexandrescu wrote: Yigal Chripun wrote: your abstraction inversion example doesn't apply here. The problem I see is the narrowing implicit cast, i.e. int values behave like booleans. I have no problem with the reverse which is what your example is about. An int does not convert to bool implicitly. An int can be tested with if, which is a different thing. Andrei that is an implicit cast. No. An implicit cast is this: int a; bool b = a; // doesn't compile or this: void fun(bool); fun(5); // doesn't compile You are mistakenly presupposing that if() takes a bool. In reality if() accepts a bool, an integral, a floating-point type, a pointer, an array, or a class reference. Andrei
Re: Operator overloading, structs
On Thu, 04 Jun 2009 10:41:31 -0500, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: You are mistakenly presupposing that if() takes a bool. In reality if() accepts a bool, an integral, a floating-point type, a pointer, an array, or a class reference. or delegate
Re: Operator overloading, structs
Max Samukha wrote: On Thu, 04 Jun 2009 10:41:31 -0500, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: You are mistakenly presupposing that if() takes a bool. In reality if() accepts a bool, an integral, a floating-point type, a pointer, an array, or a class reference. or delegate I was sure I forgot something... and hash too. Anything that can be compared against 0 or null. Andrei
Re: Operator overloading, structs
On Thu, 04 Jun 2009 22:10:58 +0400, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: Max Samukha wrote: On Thu, 04 Jun 2009 10:41:31 -0500, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: You are mistakenly presupposing that if() takes a bool. In reality if() accepts a bool, an integral, a floating-point type, a pointer, an array, or a class reference. or delegate I was sure I forgot something... and hash too. Anything that can be compared against 0 or null. Andrei Is it considered a good practice? Technically, the following construct is not exactly portable: float f = ..; if (f) { } because C (nor D) standard doesn't guaranty that float(0) will be implemented as all bits set to 0 on target platform (although it currently holds true). I believe it is better to use an epsilon, instead: if (fabsf(f) epsilon) { } unless you need to compare strictly against 0: if (f == 0) { }
Re: Operator overloading, structs
Andrei Alexandrescu wrote: Yigal Chripun wrote: Andrei Alexandrescu wrote: Yigal Chripun wrote: your abstraction inversion example doesn't apply here. The problem I see is the narrowing implicit cast, i.e. int values behave like booleans. I have no problem with the reverse which is what your example is about. An int does not convert to bool implicitly. An int can be tested with if, which is a different thing. Andrei that is an implicit cast. No. An implicit cast is this: int a; bool b = a; // doesn't compile or this: void fun(bool); fun(5); // doesn't compile You are mistakenly presupposing that if() takes a bool. In reality if() accepts a bool, an integral, a floating-point type, a pointer, an array, or a class reference. Andrei I'm not debating terminology with you nor am I presupposing that if() currently takes a bool, I know it takes other types as well. what I am saying is that if needs to be fixed such that it _will_ take only bool. the the C idiom of: int a = ...; if (a) {...} is a bad pattern. it is even more problematic with floats. it _should_ be written always as: if (a == 0) { .. } zero is not false. in fact zero can be very positive: zero errors, zero cache misses, etc.
Re: Operator overloading, structs
Derek Parnell wrote: On Thu, 04 Jun 2009 10:06:45 +0300, Yigal Chripun wrote: Andrei Alexandrescu wrote: Yigal Chripun wrote: your abstraction inversion example doesn't apply here. The problem I see is the narrowing implicit cast, i.e. int values behave like booleans. I have no problem with the reverse which is what your example is about. An int does not convert to bool implicitly. An int can be tested with if, which is a different thing. Andrei that is an implicit cast. what I'm saying is that: int a = .. ; if (a) { .. } this should be a compiler error IMO. I'm not agreeing with you, Yigal. I think that the idiom you described is not equivalent to if (a == TRUE) { .. } but really if (a != 0) { .. } when 'a' is an integer of any size or sign. This should *not* be a compiler error as it is a convenient shorthand for some coders. Personally, I try not to code this idiom because I find it misleading in terms of self documentation ... but then I'm against using goto as well ;-) I don't see how we disagree since you say yourself that you try to avoid this idiom and find it misleading in terms of documentation. which I agree with. yes, it does save a few key strokes but as I said before, that's a really bad optimization since code is read much more often than it's written and readability is much more important than saving a few key strokes. I also agree about goto. there are very rare cases where it is useful but outside those goto is a bad bad thing to use.
Re: Operator overloading, structs
bearophile wrote: Yigal Chripun: that is an implicit cast. what I'm saying is that: int a = .. ; if (a) { .. } this should be a compiler error IMO. I think the opposite is good: that empty collections are false, so the following ones print X: int[] a; if (!a) printf(X); Set!(int) s; if (!s) printf(X); int[string] aa; if (!aa) printf(X); Bye, bearophile what's so bad about using a general collection.empty() API? int[] a; if (!a.empty) printf(X); Set!(int) s; if (!s.empty) printf(X); int[string] aa; if (!aa.empty) printf(X); what's more readable, my version or yours?
Re: Operator overloading, structs
On Thu, Jun 4, 2009 at 2:20 PM, Denis Koroskin 2kor...@gmail.com wrote: because C (nor D) standard doesn't guaranty that float(0) will be implemented as all bits set to 0 on target platform (although it currently holds true). Actually, D does. http://www.digitalmars.com/d/1.0/abi.html D requires floating-point types to be IEEE 754 compliant (though the current wording of 'real' might confusingly allow for other standards).
Re: Operator overloading, structs
Reply to Jarrett, On Thu, Jun 4, 2009 at 2:20 PM, Denis Koroskin 2kor...@gmail.com wrote: because C (nor D) standard doesn't guaranty that float(0) will be implemented as all bits set to 0 on target platform (although it currently holds true). Actually, D does. http://www.digitalmars.com/d/1.0/abi.html D requires floating-point types to be IEEE 754 compliant (though the current wording of 'real' might confusingly allow for other standards). I /think/ that it doesn't require that FP types be IEEE 754 types, just that they match the semantics (possibly with more accuracy). If you can assume that any FPU will be designed to work with IEEE 754 (would that be valid now days?), then you can assume that real will differ only by size. The only case I think you might need to look out for is where FP is done in software and at that point, what would real be anyway?
Re: Operator overloading, structs
Yigal Chripun: what's more readable, my version or yours? Mine, ihmo :-) Less things to remember. And the code is shorter and less noisy. Java programmers seems to ignore how much noisy is their code. empty collections are false is easy. You don't have to write code like: string s; if (s == null) ... if (s == ) ... if (s.length == 0) ... if (s.length) ... Or even: if (s is null) ... And few other variants I have seen in D code or snippets. Such things Do confuse d newbies (see digitalmars.D.learn). (If a collection is a class, and the object doesn't exists yet, and the variable is just a null reference, then it's false anywaythe collection is empty still. Do you like this?). is a bad pattern. Why? it is even more problematic with floats. I think I have never had troubles from zero testing of floats/double/reals in D. If you want to try to convince other people (and I don't think D will change on this) you have to start listing some downsides of the current design, some real bugs it leads to, and so on. Bye, bearophile
Re: Operator overloading, structs
BCS wrote: If you can assume that any FPU will be designed to work with IEEE 754 (would that be valid now days?) Not at all! IIRC, some of the PS2's CPUs don't implement NaN or Infinity (just check out the Advanced page of PCSX2, you can set how accurately the various PS2 CPUs FP operations are emulated on x86). Not sure if the PS2 is now days, but... Also, this is kind of old, but it suggests GPUs have all sorts of different behavior: http://www.cs.unc.edu/~ibr/projects/paranoia/ ... When being used only for graphics, accuracy often isn't as important as speed, however with GPGPU, I wouldn't be surprised if newer GPUs were IEEE-compliant.
Re: Operator overloading, structs
bearophile wrote: Yigal Chripun: any small positive epsilon is still greater than zero. Worse is better. An engineering system, as for example a computer language, is the result of lot of compromises. Better to keep yourself flexible. Bye, bearophile no. Worse is better implies a trade-off - you sacrifice something like purity, cleanliness, etc to gain simplicity of implementation. What I was trying to convey is that this does not apply here since there is no trade off to make - you get nothing by going with the worse option in this case.
Re: Operator overloading, structs
dsimcha wrote: == Quote from bearophile (bearophileh...@lycos.com)'s article Yigal Chripun: why not just use (i != 0) in both cases? Yes, here it can be done (if Don has implemented opEquals(int y)), but you don't need that once you have something like opBool. conversion of ints to bools in C is IMO a hole in the type system due to the lack of a boolean type in C. All those narrowing implicit casts inherited from C are a bad idea IMO. Walter was right, converting a generic integral to bool requires some time, that in the middle of the the nested loop can slow down code a bit (5%, in a case of mine). A standard opBool method allows you to tell when a collection is empty, like an empty string, an empty range, an empty array, and so on. you can use it instead of somecollection.isEmpty(). Java as Pascal keep booleans and integers separated, this looks tidy and clean. I love clean things, but in practice I don't think the current design of D (and C, Python, and several other languages) leads to a significant amount of bugs. It seems one of those situations where practical considerations win over purity. For D and other close to the metal languages, IMHO the int-bool relationship should stay the way it is simply because that's the way it works on the bare metal (at least on x86, for example, instructions like jz). I think this is a good rule of thumb in a close to the metal language, and even in the general case: When in doubt, do the thing that gives the user the least obstructed view of how things really work at the next lower level. This avoids lots of silly abstraction inversions (One of which is building a strong boolean type on top of an int). close to the metal does not imply in any way you code with binary op-codes or assembly concepts. all it means is that it does not force upon you costly abstractions and mechanisms like a VM. this does not apply to this discussion since a bool type doesn't require a VM and does not penalize performance in any way. your abstraction inversion example doesn't apply here. The problem I see is the narrowing implicit cast, i.e. int values behave like booleans. I have no problem with the reverse which is what your example is about.
Re: Operator overloading, structs
Yigal Chripun wrote: your abstraction inversion example doesn't apply here. The problem I see is the narrowing implicit cast, i.e. int values behave like booleans. I have no problem with the reverse which is what your example is about. An int does not convert to bool implicitly. An int can be tested with if, which is a different thing. Andrei
Re: Operator overloading, structs
Don wrote: ... On second thoughts, y = x.toLong or y = to!(long)(x) is probably better. Casts are evil, implicit casts even more so. If you add a toLong or to_long member to BigInt, then to!(long)(x) will work automatically. Something similar applies to fromLong/from_long and to!(BigInt)(cast(long)y).
Re: Operator overloading, structs
Don: Still, I wonder if D could simply do something like defining that for classes: if (x) is always transformed into if ( x!=0 ) if (!x) is always transformed into if ( x==0 ) Explicit is better than implicit. For example I'd like to have a set collection that is false when empty. In such situation I can write just the following method, it seems simpler and semantically cleaner than alternatives: bool opBool() { return this.length != 0; } On second thoughts, y = x.toLong or y = to!(long)(x) is probably better. Casts are evil, implicit casts even more so. I don't know. Using esplicit casts/methods may be safer. So with your current changes to BigInt, in the following program to replace the int i with a BigInt: void main() { int i = 1; if (i) i++; auto a = [10, 20, 30, 40]; printf(%d\n, a[i]); } you need to change the code like this: void main() { BigInt i = 1; if (i != 0) i++; auto a = [10, 20, 30, 40]; printf(%d\n, to!(long)a[i]); } The toBool will help avoid the change in the second line. I'd like to change programs as little as possible when I change the type of a variable from int to BigInt. This has also the big advantage that I can write templated algorithms that work with both ints and BigInts with as few static if as possible (to manage BigInts in a special way, for example adding that to!(long) ). That's why in such situation an implicit casting is handy. - Such almost-transparent replacement of ints with BigInts can be done also if BigInts are fast to perform operations with small integers (like with integers in range -1073741824 .. 1073741824). I have done few easy benchmarks (that I can show you if you want) and I have seen that when a bigint contains only ~30 bits of data or less a BigInt is much slower than an int. Some speed difference is inevitable, but to help such replacement I think it can be good if BigInts gain speed optimizations for small such numbers. (And when you use BigInts that contain 5000+ bits such optimizazions don't slow down BigInts significantly). Possible idea: you can test if the number needs less than 31 bits, if so, you can compute the operation using just a long. If the result then can be stored back in about 31 bits, then you are done. This is slower than a simple operation among ints but it may be much faster than the same operations done with BigInts. When numbers are so small the BigInt may also avoid all heap activity (Lisp languages do this using tags, they use a tagged pointer, that can be a small integer, avoiding any memory allocation when the number is small enough). Bye, bearophile
Re: Operator overloading, structs
bearophile wrote: So with your current changes to BigInt, in the following program to replace the int i with a BigInt: void main() { int i = 1; if (i) i++; auto a = [10, 20, 30, 40]; printf(%d\n, a[i]); } you need to change the code like this: void main() { BigInt i = 1; if (i != 0) i++; auto a = [10, 20, 30, 40]; printf(%d\n, to!(long)a[i]); } The toBool will help avoid the change in the second line. I'd like to change programs as little as possible when I change the type of a variable from int to BigInt. This has also the big advantage that I can write templated algorithms that work with both ints and BigInts with as few static if as possible (to manage BigInts in a special way, for example adding that to!(long) ). That's why in such situation an implicit casting is handy. why not just use (i != 0) in both cases? this should work with any numeric type (so it'll be used in generic code). conversion of ints to bools in C is IMO a hole in the type system due to the lack of a boolean type in C. All those narrowing implicit casts inherited from C are a bad idea IMO. the need to convert the bigInt to long in order to print it is a design error in printf() - the format string should specify the formatting of the variables not their types.
Re: Operator overloading, structs
Yigal Chripun: why not just use (i != 0) in both cases? Yes, here it can be done (if Don has implemented opEquals(int y)), but you don't need that once you have something like opBool. conversion of ints to bools in C is IMO a hole in the type system due to the lack of a boolean type in C. All those narrowing implicit casts inherited from C are a bad idea IMO. Walter was right, converting a generic integral to bool requires some time, that in the middle of the the nested loop can slow down code a bit (5%, in a case of mine). A standard opBool method allows you to tell when a collection is empty, like an empty string, an empty range, an empty array, and so on. you can use it instead of somecollection.isEmpty(). Java as Pascal keep booleans and integers separated, this looks tidy and clean. I love clean things, but in practice I don't think the current design of D (and C, Python, and several other languages) leads to a significant amount of bugs. It seems one of those situations where practical considerations win over purity. There are other situations where I'd like to see fixed some implicit type conversions. C# shows a saner design in such regard. There are few things in C# that I'd like to see copied by D. the need to convert the bigInt to long in order to print it is a design error in printf() - the format string should specify the formatting of the variables not their types. printf was invented lot of time ago, in galaxy far away, when needs and situations were different. That code of mine is wrong, this is more correct, so here it's not printf fault: printf(%d\n, a[to!(long)i]); Because it's i the BigInt, not the contents of the a array. Bye, bearophile
Re: Operator overloading, structs
== Quote from bearophile (bearophileh...@lycos.com)'s article Yigal Chripun: why not just use (i != 0) in both cases? Yes, here it can be done (if Don has implemented opEquals(int y)), but you don't need that once you have something like opBool. conversion of ints to bools in C is IMO a hole in the type system due to the lack of a boolean type in C. All those narrowing implicit casts inherited from C are a bad idea IMO. Walter was right, converting a generic integral to bool requires some time, that in the middle of the the nested loop can slow down code a bit (5%, in a case of mine). A standard opBool method allows you to tell when a collection is empty, like an empty string, an empty range, an empty array, and so on. you can use it instead of somecollection.isEmpty(). Java as Pascal keep booleans and integers separated, this looks tidy and clean. I love clean things, but in practice I don't think the current design of D (and C, Python, and several other languages) leads to a significant amount of bugs. It seems one of those situations where practical considerations win over purity. For D and other close to the metal languages, IMHO the int-bool relationship should stay the way it is simply because that's the way it works on the bare metal (at least on x86, for example, instructions like jz). I think this is a good rule of thumb in a close to the metal language, and even in the general case: When in doubt, do the thing that gives the user the least obstructed view of how things really work at the next lower level. This avoids lots of silly abstraction inversions (One of which is building a strong boolean type on top of an int).
Re: Operator overloading, structs
bearophile wrote: Yigal Chripun: why not just use (i != 0) in both cases? Yes, here it can be done (if Don has implemented opEquals(int y)), but you don't need that once you have something like opBool. conversion of ints to bools in C is IMO a hole in the type system due to the lack of a boolean type in C. All those narrowing implicit casts inherited from C are a bad idea IMO. Walter was right, converting a generic integral to bool requires some time, that in the middle of the the nested loop can slow down code a bit (5%, in a case of mine). A standard opBool method allows you to tell when a collection is empty, like an empty string, an empty range, an empty array, and so on. you can use it instead of somecollection.isEmpty(). Java as Pascal keep booleans and integers separated, this looks tidy and clean. I love clean things, but in practice I don't think the current design of D (and C, Python, and several other languages) leads to a significant amount of bugs. It seems one of those situations where practical considerations win over purity. There are other situations where I'd like to see fixed some implicit type conversions. C# shows a saner design in such regard. There are few things in C# that I'd like to see copied by D. if I understand you correctly, you claim that the C behavior is just more practical and/or useful than the Pascal approach. this is where we differ. The _only_ practical benefit I see is that it saves you two characters to type. on the other hand you get less readable code which can potentially be buggy. it's not important that the chance to get a bug here for an experienced C programmer (or a Python one) is slim since the comparison is against absolute zero chance of bugs with the pure approach. any small positive epsilon is still greater than zero. the need to convert the bigInt to long in order to print it is a design error in printf() - the format string should specify the formatting of the variables not their types. printf was invented lot of time ago, in galaxy far away, when needs and situations were different. That code of mine is wrong, this is more correct, so here it's not printf fault: printf(%d\n, a[to!(long)i]); Because it's i the BigInt, not the contents of the a array. Bye, bearophile
Re: Operator overloading, structs
Yigal Chripun: any small positive epsilon is still greater than zero. Worse is better. An engineering system, as for example a computer language, is the result of lot of compromises. Better to keep yourself flexible. Bye, bearophile
Re: Operator overloading, structs
bearophile wrote: This post is mostly about D2 operator overloading in general, but I also talk about problems in the API of Tango BigInts. A small program that use multiprecision integers of Tango: import tango.stdc.stdio: printf; import tango.math.BigInt: bint = BigInt; void main() { bint i = 1; // #1 if (i) // #2 i++; auto a = [10, 20, 30, 40]; printf(%d\n, a[i]); // #3 } If you replace BigInt with int that program works. With bigInteger it doesn't work, because I think: - In #1 it doesn't call static opCall. Works for me with int. I've fixed BigInt so that it now works with long as well. - In #2 D doesn't have a standard method that returns true/false. In Python2.6 such method is named __nonzero__ and in python3 it's named __bool__. - In #3 there's no implicit cast to int. I think that improving such D2 operator overloading is very good, it allows to use BigInts, SafeInts, Complex, etc, in a quite more transparent way, allowing very similar code to work with native and user defined types. --- Regarding specifically BigInt: D1 has opCast, but here I think not even a[cast(long)i] works, because BigInt doesn't define it yet. When a big int can't be converted to long, it can throw an exception. Yes, that's not a bad idea. Until a more efficient solution is found, I think BigInts must have a toString too. In most situations you don't print such numbers, you do lot of computations with them and then you finally print some of them. So often the time spent printing them is not much). Not toString(), though. You MUST be able to specify if you want leading zeros, and if you want hex or decimal. I just (a) haven't got around to it; and (b) haven't been sure about the interface should be. But I hate toString() so much, I'm _never_ going to support it. It's an OMDB (over my dead body). Sorry. I think BigInt also may enjoy a lot methods like: int opEquals(int y), etc. Ouch! That's a simple omission. Fixed in Tango SVN 4717.
Re: Operator overloading, structs
- In #2 D doesn't have a standard method that returns true/false. In Python2.6 such method is named __nonzero__ and in python3 it's named __bool__. No one has commented about that, but I think that having a way to overload cast(bool)foo is important. I use it in Python and I have shown why and how it can be used in D too. It's an easy thing to do and I think it's safe. Don: D1 has opCast, but here I think not even a[cast(long)i] works, because BigInt doesn't define it yet. When a big int can't be converted to long, it can throw an exception. Yes, that's not a bad idea. But eventually an implicit cast will be better (even if a bit less safe) in D2. Not toString(), though. You MUST be able to specify if you want leading zeros, and if you want hex or decimal. toString() is for the default case, when you just want the decimal number with no leading zeros. Then you can add other methods to output hex and all you want. (In what situations do you want to print leading zeros of a big multiprecision integral value? I have never faced such need so far). But I hate toString() so much, I'm _never_ going to support it. It's an OMDB (over my dead body). Sorry. I have patched a copy of the bigint module to add the toString method. I'll keep using such patch for my programs. I want you well alive and happy too. Fixed in Tango SVN 4717. Thank you. Bye, bearophile
Re: Operator overloading, structs
bearophile wrote: - In #2 D doesn't have a standard method that returns true/false. In Python2.6 such method is named __nonzero__ and in python3 it's named __bool__. No one has commented about that, but I think that having a way to overload cast(bool)foo is important. I use it in Python and I have shown why and how it can be used in D too. It's an easy thing to do and I think it's safe. It's definitely required for completeness. In C++ there's a hack to do it safely (you return a pointer to a private member class). Still, I wonder if D could simply do something like defining that for classes: if (x) is always transformed into if ( x!=0 ) if (!x) is always transformed into if ( x==0 ) Don: D1 has opCast, but here I think not even a[cast(long)i] works, because BigInt doesn't define it yet. When a big int can't be converted to long, it can throw an exception. Yes, that's not a bad idea. But eventually an implicit cast will be better (even if a bit less safe) in D2. On second thoughts, y = x.toLong or y = to!(long)(x) is probably better. Casts are evil, implicit casts even more so. Not toString(), though. You MUST be able to specify if you want leading zeros, and if you want hex or decimal. toString() is for the default case, when you just want the decimal number with no leading zeros. Then you can add other methods to output hex and all you want. (In what situations do you want to print leading zeros of a big multiprecision integral value? I have never faced such need so far). BigFloat, for example.