Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #83641

Re: Comparisons and sorting of a numeric class....

Path csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!news.albasani.net!news.stack.nl!newsfeed.xs4all.nl!newsfeed4.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail
Return-Path <andrew3@r3dsolutions.com>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.000
X-Spam-Evidence '*H*': 1.00; '*S*': 0.00; 'broken': 0.04; 'guido': 0.05; 'url:pipermail': 0.05; '"""': 0.07; 'modified': 0.07; 'practice,': 0.07; 'reason,': 0.07; 'revision': 0.07; 'source.': 0.07; 'alternatives': 0.09; 'assumed': 0.09; 'differently.': 0.09; 'except:': 0.09; 'explanation': 0.09; 'extends': 0.09; 'false.': 0.09; 'happen.': 0.09; 'implements': 0.09; 'logic': 0.09; 'oop': 0.09; 'override': 0.09; 'spreading': 0.09; 'try:': 0.09; 'type,': 0.09; 'wrapper': 0.09; '~ethan~': 0.09; 'python': 0.11; 'def': 0.12; 'creates': 0.14; 'thread': 0.14; '(true,': 0.16; '*do': 0.16; 'arbitrarily': 0.16; 'bool': 0.16; 'boolean': 0.16; 'c++)': 0.16; 'c/c++': 0.16; 'charles': 0.16; 'close:': 0.16; 'comparison.': 0.16; 'contract.': 0.16; 'correctness': 0.16; 'crude': 0.16; 'eliminating': 0.16; 'exist.': 0.16; 'false)': 0.16; "guido's": 0.16; 'happily': 0.16; 'instances,': 0.16; 'instantiated': 0.16; 'iterable': 0.16; 'iterables': 0.16; 'length,': 0.16; 'less,': 0.16; 'mainstream': 0.16; 'merely': 0.16; 'objection': 0.16; 'objects.': 0.16; 'operation,': 0.16; 'python;': 0.16; 'saying.': 0.16; 'semantics': 0.16; 'singleton': 0.16; 'subclass': 0.16; 'subclassing': 0.16; 'tuple': 0.16; 'tuple.': 0.16; 'exception': 0.16; 'prevent': 0.16; 'ignore': 0.16; 'language': 0.16; 'wrote:': 0.18; '(not': 0.18; 'do.': 0.18; 'trying': 0.19; 'written': 0.21; '(the': 0.22; '>>>': 0.22; 'memory': 0.22; 'example': 0.22; 'saying': 0.22; 'creating': 0.23; 'header:User-Agent:1': 0.23; '&gt;&gt;&gt;': 0.24; 'controlling': 0.24; 'enhanced': 0.24; 'oriented': 0.24; 'passes': 0.24; 'proxy': 0.24; 'why.': 0.24; 'initial': 0.24; 'non': 0.24; 'versions': 0.24; "haven't": 0.24; "i've": 0.25; 'class.': 0.26; 'define': 0.26; 'equivalent': 0.26; 'holds': 0.26; 'mention': 0.26; 'nearly': 0.26; 'possibly': 0.26; 'second': 0.26; 'pass': 0.26; 'least': 0.26; 'skip:_ 20': 0.27; 'values': 0.27; 'header:In- Reply-To:1': 0.27; 'testing': 0.29; 'generally': 0.29; 'wonder': 0.29; "doesn't": 0.30; 'andrew': 0.30; 'compared': 0.30; 'converting': 0.30; 'newer': 0.30; 'restrict': 0.30; "i'm": 0.30; 'code': 0.31; '(perhaps': 0.31; 'apparently': 0.31; 'comparison': 0.31; 'operators': 0.31; 'proposing': 0.31; 'restricted': 0.31; 'tuples': 0.31; 'containing': 0.69; 'limit': 0.70; 'quality': 0.72; 'foreign': 0.74; 'acts': 0.74; 'goal': 0.75; 'objectives': 0.83; "'make'": 0.84; "'true'": 0.84; 'ethan': 0.84; 'furman': 0.84; 'huh?': 0.84; 'preventing': 0.84; 'technically': 0.84; 'url :python-dev': 0.84; 'canonical': 0.91; 'defeat': 0.91; 'do:': 0.91; 'reasoning': 0.91; 'received:173.201': 0.91; 'received:173.201.192': 0.91; 'write:': 0.91; 'besides,': 0.93; 'enhancement': 0.95
Date Mon, 12 Jan 2015 14:27:48 -0800
From Andrew Robinson <andrew3@r3dsolutions.com>
User-Agent Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.1.0
MIME-Version 1.0
To python-list@python.org
Subject Re: Comparisons and sorting of a numeric class....
References <54ABB88A.7070504@r3dsolutions.com> <54ABC52A.1050507@davea.name> <54ABE383.3020801@r3dsolutions.com> <CAPTjJmpktyHfghEr+cjPrhso7JgB4VfS4=5Gdi95gT0aFbSYGA@mail.gmail.com> <54AC97D9.4010504@r3dsolutions.com> <CAPTjJmooTK_+HVoeyeSrqBHN1=YjRYQ2kfDyQtL9JoA9SbTqsQ@mail.gmail.com> <54ACAA04.60801@r3dsolutions.com> <54ADC99F.3020405@stoneleaf.us>
In-Reply-To <54ADC99F.3020405@stoneleaf.us>
Content-Type multipart/alternative; boundary="------------030508070805080204060809"
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.15
Precedence list
List-Id General discussion list for the Python programming language <python-list.python.org>
List-Unsubscribe <https://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive <http://mail.python.org/pipermail/python-list/>
List-Post <mailto:python-list@python.org>
List-Help <mailto:python-list-request@python.org?subject=help>
List-Subscribe <https://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe>
Newsgroups comp.lang.python
Message-ID <mailman.17644.1421101760.18130.python-list@python.org> (permalink)
Lines 410
NNTP-Posting-Host 2001:888:2000:d::a6
X-Trace 1421101760 news.xs4all.nl 2900 [2001:888:2000:d::a6]:40988
X-Complaints-To abuse@xs4all.nl
Xref csiph.com comp.lang.python:83641

Show key headers only | View raw


[Multipart message — attachments visible in raw view] - view raw

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???

Back to comp.lang.python | Previous | Next | Find similar | Unroll thread


Thread

Re: Comparisons and sorting of a numeric class.... Andrew Robinson <andrew3@r3dsolutions.com> - 2015-01-12 14:27 -0800

csiph-web