Re: [Python-ideas] [Python-ideos] Dedicated overloadable boolean operators
Sorry, the order was incorrect in that last message. It should be: When x and y is written, if x has __booland__, then x.__booland__(y) is returned. If not, then return x if x==False else if x==True, then if y has y.__rbooland__(x), that is returned. If not, then return y. On Monday, November 30, 2015 at 10:11:03 AM UTC-6, Henry Schreiner wrote:
It seems to me there are two ideas being discussed. One is adding 2 new operators, something like && and ||, and providing them for some sort of "element wise" or other boolean context, and giving them a better order of evaluations than bitwise ops. This would have the advantage of being usable on the built in python lists/tuples if needed, but otherwise doesn't seem to solve all the issues above, including expressions like -1 < mat < 1, which work for python variables but not for things like Numpy arrays. (for example, selecting values from an array works like this: mat[(-1<mat) & (mat<1)] but not like this: mat[-1 < mat < 1] or this: mat[-1<mat & mat<1] ).
The common "general purpose infix notation" pops up here, of course, but I'd consider it a variant of the first idea.
The other idea is that overloads could be added to the existing and and or operators. This, I believe, would solve all the main problems, and would not add more to the language for a newcomer to learn. (In fact, most people could forget about the current bitwise and and or, since that's not what most people need, at least those using databases and Numpy). The downside is that the current and and or operators are short-circuiting, and adding a way to overload a short-circuiting operator is tricky/ugly/expensive (though the last one might not be that bad anymore). But, as I think Andrew was mentioning, what about a mixed solution? One that provides a non-short-circuiting overload, but the original short-circuiting behavior is default? It would look like this:
Two new magic methods would be added, for now called __booland__ and __boolor__, along with __rbooland__ and __rboolor__.
Evaluation would work like this, using and for an example: When x and y is written, if x has __booland__, then y.__booland__(y) is called. If it does not, then if y exists and has y.__rbooland__(x), that is called. If neither, then x and y is performed in a normal, short circuiting manner, calling bool(x) then calling bool(y) only if x == True. (The second line here might be the hard part due to the way short circuiting works)
This would allow object that want custom and/or behavior to implement these magic functions. They would lose (explicit) short-circuiting, but they would gain custom behavior. Most of these special objects do not need or expect the short circuit behavior (Only if an array was all True or False would it even make sense in numpy , and this would allow expressions like -1 < mat < 1 to work as expected in Python. This would be easy to teach to newcomers, too, since only objects that have a definite True/False should short circuit, others have the special methods. The old behavior could be forced on overriding objects by wrapping them in bool().
Would something like that be possible and better than PEP 335?
PS: Either type of solution would also be useful for the Plumbum library, by the way, as it would be useful to add and-ing and or-ing to pipelines, but the bitwise operators have a different meaning for Plumbum. Due to the lazy evaluation of Plumbum, even the above solution (or any solution) would still allow short-circuiting in the pipeline.
On Mon, Nov 30, 2015 at 8:22 AM, Henry Schreiner < henryschreineriii@gmail.com> wrote:
Sorry, the order was incorrect in that last message. It should be:
When x and y is written, if x has __booland__, then x.__booland__(y) is returned. If not, then return x if x==False else if x==True, then if y has y.__rbooland__(x), that is returned. If not, then return y
This proposal isn't significantly different from PEP 335. In PEP 335, first you ask the left operand whether to overload 'and' or not (by calling its __and1__); if it says yes, you evaluate the second arg and ask the first to evaluate it. In your proposal, the first question is answered by inspecting whether x defines __booland__. I don't think this makes much practical difference. The second part of your proposal is just a renaming of __and2__/__rand2__ to __booland__/__rbooland__. I'm not sure I like this much; the return type of these methods is almost never going to be an actual bool, so the 'bool' in the name is somewhat misleading. (The names chosen in PEP 335 are intentionally free of semantic hints, since the intuition of someone who encounters these for the first time isn't likely to be useful.) -- --Guido van Rossum (python.org/~guido)
I didn't realize the similarity of the proposals. I do think that testing for existence is better than running a method (that might not exist), at least from a high level perspective. So PEP 335 might be dusted off again and run through benchmarks? There seems to be at least a test implementation for Python 2.3, are there benchmarks documented somewhere? It sound like the version that adds new byte codes instead of an additional byte code per op was never included. I do like the cleanliness of not adding extra operators with nearly identical meanings. On Monday, November 30, 2015 at 11:24:12 AM UTC-6, Guido van Rossum wrote:
On Mon, Nov 30, 2015 at 8:22 AM, Henry Schreiner <henrysch...@gmail.com <javascript:>> wrote:
Sorry, the order was incorrect in that last message. It should be:
When x and y is written, if x has __booland__, then x.__booland__(y) is returned. If not, then return x if x==False else if x==True, then if y has y.__rbooland__(x), that is returned. If not, then return y
This proposal isn't significantly different from PEP 335. In PEP 335, first you ask the left operand whether to overload 'and' or not (by calling its __and1__); if it says yes, you evaluate the second arg and ask the first to evaluate it. In your proposal, the first question is answered by inspecting whether x defines __booland__. I don't think this makes much practical difference. The second part of your proposal is just a renaming of __and2__/__rand2__ to __booland__/__rbooland__. I'm not sure I like this much; the return type of these methods is almost never going to be an actual bool, so the 'bool' in the name is somewhat misleading. (The names chosen in PEP 335 are intentionally free of semantic hints, since the intuition of someone who encounters these for the first time isn't likely to be useful.)
-- --Guido van Rossum (python.org/~guido)
Well, there is still the issue of whether numpy would adopt PEP 335 even if it was implemented. I'm still waiting for a response to my message questioning how common `bool_value and/or numpy_array` really is. Also, there may still be a significant difference between PEP 335 and your proposal -- IIUC in your proposal if the value of the first operand requires the second operand to be evaluated (e.g. `True or y`) then in your proposal if y defined the 'r' special method it will be used; I don't think PEP 335 does that. I like your version better. On Mon, Nov 30, 2015 at 10:08 AM, Henry Schreiner < henryschreineriii@gmail.com> wrote:
I didn't realize the similarity of the proposals. I do think that testing for existence is better than running a method (that might not exist), at least from a high level perspective.
So PEP 335 might be dusted off again and run through benchmarks? There seems to be at least a test implementation for Python 2.3, are there benchmarks documented somewhere? It sound like the version that adds new byte codes instead of an additional byte code per op was never included.
I do like the cleanliness of not adding extra operators with nearly identical meanings.
On Monday, November 30, 2015 at 11:24:12 AM UTC-6, Guido van Rossum wrote:
On Mon, Nov 30, 2015 at 8:22 AM, Henry Schreiner <henrysch...@gmail.com> wrote:
Sorry, the order was incorrect in that last message. It should be:
When x and y is written, if x has __booland__, then x.__booland__(y) is returned. If not, then return x if x==False else if x==True, then if y has y.__rbooland__(x), that is returned. If not, then return y
This proposal isn't significantly different from PEP 335. In PEP 335, first you ask the left operand whether to overload 'and' or not (by calling its __and1__); if it says yes, you evaluate the second arg and ask the first to evaluate it. In your proposal, the first question is answered by inspecting whether x defines __booland__. I don't think this makes much practical difference. The second part of your proposal is just a renaming of __and2__/__rand2__ to __booland__/__rbooland__. I'm not sure I like this much; the return type of these methods is almost never going to be an actual bool, so the 'bool' in the name is somewhat misleading. (The names chosen in PEP 335 are intentionally free of semantic hints, since the intuition of someone who encounters these for the first time isn't likely to be useful.)
-- --Guido van Rossum (python.org/~guido)
-- --Guido van Rossum (python.org/~guido)
I find the need to use np.logical_or quite often in NumPy. I'm sure the NumPy community would much prefer to be able to write: new = arr[arr<10 or arr>100] Instead of the current: new = arr[np.logical_or(arr<10, arr>100)] Likewise for np.logical_and(). On Mon, Nov 30, 2015 at 10:23 AM, Guido van Rossum <guido@python.org> wrote:
Well, there is still the issue of whether numpy would adopt PEP 335 even if it was implemented. I'm still waiting for a response to my message questioning how common `bool_value and/or numpy_array` really is.
Also, there may still be a significant difference between PEP 335 and your proposal -- IIUC in your proposal if the value of the first operand requires the second operand to be evaluated (e.g. `True or y`) then in your proposal if y defined the 'r' special method it will be used; I don't think PEP 335 does that. I like your version better.
On Mon, Nov 30, 2015 at 10:08 AM, Henry Schreiner < henryschreineriii@gmail.com> wrote:
I didn't realize the similarity of the proposals. I do think that testing for existence is better than running a method (that might not exist), at least from a high level perspective.
So PEP 335 might be dusted off again and run through benchmarks? There seems to be at least a test implementation for Python 2.3, are there benchmarks documented somewhere? It sound like the version that adds new byte codes instead of an additional byte code per op was never included.
I do like the cleanliness of not adding extra operators with nearly identical meanings.
On Monday, November 30, 2015 at 11:24:12 AM UTC-6, Guido van Rossum wrote:
On Mon, Nov 30, 2015 at 8:22 AM, Henry Schreiner <henrysch...@gmail.com> wrote:
Sorry, the order was incorrect in that last message. It should be:
When x and y is written, if x has __booland__, then x.__booland__(y) is returned. If not, then return x if x==False else if x==True, then if y has y.__rbooland__(x), that is returned. If not, then return y
This proposal isn't significantly different from PEP 335. In PEP 335, first you ask the left operand whether to overload 'and' or not (by calling its __and1__); if it says yes, you evaluate the second arg and ask the first to evaluate it. In your proposal, the first question is answered by inspecting whether x defines __booland__. I don't think this makes much practical difference. The second part of your proposal is just a renaming of __and2__/__rand2__ to __booland__/__rbooland__. I'm not sure I like this much; the return type of these methods is almost never going to be an actual bool, so the 'bool' in the name is somewhat misleading. (The names chosen in PEP 335 are intentionally free of semantic hints, since the intuition of someone who encounters these for the first time isn't likely to be useful.)
-- --Guido van Rossum (python.org/~guido)
-- --Guido van Rossum (python.org/~guido)
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th.
participants (3)
-
David Mertz -
Guido van Rossum -
Henry Schreiner