digitalmars.D - If !in is inconsistent because of bool/pointer, then so is !
- downs (3/3) Feb 06 2009 This has been brought up before as an argument against the !in operator ...
- bearophile (4/5) Feb 06 2009 If the pressure coming from such silly limits/warts gets large enough, L...
- grauzone (3/3) Feb 06 2009 vote++ for !in
- Moritz Warning (3/15) Feb 06 2009 Having such operator/syntactic sugar would be very nice.
- Rainer Deyke (11/15) Feb 06 2009 I agree. 'a != b' is short for '!(a == b)'. 'a !is b' is short for
- downs (3/20) Feb 06 2009 Hmm ...
- Rainer Deyke (13/16) Feb 06 2009 It's a question of consistent patterns versus special cases. If
- bearophile (6/7) Feb 06 2009 You may think that for humans it's better to have a very orthogonal lang...
- Bill Baxter (21/26) Feb 06 2009 age, like for example Scheme.
- bearophile (4/5) Feb 06 2009 Of course.
- Rainer Deyke (17/21) Feb 06 2009 I had to check the spec for the difference. 'a !< b' and '!(a < b)'
- Daniel Keep (3/24) Feb 06 2009 I believe this is, or is the result of, an aspect of IEEE floating point...
- Don (4/30) Feb 06 2009 Yes. It's the hardware. It's hard to find situations where the
- Rainer Deyke (24/35) Feb 06 2009 I don't have a copy of the IEEE floating point standard, but I strongly
- Don (29/63) Feb 07 2009 I don't have the final standard, but the last publically avilable draft
- downs (2/10) Feb 07 2009 Well yeah, but note that it can be pronounced "not bigger", as opposed t...
- Simen Kjaeraas (5/9) Feb 08 2009 From the identity (a != b) == !(a == b), you could argue that
This has been brought up before as an argument against the !in operator (forcing us to resort to such workarounds as /notin/): that the !in operator would have inconsistent syntax with in, because in returns a pointer and !in would return a bool. This is NOT a reason against !in. In fact, this so-called "inconsistency" is already present in the language. If we remember, !pointer already transforms it into a boolean, so it would actually be more consistent if !in changed the return type to bool. Furthermore, many newcomers expect !in to work because it is intuitive. Violating such user expectations should be avoided wherever possible.
Feb 06 2009
downs:Furthermore, many newcomers expect !in to work because it is intuitive. Violating such user expectations should be avoided wherever possible.If the pressure coming from such silly limits/warts gets large enough, LDC may start fixing them independently from DMD (I don't know what LDC developers think about this idea). Bye, bearophile
Feb 06 2009
vote++ for !in It's one of those things, which are very annoying to programmers, but very easy to fix. Just do it, Walter.
Feb 06 2009
On Fri, 06 Feb 2009 12:42:30 +0100, downs wrote:This has been brought up before as an argument against the !in operator (forcing us to resort to such workarounds as /notin/): that the !in operator would have inconsistent syntax with in, because in returns a pointer and !in would return a bool. This is NOT a reason against !in. In fact, this so-called "inconsistency" is already present in the language. If we remember, !pointer already transforms it into a boolean, so it would actually be more consistent if !in changed the return type to bool. Furthermore, many newcomers expect !in to work because it is intuitive. Violating such user expectations should be avoided wherever possible.Having such operator/syntactic sugar would be very nice. None of the arguments against it have convinced me so far.
Feb 06 2009
downs wrote:This is NOT a reason against !in. In fact, this so-called "inconsistency" is already present in the language. If we remember, !pointer already transforms it into a boolean, so it would actually be more consistent if !in changed the return type to bool.I agree. 'a != b' is short for '!(a == b)'. 'a !is b' is short for '!(a in b)'. For consistency, 'a !in b ' should be short for '!(a in b)'. I'd even go so far as to say that 'a !+ b' should be short for '!(a + b)', although I can't think of a use for the '!+' operator. a !<op> b == !(a <op> b): simple, consistent pattern. a !<op> b == !(a <op> b), but only for <op> in some limited set that doesn't include all operators with which you might want to use the pattern: less consistent; requires memorization. -- Rainer Deyke - rainerd eldwood.com
Feb 06 2009
Rainer Deyke wrote:downs wrote:Hmm ... A large part of the case for !in is that you can pronounce it "a *not in* b". !+, on the other hand, would be .. what? "a not plus b? does that mean a - b? " :)This is NOT a reason against !in. In fact, this so-called "inconsistency" is already present in the language. If we remember, !pointer already transforms it into a boolean, so it would actually be more consistent if !in changed the return type to bool.I agree. 'a != b' is short for '!(a == b)'. 'a !is b' is short for '!(a in b)'. For consistency, 'a !in b ' should be short for '!(a in b)'. I'd even go so far as to say that 'a !+ b' should be short for '!(a + b)', although I can't think of a use for the '!+' operator. a !<op> b == !(a <op> b): simple, consistent pattern. a !<op> b == !(a <op> b), but only for <op> in some limited set that doesn't include all operators with which you might want to use the pattern: less consistent; requires memorization.
Feb 06 2009
downs wrote:A large part of the case for !in is that you can pronounce it "a *not in* b". !+, on the other hand, would be .. what? "a not plus b? does that mean a - b? " :)It's a question of consistent patterns versus special cases. If 'a !<op> b == !(a <op> b)', then the parser can rewrite all 'a !<op> b' expressions as '!(a <op> b)' in a single place, without looking at what <op> is. (Of course '!=' (as the opposite of '==' as opposed to '=') is already a special case, so perhaps defining the '!<op>' operators individually is unavoidable. 'a !== b' as '!(a == b)' would work, but 'a != b' as '!(a = b)' would be very weird and inconsistent with other languages.) I'm not suggesting that anybody should actually /use/ the '!+' operator, even if it was defined. That would be horrible. -- Rainer Deyke - rainerd eldwood.com
Feb 06 2009
Rainer Deyke:It's a question of consistent patterns versus special cases.You may think that for humans it's better to have a very orthogonal language, like for example Scheme. There's also a famous quote about this, "Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary." But in practice the large part of programmers work with languages like Java, C, restrictions compared to Scheme. This is a long thing to explain, and I don't have enough space in this tight post to explain it, but the short version is that removing "special cases" as allowing !+ makes the language worse, less easy to use, more bug-prone, and generally less good. Bye, bearophile
Feb 06 2009
On Sat, Feb 7, 2009 at 8:54 AM, bearophile <bearophileHUGS lycos.com> wrote= :Rainer Deyke:age, like for example Scheme.It's a question of consistent patterns versus special cases.You may think that for humans it's better to have a very orthogonal langu=There's also a famous quote about this, "Programming languages should be =designed not by piling feature on top of feature, but by removing the weakn= esses and restrictions that make additional features appear necessary." But= in practice the large part of programmers work with languages like Java, C= estrictions compared to Scheme.This is a long thing to explain, and I don't have enough space in this ti=ght post to explain it, but the short version is that removing "special cas= es" as allowing !+ makes the language worse, less easy to use, more bug-pro= ne, and generally less good. Note that D already has things like !>. But quoth the spec: "For floating point comparison operators, (a !op b) is *NOT* the same as !(a op b)." [emphasis added] But anyway I wholeheartedly agree that (a !in b) should exist and it should be the same as !(a in b). I think the principle of least surprise is generally a good one to follow. And I think most people are surprised that (a !is b) means !(a is b), while the same is not true of (a !in b). --bb
Feb 06 2009
Bill Baxter:(a !in b) should exist and it should be the same as !(a in b).Of course. Bye, bearophile
Feb 06 2009
Bill Baxter wrote:Note that D already has things like !>. But quoth the spec: "For floating point comparison operators, (a !op b) is *NOT* the same as !(a op b)." [emphasis added]I had to check the spec for the difference. 'a !< b' and '!(a < b)' /are/ equivalent in the sense that '(a !< b) == !(a < b)' for any values of 'a' and 'b'. The vast majority of the time, the expressions 'a !< b' and '!(a < b)' /are/ interchangeable. The difference is that '!(a < b)' sets a global exception state if either operand is NaN, while 'a !< b' does not. This is, in my opinion, a significant design error in the language. The difference between '!(a < b)' and 'a !< b' is not obvious. There is nothing about the operator '<' that suggests that it should set a global exception state, and there is nothing about '!<' that suggests that it should /not/ set a global exception state. (Is global state for error reporting ever a good idea in a high-level language?) It also adds awkward expressions to the language, not just in the form '!(a < b)', but in the form '!(a !< b)'. -- Rainer Deyke - rainerd eldwood.com
Feb 06 2009
Rainer Deyke wrote:Bill Baxter wrote:I believe this is, or is the result of, an aspect of IEEE floating point. -- DanielNote that D already has things like !>. But quoth the spec: "For floating point comparison operators, (a !op b) is *NOT* the same as !(a op b)." [emphasis added]I had to check the spec for the difference. 'a !< b' and '!(a < b)' /are/ equivalent in the sense that '(a !< b) == !(a < b)' for any values of 'a' and 'b'. The vast majority of the time, the expressions 'a !< b' and '!(a < b)' /are/ interchangeable. The difference is that '!(a < b)' sets a global exception state if either operand is NaN, while 'a !< b' does not. This is, in my opinion, a significant design error in the language. The difference between '!(a < b)' and 'a !< b' is not obvious. There is nothing about the operator '<' that suggests that it should set a global exception state, and there is nothing about '!<' that suggests that it should /not/ set a global exception state. (Is global state for error reporting ever a good idea in a high-level language?) It also adds awkward expressions to the language, not just in the form '!(a < b)', but in the form '!(a !< b)'.
Feb 06 2009
Daniel Keep wrote:Rainer Deyke wrote:Yes. It's the hardware. It's hard to find situations where the difference matters. And this is why !<> and !<>= are the only ones of those operators which are actually useful.Bill Baxter wrote:I believe this is, or is the result of, an aspect of IEEE floating point. -- DanielNote that D already has things like !>. But quoth the spec: "For floating point comparison operators, (a !op b) is *NOT* the same as !(a op b)." [emphasis added]I had to check the spec for the difference. 'a !< b' and '!(a < b)' /are/ equivalent in the sense that '(a !< b) == !(a < b)' for any values of 'a' and 'b'. The vast majority of the time, the expressions 'a !< b' and '!(a < b)' /are/ interchangeable. The difference is that '!(a < b)' sets a global exception state if either operand is NaN, while 'a !< b' does not. This is, in my opinion, a significant design error in the language. The difference between '!(a < b)' and 'a !< b' is not obvious. There is nothing about the operator '<' that suggests that it should set a global exception state, and there is nothing about '!<' that suggests that it should /not/ set a global exception state. (Is global state for error reporting ever a good idea in a high-level language?) It also adds awkward expressions to the language, not just in the form '!(a < b)', but in the form '!(a !< b)'.
Feb 06 2009
Daniel Keep wrote:Rainer Deyke wrote:I don't have a copy of the IEEE floating point standard, but I strongly suspect it would have allowed syntax like: a < b // sets global state a !< b // sets global state less_than_no_state(a, b) // does not set global state !less_than_no_state(a, b) // does not set global state Or: a < b // does not set global state a !< b // does not set global state less_than_set_state(a, b) // sets global state !less_than_set_state(a, b) // sets global state Or: a < b // sets global state a !< b // sets global state a [<] b // does not set global state a [!<] b // does not set global state Or any number of other syntax choices, all less confusing than the syntax actually used. This is assuming we need two sets of comparison operators, one of which uses global state to report NaN operands and one which does not. I'm not convinced that this is the case. -- Rainer Deyke - rainerd eldwood.comThis is, in my opinion, a significant design error in the language. The difference between '!(a < b)' and 'a !< b' is not obvious. There is nothing about the operator '<' that suggests that it should set a global exception state, and there is nothing about '!<' that suggests that it should /not/ set a global exception state. (Is global state for error reporting ever a good idea in a high-level language?) It also adds awkward expressions to the language, not just in the form '!(a < b)', but in the form '!(a !< b)'.I believe this is, or is the result of, an aspect of IEEE floating point.
Feb 06 2009
Rainer Deyke wrote:Daniel Keep wrote:I don't have the final standard, but the last publically avilable draft (IEE754R Draft 1.2.5, Oct 2006) states: "The unordered-signaling predicates in Table 9, intended for use by programs not written to take into account the possibility of NaN operands, signal an invalid exception on quiet NaN operands:" [table 9] "The unordered-quiet predicates in Table 10, intended for use by programs written to take into account the possibility of NaN operands, do not signal an exception on quiet NaN operands:" [table 10] "There are two ways to write the logical negation of a predicate, one using NOT explicitly and the other reversing the relational operator. Thus in programs written without considering the possibility of a NaN operand, the logical negation of the unordered-signaling predicate (X < Y) is just the unordered-signaling predicate NOT(X < Y); the unordered-quiet reversed predicate (X ?>= Y) is different in that it does not signal an invalid operation exception when X and Y are unordered. In contrast, the logical negation of (X = Y) may be written either NOT(X = Y) or (X ?<> Y); in this case both expressions are functionally equivalent to (X != Y). The "global state" you're referring to is just a flag in the floating-point status register. Although I believe you could implement these comparisons as functions rather than operators, they'd have to be intrinsics. On x87, the normal comparisons are done with the FCOM instruction, and the others are done with FCOMI. That's the only difference.Rainer Deyke wrote:I don't have a copy of the IEEE floating point standard, but I strongly suspect it would have allowed syntax like: a < b // sets global state a !< b // sets global state less_than_no_state(a, b) // does not set global state !less_than_no_state(a, b) // does not set global state Or: a < b // does not set global state a !< b // does not set global state less_than_set_state(a, b) // sets global state !less_than_set_state(a, b) // sets global state Or: a < b // sets global state a !< b // sets global state a [<] b // does not set global state a [!<] b // does not set global state Or any number of other syntax choices, all less confusing than the syntax actually used. This is assuming we need two sets of comparison operators, one of which uses global state to report NaN operands and one which does not. I'm not convinced that this is the case.This is, in my opinion, a significant design error in the language. The difference between '!(a < b)' and 'a !< b' is not obvious. There is nothing about the operator '<' that suggests that it should set a global exception state, and there is nothing about '!<' that suggests that it should /not/ set a global exception state. (Is global state for error reporting ever a good idea in a high-level language?) It also adds awkward expressions to the language, not just in the form '!(a < b)', but in the form '!(a !< b)'.I believe this is, or is the result of, an aspect of IEEE floating point.
Feb 07 2009
Bill Baxter wrote:On Sat, Feb 7, 2009 at 8:54 AM, bearophile <bearophileHUGS lycos.com> wrote:Well yeah, but note that it can be pronounced "not bigger", as opposed to !+.Rainer Deyke:Note that D already has things like !>.It's a question of consistent patterns versus special cases.You may think that for humans it's better to have a very orthogonal language, like for example Scheme. There's also a famous quote about this, "Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary." But in practice the large part of programmers work with languages like Java, C, restrictions compared to Scheme. This is a long thing to explain, and I don't have enough space in this tight post to explain it, but the short version is that removing "special cases" as allowing !+ makes the language worse, less easy to use, more bug-prone, and generally less good.
Feb 07 2009
On Sat, 07 Feb 2009 00:39:33 +0100, Rainer Deyke <rainerd eldwood.com> wrote:(Of course '!=' (as the opposite of '==' as opposed to '=') is already a special case, so perhaps defining the '!<op>' operators individually is unavoidable. 'a !== b' as '!(a == b)' would work, but 'a != b' as '!(a = b)' would be very weird and inconsistent with other languages.)From the identity (a != b) == !(a == b), you could argue that (a !<op> b) == !(a <op>= b), but I can hardly see that being better. :p -- Simen
Feb 08 2009