[Python-ideas] Revisiting dedicated overloadable boolean operators

Steven D'Aprano steve at pearwood.info
Sat Aug 4 12:37:52 EDT 2018


On Sat, Aug 04, 2018 at 04:56:56PM +0200, Benedikt Werner wrote:
> >I think that before adding more ad hoc binary operators, we ought to
> >consider the possibility of custom operators.
>
> That actually sounds like the most sensible solution so far

Thanks :-)

Unfortunately there's a flaw, in that the ~ symbol already means unary 
bitwise-not, so we can't use ~op for operators. Throwing some ideas out 
to be shot down:

    spam !op eggs
    spam :op eggs
    spam @op eggs
    spam ..op eggs


> >Although possibly we might choose another pseudo-namespace, to avoid
> >custom operators clashing with dunders. Trunders perhaps? (Triple
> >underscores?)
> >
> >Under this scheme, your operators would become:
> >
> >     ~or
> >     ~and
> >     ~xor
> >
> >and call trunders ___or___ etc.
> As Dan already pointed out it's very hard to see the difference between 
> two and three underscores so I don't think "trunders" would be a good idea.

Three underscores is 50% longer than two. I don't believe that it is 
harder to tell the difference between ___ and __ at a glance than it is 
to tell the difference between __ and _ at a glance, even for those with 
a mild visual impairment like mine.

Unless you're reading and writing code using a proportional font, in 
which case I have no sympathy.

Whatever naming convention we use, it should be a subset of dunders, 
different from all existing dunders, short enough to avoid being 
annoying to use, and make up an obviously distinct group. How about 
this?

    __o_name__

    __o_rname__


> I think it would make sense to instead use a new keyword to define 
> operators. Maybe something like "defop". I don't think that's a very 
> common variable or function name.

New keywords should be a last resort, only for functionality which 
requires syntactic support. This doesn't. What will this "defop" keyword 
do that def doesn't already do? Probably nothing, the methods will be 
ordinary methods just like __add__ and other operator dunders.

And even if we needed some sort of extra functionality, say, registering 
the operators, we could use a decorator for that.


> Example syntax could be:
> 
> class MyInt(int):
>     defop combine(self, other):
>         return self, other
> 
> # and now we can use it
> x combine y
> 
> # which is equivalent to
> x.combine(y)

That would mean giving up the ability to detect a whole lot of syntax 
errors at compile time.

Remember that under Python's execution model, the compiler cannot tell 
in advance which custom operators have been defined and which have not. 
It has to resolve them at runtime. So the only way we could allow 
`x combine y` as valid syntax would be if we also allowed errors like 
`print len alist` as valid syntax.

This is why I think that named operators should require a special 
prefix. Without the prefix, x combine y is a syntax error. But with the 
prefix, say, x :combine y, the compiler can use a custom byte-code to 
resolve the operator at runtime.

(Of course it will still be a runtime error if neither x nor y define 
the combine operator.)

All this supposes that there is sufficient benefit to allowing custom 
infix operators, including overridable or/and/xor, which is not yet 
shown.


-- 
Steve


More information about the Python-ideas mailing list