Comparisons and sorting of a numeric class....

Andrew Robinson andrew3 at r3dsolutions.com
Mon Jan 12 17:27:48 EST 2015


On 01/07/2015 04:04 PM, Ethan Furman wrote:
> On 01/06/2015 07:37 PM, Andrew Robinson wrote:
>
>> Explain; How does mere subclassing of bool break the contract that bool has?
>> eg: What method or data would the superclass have that my subclass would not?
> bool's contract is that there are only two values (True and False) and only one instance each of those two values (True
> and False).  If bool were subclassable, new values could be added with either completely different values (PartTrue) or
> with more of the same value (True, ReallyTrue, AbsolutelyTrue) -- hence, broken contract.
>
> --
> ~Ethan~
>
>
>
Huh? I'm not adding any values when I merely subclass bool ; and even if 
the subclass could be instantiated -- that's doesn't mean a new value or 
instance of the base class (bool) must exist.  For I could happily work 
with a new subclass that contains no new data, but only an already 
_existing instance_ of 'True' or 'False_'_ as its value source.   That 
means there is no new value...  but at most (and even that could be 
worked around) a new instance of a subclass containing an existing 
instance of it's base class.

Note:  Guido only mentioned that he didn't want multiple instances of 
the base class bool -- But that's not technically the same as objecting 
to a subclass having an instance which CONTAINS an original bool 
instance and not a new one.

There are other ways Guido could have modified the Python language to 
prevent creation of new values without preventing the creation of a 
subclass --  if that's what he was really after....    So -- no -- I 
disagree with you.

Subclassing is allowed in many other OOP languages (not just C++) when 
working with singletons, and dualtons, n-tons... and the very PURPOSE of 
those objects is to prevent multiple instances, or spreading of 
control.  BUT -- Most object oriented languages I know of -- allow as 
standard practice, subclassing of n-tons -- while (often) simultaneously 
controlling or even eliminating the number of instances a subclass may 
have / and or the values it may take.  eg: depending on how flexible the 
type/class definition of a language is -- languages handle sub-classing 
of singletons differently.

Besides, a contract for a class can only be assumed to be valid for code 
designed for that specific class -- not code made for a subclass;  The 
contract for bool simply says nothing about programs designed for any 
other classes that bool is found inside of -- either as a subclass or a 
subelement;  eg:  I can still put bool inside another object with 
different methods: eg: I just write: (False,) as proof -- so Guido 
couldn't possibly have been trying to limit the methods which can 
operate on bool or the number of links to bool.

So I don't understand why Guido cared to restrict subclassing of bool -- 
and what the contract you mention has to do with it --  eg: what was his 
actual goal ?  Was it memory conservation, or compatability of built-in 
return types -- or what ?  There is no written 'contract' saying exactly 
what Guido's design objectives were in detail and more importantly 
'WHY';  but Guido only said that subclassing instances allowed a 'back 
door' (not that subclassiing itself was bad, just that it allowed some 
side effect...) to whatever Guido really didn't want to happen.

Python generally allows subclassing of singleton instances; so that 
makes 'bool' is an arbitrary exception to the general rule which Guido 
decided  to make... and he did so without any very clear explanation as 
to why.  eg: he cited what C/C++ *must *do as part of his reasoning -- 
but C/C++ can apparently do something that Guido  thought it couldn't 
(Guido was flat wrong).... and for that reason, I really wonder if 
Guido's decision was some kind of spur of the moment erroneous epiphany 
-- bolstered by the fact that he said "I realized last night..." like 
something he had never thought of before, or thought through carefully....

https://mail.python.org/pipermail/python-dev/2002-March/020822.html


And worse, Guido's problem even apparently extends to making 'duck 
types' which other writers in this thread have been proposing I do. eg: 
They, too, are going against canonical Guido's epiphany night...

Of course, you can define your own subclass of int similar to the bool
class I show in the PEP, and you can give it any semantics you want --
but that_would also defeat the purpose of having a standard bool_.

Not to mention, that Charles Bool's two initial values True and False 
are NOT the only ones used in computer engineering and science; for 
boolean logic only became useful at a time when engineers and 
mathematicians realized that at least a third type, AKA: 'Don't care' -- 
was necessary for doing correctness testing of logic in a tractable 
way.   So -- Guido arbitrarily chose to make bool based on a historical 
curiosity that never has been mainstream in logic analysis.  eg: He 
based it on a beta quality revision of boolean theory....    Look at any 
logic design and testing package -- such as silos Three, or verilog, or 
VHDL, UHDL, etc.  and all of them support tri-state logic with at least 
one 'don't care' state for boolean logic.

But setting that all aside....

I've already said that I don't actually need an instance of the 
subclass... but you (and others) repeatedly ignore what I'm saying. So, 
let me try to give a crude example of alternative routes an OOP language 
like Python COULD take....

Consider -- There are generic alternatives to class instances in many 
OOP languages; eg: making proxy or wrapper objects.

These are not foreign ideas in Python; though it implements them too 
crudely for my use or else there is a trick to the Python versions I 
haven't figured out yet -- but none the less, Python already creates 
proxy objects ( CF: super() ) ; so it's not a foreign idea.

For my purposes;  At minimum I need a wrapper and proxy object (both) 
which can be passed in lieu of a an actual bool or subclass of bool; eg: 
it holds an actual False or True object (the super), and can pass the 
test whenever a user attempts an 'isinstance( mybinding, bool )' for 
type checking; but fails whenever it is examined by  'is' True or 'is' 
False;  Python can almost do what I want -- but not quite -- because the 
existing proxys are not quite as transparent as they need to be; but 
it's very close:

 >>> a=super(True,int)
 >>> isinstance( a.__self__, bool )
True
 >>> a is bool
False

So -- since it can't be done, the next best thing is some kind of 
wrapper object acting as a proxy;
As a first attempt -- I'll override the comparison operators in a 
generic way to 'make' a more generic proxy:

def _op(op,other): # Call an operation, insuring iterable is second arg.
         try: other[0]
         except: return op((other,))
         return op(other)

class ETuple(tuple):
     """
     Enhanced Tuple.
     A tuple which does rich comparisons even when the item being
     compared against is not an iterable by converting non iterables to
     tuples of length, exactly one.
     """
     def __new__(cls, data):return super(ETuple,cls).__new__(cls,data)
     def __eq__(self,other):return _op(super(ETuple,self).__eq__,other)
     def __ne__(self,other):return _op(super(ETuple,self).__ne__,other)
     def __lt__(self,other):return _op(super(ETuple,self).__lt__,other)
     def __le__(self,other):return _op(super(ETuple,self).__le__,other)
     def __gt__(self,other):return _op(super(ETuple,self).__gt__,other)
     def __ge__(self,other):return _op(super(ETuple,self).__ge__,other)
     def __cmp__(self,other):return _op(super(ETuple,self).__cmp__,other)
     def __nonzero__(self,other):return 
_op(super(ETuple,self).__cmp__,other)


Now, I can do:
 >>> (False,) == False
True
and:
 >>> (False,) is False
False
 >>> PartFalse = (False,)
 >>> PartFalse == False
True
 >>> PartFalse == PartTrue
False

and, it's clear that I am not creating a new instance of 'bool;' -- for 
PartFalse is not a new instance of bool, it is (under rich comparison), 
exactly equivalent to a bool.  eg: a duck type under rich comparison.
Therefore, RBool acts exactly like a bool for traditional code in a 
nearly transparent way (proxy idea) -- but still allows detection of the 
wrapper by 'is' so that newer code can take advantage of a refined 
definition of falseness...

So,  If Etuple was a subclass of 'bool', instead of just tuple -- and 
was restricted to wrap ONLY an existing bool (perhaps as an enhancement 
to the class definition...) -- it would achieve all my design goals;  so 
your objection that it is a new value would simply be false.  It would 
merely be a wrapper of an existing bool that passes the type check 
isinstance( bool, ETuple(False) ) --> True .

Why was it so important to Guido to make this impossible???
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20150112/741e1ed7/attachment.html>


More information about the Python-list mailing list