Other notes

Bengt Richter bokr at oz.net
Thu Dec 30 04:55:12 CET 2004

On Wed, 29 Dec 2004 13:11:43 -0500, Steve Holden <steve at holdenweb.com> wrote:

>Mike Meyer wrote:
>> bearophileHUGS at lycos.com writes:
>>>def interval(x, y): return range(x, y+1) # 2 parameters needed
>>>This may allow:
>>>assert 5 interval 9 == interval(5,9)
>> I don't like the idea of turning words into operators. I'd much rather
>> see something like:
>> @infix('..')
>> def interval(x, y):
>>     return range(x, y + 1)
>> assert 5 .. 9 == interval(5, 10)
>> This would also allow us to start working on doing away with the magic
>> method names for current operators, which I think would be an
>> improvement.
>Well, perhaps you can explain how a change that's made at run time 
>(calling the decorator) can affect the parser's compile time behavior, 
>then. At the moment, IIRC, the only way Python code can affect the 
>parser's behavior is in the __future__ module, which must be imported at 
>the very head of a module.
Good point, which I didn't address in my reply. (in fact I said I liked
@infix('..') for punctuation-char-named ops, but I was too busy with my
idea to think about that implementation ;-)

Potentially, you could do it dynamically with a frame flag (to limit the damage)
which said, check all ops against a dict of overloads and infix definitions while
executing byte code for this frame. Of course, the compiler would have to defer
some kinds of syntax error 'til run time. I.e., '..' would have to be translated
to OP_POSSIBLE_CUSTOM_INFIX or such. I doubt if it would be worth doing.

OTOH, I think my suggestion might be ;-) I.e., just do a macro-like (not a general
macro capability for this!!) translation of expressions with dots at both ends and
no embedded spaces (intial thought, to make things easier) thus:
    x .expr. y =>  expr(x, y)

when expr is a simple name, you can use that expression format to call a two-arg function
of that name, e.g.,

    def interval(x, y): return xrange(x, y+1)
    for i in x .interval. y: print i,  # same as for i in interval(x, y): print i,

but you could also write stuff like

    def GE(x,y): return x is MY_INFINITY or x >= y
    if x .GE. y: print 'x is greater than y'

The .expr. as expression would allow module references or tapping into general
expression and attribute magic etc. I.e., (untested)

   from itertools import chain as CHAIN
   for k,v in d1.items() .CHAIN. d2.items(): print k, v

or if you had itertools imported and liked verbose infix spelling:

   for k,v in d1.items() .itertools.chain. d2.items(): print k, v

or define a hidden-attribute access operation using an object's dict

   def HATTR(obj, i):
       try: return vars(obj)[i]
       except KeyError: raise AttributeError('No such attribute: %r', i)

   if thing .HATTR. 2 == 'two': print 'well spelled'

   from rational import rat as RAT

   if x .RAT. y > 1 .RAT. 3: do_it()

   your turn ;-)

>> As others have pointed out, you do need to do something about operator
>> precedence. For existing operators, that's easy - they keep their
>> precedence. For new operators, it's harder.
>Clearly you'd need some mechanism to specify preference, either 
>relatively or absolutely. I seem to remember Algol 68 allowed this.
>> You also need to worry about binding order. At the very least, you
>> can specify that all new operators bind left to right. But that might
>> not be what you want.
>Associativity and precedence will also have to affect the parsing of the 
>code, of course. Overall this would be a very ambitious change.
My suggestion if implemented with left-right priority would be easy to
implement (I think ;-) And you could always override order with parens.

Bengt Richter

More information about the Python-list mailing list