Comparisons and sorting of a numeric class....

Andrew Robinson andrew3 at r3dsolutions.com
Fri Jan 23 12:46:03 CET 2015


On 01/15/2015 09:05 AM, Ian Kelly wrote:
> On Thu, Jan 15, 2015 at 12:23 AM, Andrew Robinson
> <andrew3 at r3dsolutions.com> wrote:
>> Can you name any other language that *does* allow subclassing of
>> booleans or creation of new boolean values?
>>
>> Yes. Several off the top of my head -- and I have mentioned these before.
>> They generally come with the extra subclasses pre-created and the user
>> doesn't get to create the classes, but only use them; none the less -- they
>> have more than two values with which to do logic equations with.
>>
>> VHDL, Verilog, HDL, Silos III, and there are IEEE variants also.
>> C/C++ historically allowed you to do it with instances included, although I
>> am not sure it still does.
> Sorry, let me rehprase my question. Of course there will be
> special-purpose languages that allow you to do interesting things with
> the logic values and operators. Can you name any other
> *general-purpose* language that allows subclassing of booleans or
> creation of new boolean values? If not, it seems rather unfair to
> single out Python and marvel that this isn't allowed when it's
> actually quite normal to disallow it. Unless you care to provide an
> example, I am fairly sure your claim of C/C++ is wrong. The bool type
> in C++ is a primitive type, none of which can be inherited from. C
> doesn't even have a bool type; at most you have macros for true and
> false to 1 and 0, so the "booleans" there are just ordinary integers.
Ian,
I agree with you mostly; there is good reason to pick on other 
languages, too, with respect to what a bool is.

Although, I have to laugh -- Verilog can syntheze a CPU -- implement 
memory -- and then load a program and run python on the virtual 
machine.   When the pentium was first developed, I watched as Intel 
actually booted up MS-DOS under using Xilinx chips to run the verilog 
program's output they could physically run anything a pentium processor 
could run.  That's *IS* what I consider "general purpose".

But you're sort of confounding my need for type information in my new 
class as a way to advertise compatability with bool, with subclassing -- 
which is only one way that I was exploring to get the 'type' name 
attached to the new object;  That's a mistake that D'Aprano seems to be 
repetitively making as well.
But please note: Type checking for 'bool' is only needed for 
legacy/compatability reasons -- but new code can use any type; so 
subtyping is not strictly necessary if there is another way to get the 
'bool' type attached to my return object for advertising purposes; for 
what I am interested in is an object who presents as bool for legacy 
code, but new code can convert it to anything at all..

C++ *DOES* allow the necessary kind of type checking and subclassing for 
what I need to do in spite of not having a subclass mechanism built into 
the language for base types; eg: C++ allows a semantic subclass to be 
constructed which can be typecast to a bool for compatibility, but 
otherwise presents extra data and the type the enhanced object reports 
is irrelevant.  As I've mentioned before, people can do object oriented 
programming in C,  So, to satisfy your curiosity -- I'll show you a 
mixed C/C++ example, where I make a semantic subclass that has five 
values AllFalse, PartFalse, Uncertain, PartTrue, True ; and these five 
values will have a typeid() of bool and be 100% compatible with legacy 
C++ bool; but upon request, they these 'bool' types will re-cast into a 
semantic subtype that provides additional certainty data.

See the program at end of e-mail.  It compiles with gcc 4.8.2 with no 
warnings;  g++ filename.cc ; ./a.out

But let me explain a bit more why I'm picking on Python:  For even if we 
set the electronic engineering concerns aside that I've raised (and they 
are valid, as OOP is supposed to model reality, not reality be bent to 
match OOP) -- People's facile explanations about why Python's version of 
bool is the way it is -- still bothers me here in the python mail list 
-- because people seem to have a very wrong idea about bool's nature as 
a dualton being somehow justified solely by the fact that there are only 
two values in Boolean logic; For, singletons style programming is not 
justified by the number of values an object has in reality -- And I know 
Charles bool didn't use singletons in his algebra,  -- just read his 
work and you'll see he never mentions them or describes them, but he 
does actually use dozens of *instances* of the True and False objects he 
was talking about -- for the obvious reason that he would have needed 
special mirrors, dichroic or partially silvered, to be even able to 
attempt to make one instance of True written on paper show up in 
multiple places; And that's silly to do when there's no compelling 
reason to do it.

Yet -- people here seem to want to insist that the bool type with only 
two *instances* is some kind of pure re-creation of what Charles Bool 
did -- when clearly it isn't.  It's a amalgamation of enhancements such 
as binary words instead of just True/False and many other things 
(operators that work on words rather than single bits.).  So -- I don't 
see that Python's implementation of Bool is justified by either a purist 
appeal to Charles bool, or by ignoring pragmatic concerns that have been 
attached to Bool's work for years by Electrical Engineers in order to 
make it more useful for *practical* computer problems.  Yet these two 
things are what this python list has sort of harped on.

That brings me to your point about other languages;  I think following 
other languages restrictions arbitrarily is potentially a lemmings 
approach, eg: just because 'everyone' is doing it statistically does not 
mean that it is good to do it that way; If many languages do something, 
there is excellent cause to examine and look for reasons 'why' they do 
that (and I'd love to hear your opinions) but Python has a different set 
of constraints as an interpreter, as opposed to a compiler, and many 
other differences which cause unintended side effects when mimicking 
other programming languages. It's the unintended side effects and 
surprises when a hasty decision is made that's the issue here.

Where python is different from other languages regarding bool -- and 
deserves a little extra picking on, is that Guido has imposed four 
constraints *simultaneously* to bool which together cause a conflict 
that I don't think (offhand) I've ever encountered in another language;  
Definitely not in C/C++!

The four things are: 1 -- he cut off subtyping and created no alternate 
method of doing type checking of duck-types,  2 -- he does not allow 
multiple instances,  3 -- he himself did not implement bool using the 
standard alternative methodology to subclassing -- eg: as a composite 
structure with delegation. 4.  and he has made bool into the default 
return type for base type comparison operators; which means that general 
programmers expect a bool for base types and may check for it, even if 
Python's built in functions do not.

If any one of these four things had not been done, I would not have 
reason to complain about bool in Python; because there would be a way 
for me to easily work with people expecting a bool as a return type from 
comparison operators, using standard OOP techniques and a little 
creativity to make something perfectly compatible; rather than having to 
dig through manuals endlessly with conflicting notions, pep's, and 
subtleties that make for an extremely steep learning curve and lots of 
time spent making only slight progress when there's not much *reasoning* 
behind what Guido did which is consistent and useable as a guideline...

As far a subtyping goes; The very fact that Guido used subtyping to 
create bool in the first place (subtype of int), precludes any real 
claim that bool should not itself be subclassable just because bools 
only have two values;  I mean, seriously --  Guido's 'strict' Bool is 
already an impure form of OOP that is borderline hypocrisy, as it can 
'+' to 2 or 3... and many other things;  and worse I've just come across 
a couple of papers which suggest that Guido doesn't like subclassing 
when Composite object structures could be used instead to replace the 
subclass 'is' relationship with a 'has a' relationship.  So -- if that's 
the case, why isn't bool a composite to begin with ?  eg: Guido's 
programming guides must be read with a caveat 'do what Guido says and 
not what Guido does' ?!

Now to your last point -- I need to point out that  C++ does not have 
all four restrictions I've mentioned so it doesn't have the problem 
Python does;  In C++, there are instances of bool, and therefore I can 
easily encode extra information in a bool object without changing the 
object itself.

Here's a skeleton example, where I only implement one operator '<' on 
the semantic subclass, but the example shows the principle of how to 
extend the bool type via typecasting to bool.  There are better ways of 
doing this, and there are some problems with how I implemented esp. as 
many use cases are not properly covered -- but it serves to show that 
C/C++ CAN encode new subtypes (semantic subtypes only not C++ subtypes) 
while using only the base type itself to transmit data in a perfectly 
backwards compatible way.  In Python, however, it's pretty close to 
hopeless...

#include <iostream>
#include <typeinfo>
using namespace std;

// Create a new super-bool type which is semantically a subtype of bool,
// But have it masquerade as a bool for compatability, unless new code
// explicity typecasts it and access its subtype members.

struct _SBool {
     bool basebool;
     int certainty;
};

class SBool: public _SBool {
public:
     SBool( const bool& );
     bool operator < (const SBool &);
};

// Create all 4 of the statistical uncertainty values as penta-ton.
const _SBool bools[5] = {{false,0},{false,1},{false,2},{false,3},{true,4}};

// Create 4 global alias bool names having full compatability with bool
// for legacy code, but useable in mixed or advanced compares.

const bool & AllFalse  = bools[0].basebool; // uncertainty 0
const bool & PartFalse = bools[1].basebool; // uncertainty 1
const bool & Uncertain = bools[2].basebool; // uncertainty 2
const bool & PartTrue  = bools[3].basebool; // uncertainty 3
const bool & True      = bools[4].basebool; // uncertainty 4

// Create the typecast method.
SBool::SBool( const bool &b ) {
     const void* that = &b;
     if ((that >= bools) && (that < bools+5)) *this=*(const SBool*)that;
     else *this=*(const SBool*)(const void*) &(b?True:AllFalse);

bool SBool::operator < (const SBool &other ) {
     return this->certainty < other.certainty;
}

// ------------------------------------  Test harness.
int main(void) {
     cout << "type match=" <<  (typeid(bool) == typeid(AllFalse)) << endl;
     cout << "testing as bool "       << AllFalse << PartFalse << 
Uncertain << PartTrue << True << endl;
     cout << "testing as SBool "      << SBool(PartFalse).certainty << 
endl;
     cout << "testing up-cast false " << SBool(false).certainty << endl;
     cout << "testing up-cast true "  << SBool(true).certainty << endl;
     cout << "testing advanced compare (should be true)" << 
(SBool(AllFalse) < PartFalse) << endl;
     cout << "testing legacy compare (should be false) " << (AllFalse < 
PartFalse) << endl;
     return 0;
}

//------------------------------------ End of program, Test output 
follows -------------------

type match=1
testing as bool 00001
testing as SBool 1
testing up-cast false 0
testing up-cast true 4
testing advanced compare (should be true)1
testing legacy compare (should be false) 0bash-4.2$
















More information about the Python-list mailing list