[Python-ideas] non-Pre-PEP: Syntactic replacement of built-in types with user-defined callables (Take 2... fewer newlines!)

Taro taroso at gmail.com
Thu Jan 31 14:38:32 CET 2008


Stephen, hi, and thanks for the critique.

On Jan 30, 2008 8:59 AM, Stephen J. Turnbull <stephen at xemacs.org> wrote:
> This is very persuasive, but may not be enough.  Jim's suggestion of a
> "logging string" was also interesting.
Nod -- changing one line at the beginning of a file could be rather elegant.

> I'm sorry, but I hate this term "typedef".  This is not a "type
> definition" in any Pythonic sense of the word "type", and the
> associations with C-style typedefs are painful.  How about
I'm not particularly enamoured with "typedef" either but the best
alternative I could think of was (ugh) "replacetype". If the idea is
deemed to be workable, then exact spelling can come later - I'll use
"replacingsyntax" until an alternative comes along. Not using "as" as
the preposition is probably a good idea, come to think of it, as there
could be less magic:
    # literal replacement only
    # float() calls __builtins__.float(); Decimal() calls decimal.Decimal()
    from decimal import Decimal replacingsyntax float
and
    # type replacement
    # float() calls decimal.Decimal(); Decimal() raises a NameError
    from decimal import Decimal as float replacingsyntax float

>  > a/ definition of adaptors would have to be allowed pre-typedef, which
>  > would allow them to be buried in code, making them far easier to miss;
> I don't see why this is a problem.  An adaptor for a scalar TYPE is
> just a converter from string to that TYPE.  If you have a such a
> converter (eg, because you're using Python as the platform for
> translating another language), why not just use it here?
>
> Since the way this would work is that each TYPE would have a
> string-to-TYPE-value converter, you would just do (inside the
> compiler)
>
> TYPE.stringconverter = STRINGCONVERTER
>
> and if the compiler encountered a literal with an undefined
> .stringconverter, it would generate an error to the effect of
>
>     Use of TYPE stringconverter 'STRINGCONVERTER' before definition.
[...provided that TYPE.stringconverter is set]

If I understand your intent correctly, as things stand this would
ordinarily be a runtime NameError, and extra code would need to be
added to the compiler to keep track of that:
   from decimal import Decimal with replacingsyntax float as float
   x = 1.01                  # SyntaxError here???
   def Decimal():....


> I think this would not be a problem in practice (except for typos)
> because you'd write decimal.py like this:
> ### decimal.py --- class Decimal for multiprecision decimal arithmetic
> from decimal import string_to_decimal with float readsyntax
I forgot about a module being able to import itself (I can't recall
using it for real, though I guess that mutual-imports count), but that
makes me uncomfortable; I'm not sure that my discomfort is
well-founded, though.

> want to put on that.  It seems like what you have in mind for a MyList
> is to convert from a list, but what if in your code you mostly want
> floats to be floats, but in MyLists they should be Decimals?  This
> would mean loss of precision:
For this, the "solution" to keep precision would be along the lines of:
    ## mycollections.py
    class MyListFloatHelper(float):
        def __init__(self, value):
            self._strvalue = value

    class MyList(list):
        def __init__(self, inlist):
            for elem in inlist:
                try:
                    elem = Decimal(elem._strvalue)
                except AttributeError:
                    pass
                self.append(elem)

    ## main.py
    from mycollections import MyListFloatHelper with readsyntax float
    from mycollections import MyList with readsyntax list
    def foo():
        myfloat = 1.000000000000000000000000000001
        mydlist = [1.0000000000000000000000000001]
        mydecimal = mydlist[0]
        print myfloat,"/", mydecimal
        #==> 1.0 / Decimal("1.0000000000000000000000000001")
        print type(myfloat), "/", type(mydecimal)
        #==> <class 'mycollections.MyListFloatHelper'> / <class
'decimal.Decimal'>

> (IANALL but ISTM that) an issue here is at what point does the
> compiler learn that a syntactic list is actually a literal, and your
> code doesn't help indicate that, or whether it would need to differ
> from the current compiler, either.

It would learn that a token is a literal at the same time it does now.
Determination of the need for literal replacements needs to be made at
the compilation stage so that stringliterals can be provided and extra
opcodes emitted (?an AST Visitor would be too late since the original
literals are already converted?)

    def foo():
        myfloat = 1.000000000000000000000000000001
        mydecimallist = [1.0000000000000000000000000001]
        mydecimal = mydecimallist[0]

    dis.dis(foo)        # Currently
    #==>  2           0 LOAD_CONST               1 (1.0)
    #==>              3 STORE_FAST               0 (myfloat)
    #==>
    #==>  3           6 LOAD_CONST               1 (1.0)
    #==>              9 BUILD_LIST               1
    #==>             12 STORE_FAST               1 (mydecimallist)
    #==>
    #==>  4          15 LOAD_FAST                1 (mydecimallist)
    #==>             18 LOAD_CONST               2 (0)
    #==>             21 BINARY_SUBSCR
    #==>             22 STORE_FAST               2 (mydecimal)
    #==>             25 LOAD_CONST               0 (None)
    #==>             28 RETURN_VALUE


    dis.dis(foo)         # With MyListFloatHelper and MyList
    #==>   2           0 LOAD_GLOBAL              0 (MyListFloatHelper)
    #==>               3 LOAD_CONST               1
('1.0000000000000000000000000001')
    #==>               6 CALL_FUNCTION            1
    #==>               9 STORE_FAST               0 (myfloat)
    #==>
    #==>   3          12 LOAD_GLOBAL              1 (MyList)
    #==>              15 LOAD_GLOBAL              0 (MyListFloatHelper)
    #==>              18 LOAD_CONST               1
('1.0000000000000000000000000001')
    #==>              21 CALL_FUNCTION            1
    #==>              24 BUILD_LIST               1
    #==>              27 CALL_FUNCTION            1
    #==>              30 STORE_FAST               1 (mydecimallist)
    #==>
    #==>   4          33 LOAD_FAST                1 (mydecimallist)
    #==>              36 LOAD_CONST               2 (0)
    #==>              39 BINARY_SUBSCR
    #==>              40 STORE_FAST               2 (mydecimal)
    #==>              43 LOAD_CONST               0 (None)
    #==>              46 RETURN_VALUE



More information about the Python-ideas mailing list