Comparisons and sorting of a numeric class....

Steven D'Aprano steve at pearwood.info
Thu Jan 15 03:41:47 EST 2015


On Wed, 14 Jan 2015 23:23:54 -0800, Andrew Robinson wrote:

[...]
> A subclass is generally backward compatible in any event -- as it is
> built upon a class, so that one can almost always revert to the base
> class's meaning when desired -- but subclassing allows extended meanings
> to be carried.  eg: A subclass of bool is a bool -- but it can be MORE
> than a bool in many ways.

You don't have to explain the benefits of subclassing here.

I'm still trying to understand why you think you *need* to use a bool 
subclass. I can think of multiple alternatives:

- don't use True and False at all, create your own multi-valued 
  truth values ReallyTrue, MaybeTrue, SittingOnTheFence, ProbablyFalse,
  CertainlyFalse (or whatever names you choose to give them);

- use delegation to proxy True and False;

- write a class to handle the PossiblyTrue and PossiblyFalse cases,
  and use True and False for the True and False cases;

There may be other alternatives, but what problem are you solving that 
you think 

    class MyBool(bool): ...

is the only solution?



> One example: It can also be a union.

I don't understand what you think this means. I know what *I* think it 
means, but "subclass = union" doesn't make sense to me, so wonder what 
you think it means.

> So when Guido chose to cut off
> subclassing -- his decision had a wider impact than just the one he
> mentioned; eg: extra *instances* of True and False.... as if he were
> trying to save memory or something.

*shrug* well maybe he was.


> The reason Guido's action puzzles me is twofold -- first it has been
> standard industry practice to subclass singleton  (or n-ton) objects to
> expand their meaning in new contexts, 

I dispute that. I *strongly* dispute that.

Industry practice, in my experience, is that there is one and only one 
case where you can subclass singleton classes: when you have a factory 
which chooses at runtime which subclass to instantiate, after which you 
can no longer instantiate any of the other subclasses.

E.g. given an *abstract* class Maze, and three *concrete* subclasses 
Labyrinth, OrdinaryMaze, and EnchantedMaze, you can have a factory 
function, or method on Maze:

class Maze:
    _the_instance = None
    @classmethod
    def create(cls, variant='ordinary'):
        if cls._the_instance is None:
            # Create the Maze singleton
            if variant == 'ordinary':
                cls._the_instance = OrdinaryMaze()
            elif variant == 'labyrinth':
                cls._the_instance = Labyrinth()
            elif variant == 'enchanted':
                cls._the_instance = EnchantedMaze()
        return _the_instance


(This is just a sketch of a solution, because the caller can bypass the 
factory and just call the subclasses directly. In Java it is possible to 
write this in such a way that the caller cannot easily do so.)


Why are we limited to a single Maze? Making Maze a singleton in the first 
place was a bad idea. The singleton design pattern is *highly* over-used 
and abused. But that is another story. Let's just assume that the 
designer has good reason to insist that there be only one Maze, perhaps 
it uses some resource which truly is limited to there being one only. If 
that is the case, then allowing the caller to break that invariant by 
subclassing will just lead to horrible bugs. By using a factory and 
controlling access to the subclasses, Maze can keep the singleton 
invariant and allow subclasses.

This is not relevant to bool, since True and False are already 
instantiated.


[...]
> In general -- it's not the goal of subclassing to create more instances
> of the base types

That might not be the goal, but it is the effect. When you instantiate 
the subclass, by definition the instances are also instances of the base 
classes.

> -- but rather to refine meaning in a way that can be
> automatically reverted to the base class value (when appropriate) and to
> signal to users that the type can be passed to functions that require a
> bool because of backward compatibility.

And I am wondering what you think you can extend bools to perform that is 
completely backwards compatible to code that requires bools?

I don't think you can. I think you are engaged on a fool's errand, trying 
to do something impossible *even if subclassing bool were allowed*. But I 
could be wrong. I just don't think you can possibly write code which is 
backwards-compatible with code that expects bools while still extending 
it. People are so prone to write:

    if flag is True: ... 
    if flag is False: ...


(which is naughty of them, but what are you going to do?)




[...]
>> 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.

C doesn't have instances because it doesn't have objects. I'm not 
certain, but I don't think the other languages you refer to are object-
oriented either. Verilog is a structured programming language, Silos is a 
Verilog simulator, and I think VHDL and HDL are versions of Verilog (that 
is, I've only seen them written as "Verilog-VHDL" and "Verilog-HDL").

In any case, Verilog *by design* uses four-state logic, modelling 1, 0, 
floating, undefined. It is not a bool, since *by definition* bools model 
only two states.


> The third value is usually called "TRI-state" or "don't care". (Though
> its sometimes a misnomer which means -- don't know, but do care.)

And SQL has NULL, which makes it an example of tri-state logic. (To be 
precise, SQL uses a version of Kleene K3 logic.)


[snip description of modelling hardware circuits]
All very interesting, but completely irrelevant to the question of 
subclassing bool.


> We've discovered that we live in a quantum-mechanical universe -- yet
> people still don't grasp the pragmatic issue that basic logic can be
> indeterminate at least some of the time ?!

Of course they do. My first post to you in this thread suggested that 
before you start re-inventing the wheel you look at prior art in the 
multi-value logic field.



> The name 'boolean logic' has never been re-named in honor of the many
> people who developed the advancements in computers -- including things
> like data sheets for electronic parts, 

Are you really suggesting that the name of Boolean Logic should be 
renamed away from the person who invented the field and instead named 
after the person who first wrote down a list of electronic part numbers 
and their specifications?


> or the code base used for solving
> large numbers of simultaneous logic equations with uncertainty included
> -- which have universally refined the boolean logic meanings found in
> "Truth" tables having clearly more than two values -- but don't take my
> word for it -- look in any digital electronics data book, and there they
> will be more than two states; marked with rising edges, falling edges,
> X's for don't cares, and so forth.

And those truth tables are not part of Boolean algebra.


[...]
> As I said to D'Aprano -- even a *cursory* examination (eg: as in not
> detailed) shows I could do things which he wasn't considering.

Andrew, I think you will be surprised at what I have considered. If you 
search the archives, you will find that (by memory) a decade ago I had 
considered using classes without instantiating them.

The questions I have about your strategy is not what can be done in 
Python, but how you think these things you want to do will solve the 
problem you apparently have?

To give an analogy... I have no doubt that you can build an television. 
But I question how building a television solves your problem of 
transporting a goat, a wolf and a cabbage across the river.

[...]
> I don't have a setting on my email to turn off html.  Sorry. Can't help.

You are using Thunderbird. You certainly do have such a setting.


> I don't know what you mean about composition vs. sub-classing. Would you
> care to show an example of how it would solve the problem and still
> allow hierarchical sorting ?

Composition is just another name for delegation, which is often used as 
the implementation of proxying. In an earlier message, you claimed to be 
able to write proxies. Does that help?


> I don't see how you can get pre-existing python functions (like sort,
> max, and min) to accept a complex bool value and have that value
> automatically revert to a True or False in an intelligent manner without
> overloading the operators defined in some class -- somewhere -- to
> operate on the data the class contains.


Here, let me get you started on this:


class TriStateLogic(int):
    def __new__(cls, value):
        if value in (0, 1): return bool(value)
        # Fold all other values to 2.
        obj = super(TriStateLogic, cls).__new__(cls, 2)
        return obj
    def __repr__(self):
        return "Undefined"
    def __nonzero__(self):
        return False


And an example in use:

py> Undefined = TriStateLogic(999)
py> if Undefined:
...     print "This is true"
... else:
...     print "This is false"
... 
This is false
py> sorted([True, False, Undefined, 99, 100])
[False, True, Undefined, 99, 100]
py> sorted([True, False, Undefined, 99, 100], reverse=True)
[100, 99, Undefined, True, False]




-- 
Steven



More information about the Python-list mailing list