
I just stared at this a long time:
It's "correct". I've been using Python longer than Guido <wink>, and I'm amazed this is the first time I got bit by this! Here's a hint:
'a' in 'a' == 'a' 1
thank-god-for-dis.dis-ly y'rs - tim

Tim Peters wrote:
[potential spoilers below] No, thank Jeremy for Compiler: Module(None, Stmt( [ Printnl( [ Compare(Const('a'), [ ('in', Const('abcde')), ('==', Const('abcde')) ] ) ], None ) ] ) ) It still took a look at the ref manual for me to figure it out. It looks like dubious hypergeneralization to me! <0.7 wink> Seriously, does this "feature" ever make sense to apply to the in operator? -- Take a recipe. Leave a recipe. Python Cookbook! http://www.ActiveState.com/pythoncookbook

Yeah, I ran into the same when converting some has_key() tests to using 'in'. I guess it's not very common since nobody in their right minds should want to compare the result of an 'in' test to anything else. The has_key() tests did something like "assert d.has_key(k)==1" and the mindless translation of that is "assert k in d == 1"... Didn't-need-dis-though-ly y'rs, --Guido van Rossum (home page: http://www.python.org/~guido/)

[Tim, 'a' in 'a' == 1, etc] [Guido]
Yeah, I ran into the same when converting some has_key() tests to using 'in'.
Bingo! Same here, but after adding __iter__ and __contains__ to UserDict.py, then fiddling test_userdict.py to match.
You'd think so <wink>. It was subtler in the first I bumped into, translating something like assert d1.has_key(k) == d2.has_key(k) The problem in assert k in d1 == k in d2 is, I think, harder to spot. That is, you may well be in your right might if you want to compare the result of an 'in' test to the result of *another* 'in' test! Even stranger, assert k in d1 != k in d2 succeeds if and only if k is in both d1 and d2 (assuming d1 is a dict and k isn't). I'm going to use that a lot in my code, because it's one less character than typing assert k in d1 and k in d2 Heh heh. *something*-about-this-may-not-be-ideal-ly y'rs - tim

"TP" == Tim Peters <tim.one@home.com> writes:
TP> It's "correct". I've been using Python longer than Guido TP> <wink>, and I'm amazed this is the first time I got bit by TP> this! Here's a hint: Oh, that is twisted! :) Let's throw in some parentheses just to confuse people even more:
"PP" == Paul Prescod <paulp@ActiveState.com> writes:
PP> It looks like dubious hypergeneralization to me! <0.7 wink> PP> Seriously, does this "feature" ever make sense to apply to the PP> in operator? I don't know; I wonder if "normal" people think of `in' as a chainable comparison operator or not. You're not suggesting to change this are you? gotta-leave-something-`in'-there-for-job-security-ly y'rs, -Barry

"Barry A. Warsaw" wrote:
If Tim, Guido, you and I are so completely out of sync with normal people that they will immediately intuit what we had to think hard about, we're in deep doo-doo!
You're not suggesting to change this are you?
I suggest a compile-time warning and then eventually we would make "in" non-chainable. Perhaps it should even have a different precedence than the other comparison operators. Tim's example looks reasonable to me: assert k in d1 == k in d2 And it would never, ever make sense to say: assert k in (d1==k) in d2 So why not interpret it the way that any normal human would: assert (k in d1) == (k in d2) I think that this is a subtle flaw in Python that just took a long time to manifest itself... And what about "1 is None == 2 is None"? If you saw that in a program (last week!) what would you have expected it to evalute to? Precedence levels exist to make code easier to read! -- Take a recipe. Leave a recipe. Python Cookbook! http://www.ActiveState.com/pythoncookbook

[Paul Prescod]
Na, we're not, they are: they're *never* gonna figure it out <wink>.
I suggest a compile-time warning and then eventually we would make "in" non-chainable.
An incompatible language change would, I think, need to go thru the __future__ (however spelled) business.
It *used* to look reasonable to me too <wink>.
And it would never, ever make sense to say:
assert k in (d1==k) in d2
Thin ice, there. __eq__ and __contains__ are both user-definable now, and there is no limit to how perverse ex-APL'ers can get with this stuff.
So why not interpret it the way that any normal human would:
assert (k in d1) == (k in d2)
That sounds best to me, but may be too much a bother. For example, it's not a stretch at all anymore to believe that someone *is* using a in b in c now deliberately for its (a in b) and (b in c) meaning. Perfectly natural if, e.g., you use __contains__ to implement an "is subset of" relation. If we have to keep chaining for "in", then having two distinct levels of chaining operators is bound to harbor its own odd corners. x == y in d I have no idea what that *should* mean, but having gone thru recent related pain I'm very clear now on what it *does* mean.
I think that this is a subtle flaw in Python that just took a long time to manifest itself...
You can thank Digital Creations for that, too. They're keeping Guido so busy that he doesn't have enough time to cloud our minds anymore. Makes you wonder how many other surprises he's been hiding from us <wink>!

Tim Peters wrote:
??? My understanding was that __future__ was a way of sneaking in a cool feature earlier than it would have been possible to deploy it given strict gradual evolution contraints. But disallowing confusing uses of "in" is not a feature and nobody is in a big hurry to see it happen. I wouldn't mind waiting a year or two until everyone has had a chance to clean up their code.
The following grammar would preserve it and outlaw confusing cases: comparison: in_comparison | is_comparison | math_comparison math_comparison: expr (math_comp_op expr)* in_comparison: expr ('in' | 'not' 'in' expr)* is_comparison: expr ('is' | 'is' 'not' expr)* math_comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!=' -- Take a recipe. Leave a recipe. Python Cookbook! http://www.ActiveState.com/pythoncookbook

An incompatible language change would, I think, need to go thru the __future__ (however spelled) business.
[Paul]
That's not what PEP 236 says. __future__ is about *incompatible* language changes, period. "Cool" has nothing to do with it. If you're making something illegal that used to work, that's an incompatible change, and people get at least one release cycle in which it continues to work without change but with warnings. They can also ask for future behavior early via using an explicit future-statement in the module. Although in this case I guess the "future behavior" is just to turn the wng msg into a SyntaxError, in which case the __future__ machinery does seem like overkill.
But disallowing confusing uses of "in" is not a feature
PEP 236 is about incompatible changes, not features. It so happens that the first use (nested scopes) was a new feature that *could* break old code, so was both a new feature and an incompatible change.
I'd rather not nag people at all if this is the only time it's come up in a decade <wink>. We've all got too much to do.
Did you try that grammar? I'm skeptical that it works, since at first glance the comparison production appears to require arbitrary lookahead to determine which xxx_comparison case obtains. But if so, I'm sure it can be repaired. Whether it *should* be is a different matter I'll leave to Guido to Pronounce on.

On Sun, Apr 22, 2001 at 08:04:21PM -0700, Paul Prescod wrote:
The following grammar would preserve it and outlaw confusing cases:
Won't work. Python's parser can't handle it. I also don't think the grammar really matters that much -- it's the compiler that does the actual chaining, it could decide not to chain and force a specific order, if it really wanted to. And generate warnings and all that :) -- Thomas Wouters <thomas@xs4all.net> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!

Tim Peters wrote:
[potential spoilers below] No, thank Jeremy for Compiler: Module(None, Stmt( [ Printnl( [ Compare(Const('a'), [ ('in', Const('abcde')), ('==', Const('abcde')) ] ) ], None ) ] ) ) It still took a look at the ref manual for me to figure it out. It looks like dubious hypergeneralization to me! <0.7 wink> Seriously, does this "feature" ever make sense to apply to the in operator? -- Take a recipe. Leave a recipe. Python Cookbook! http://www.ActiveState.com/pythoncookbook

Yeah, I ran into the same when converting some has_key() tests to using 'in'. I guess it's not very common since nobody in their right minds should want to compare the result of an 'in' test to anything else. The has_key() tests did something like "assert d.has_key(k)==1" and the mindless translation of that is "assert k in d == 1"... Didn't-need-dis-though-ly y'rs, --Guido van Rossum (home page: http://www.python.org/~guido/)

[Tim, 'a' in 'a' == 1, etc] [Guido]
Yeah, I ran into the same when converting some has_key() tests to using 'in'.
Bingo! Same here, but after adding __iter__ and __contains__ to UserDict.py, then fiddling test_userdict.py to match.
You'd think so <wink>. It was subtler in the first I bumped into, translating something like assert d1.has_key(k) == d2.has_key(k) The problem in assert k in d1 == k in d2 is, I think, harder to spot. That is, you may well be in your right might if you want to compare the result of an 'in' test to the result of *another* 'in' test! Even stranger, assert k in d1 != k in d2 succeeds if and only if k is in both d1 and d2 (assuming d1 is a dict and k isn't). I'm going to use that a lot in my code, because it's one less character than typing assert k in d1 and k in d2 Heh heh. *something*-about-this-may-not-be-ideal-ly y'rs - tim

"TP" == Tim Peters <tim.one@home.com> writes:
TP> It's "correct". I've been using Python longer than Guido TP> <wink>, and I'm amazed this is the first time I got bit by TP> this! Here's a hint: Oh, that is twisted! :) Let's throw in some parentheses just to confuse people even more:
"PP" == Paul Prescod <paulp@ActiveState.com> writes:
PP> It looks like dubious hypergeneralization to me! <0.7 wink> PP> Seriously, does this "feature" ever make sense to apply to the PP> in operator? I don't know; I wonder if "normal" people think of `in' as a chainable comparison operator or not. You're not suggesting to change this are you? gotta-leave-something-`in'-there-for-job-security-ly y'rs, -Barry

"Barry A. Warsaw" wrote:
If Tim, Guido, you and I are so completely out of sync with normal people that they will immediately intuit what we had to think hard about, we're in deep doo-doo!
You're not suggesting to change this are you?
I suggest a compile-time warning and then eventually we would make "in" non-chainable. Perhaps it should even have a different precedence than the other comparison operators. Tim's example looks reasonable to me: assert k in d1 == k in d2 And it would never, ever make sense to say: assert k in (d1==k) in d2 So why not interpret it the way that any normal human would: assert (k in d1) == (k in d2) I think that this is a subtle flaw in Python that just took a long time to manifest itself... And what about "1 is None == 2 is None"? If you saw that in a program (last week!) what would you have expected it to evalute to? Precedence levels exist to make code easier to read! -- Take a recipe. Leave a recipe. Python Cookbook! http://www.ActiveState.com/pythoncookbook

[Paul Prescod]
Na, we're not, they are: they're *never* gonna figure it out <wink>.
I suggest a compile-time warning and then eventually we would make "in" non-chainable.
An incompatible language change would, I think, need to go thru the __future__ (however spelled) business.
It *used* to look reasonable to me too <wink>.
And it would never, ever make sense to say:
assert k in (d1==k) in d2
Thin ice, there. __eq__ and __contains__ are both user-definable now, and there is no limit to how perverse ex-APL'ers can get with this stuff.
So why not interpret it the way that any normal human would:
assert (k in d1) == (k in d2)
That sounds best to me, but may be too much a bother. For example, it's not a stretch at all anymore to believe that someone *is* using a in b in c now deliberately for its (a in b) and (b in c) meaning. Perfectly natural if, e.g., you use __contains__ to implement an "is subset of" relation. If we have to keep chaining for "in", then having two distinct levels of chaining operators is bound to harbor its own odd corners. x == y in d I have no idea what that *should* mean, but having gone thru recent related pain I'm very clear now on what it *does* mean.
I think that this is a subtle flaw in Python that just took a long time to manifest itself...
You can thank Digital Creations for that, too. They're keeping Guido so busy that he doesn't have enough time to cloud our minds anymore. Makes you wonder how many other surprises he's been hiding from us <wink>!

Tim Peters wrote:
??? My understanding was that __future__ was a way of sneaking in a cool feature earlier than it would have been possible to deploy it given strict gradual evolution contraints. But disallowing confusing uses of "in" is not a feature and nobody is in a big hurry to see it happen. I wouldn't mind waiting a year or two until everyone has had a chance to clean up their code.
The following grammar would preserve it and outlaw confusing cases: comparison: in_comparison | is_comparison | math_comparison math_comparison: expr (math_comp_op expr)* in_comparison: expr ('in' | 'not' 'in' expr)* is_comparison: expr ('is' | 'is' 'not' expr)* math_comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!=' -- Take a recipe. Leave a recipe. Python Cookbook! http://www.ActiveState.com/pythoncookbook

An incompatible language change would, I think, need to go thru the __future__ (however spelled) business.
[Paul]
That's not what PEP 236 says. __future__ is about *incompatible* language changes, period. "Cool" has nothing to do with it. If you're making something illegal that used to work, that's an incompatible change, and people get at least one release cycle in which it continues to work without change but with warnings. They can also ask for future behavior early via using an explicit future-statement in the module. Although in this case I guess the "future behavior" is just to turn the wng msg into a SyntaxError, in which case the __future__ machinery does seem like overkill.
But disallowing confusing uses of "in" is not a feature
PEP 236 is about incompatible changes, not features. It so happens that the first use (nested scopes) was a new feature that *could* break old code, so was both a new feature and an incompatible change.
I'd rather not nag people at all if this is the only time it's come up in a decade <wink>. We've all got too much to do.
Did you try that grammar? I'm skeptical that it works, since at first glance the comparison production appears to require arbitrary lookahead to determine which xxx_comparison case obtains. But if so, I'm sure it can be repaired. Whether it *should* be is a different matter I'll leave to Guido to Pronounce on.

On Sun, Apr 22, 2001 at 08:04:21PM -0700, Paul Prescod wrote:
The following grammar would preserve it and outlaw confusing cases:
Won't work. Python's parser can't handle it. I also don't think the grammar really matters that much -- it's the compiler that does the actual chaining, it could decide not to chain and force a specific order, if it really wanted to. And generate warnings and all that :) -- Thomas Wouters <thomas@xs4all.net> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
participants (6)
-
barry@digicool.com
-
Gordon McMillan
-
Guido van Rossum
-
Paul Prescod
-
Thomas Wouters
-
Tim Peters