[Python-ideas] non-Pre-PEP: Syntactic replacement of built-in types with user-defined callables.

Taro taroso at gmail.com
Mon Jan 28 06:48:32 CET 2008


Hi all,



Built-in types such as float, string, or list are first-class citizens in
Python sourcefiles, having syntactic support:

    myfloat = 1.0

    mystring = "my string"

    mylist = [1,2,4,8]

    mydict = {1:"a", 2:"b", 3:"c"}

    myset = {1,2,3}



User-defined classes are second-class citizens, requiring data to be
manually converted from a type:

    mydecimal = Decimal("1.00000000000000001")

    myrope = Rope("my rope")

    myblist = BList([1,2,4,8])

    myordereddict = OrderedDict((1,"a"), (2, "b"), (3, "c"))

    myfrozenset = frozenset([1,2,3])



If there's only one or two conversions needed in a file, then such
conversion is not particularly burdensome, but if one wants to consistently
use (say) decimals throughout a file then the ability to use a literal
syntax makes for prettier source.



Some languages have open types, allowing the addition of methods to built-in
types.  This is not considered desired behaviour for Python, since
modifications made in one module can potentially affect code in other
modules.



A typedef is syntactic sugar to allow user-defined replacements to be
treated as first-class citizens in code.  They affect only the module in
which they appear and do not modify the original type.  To be typedeffable,
something must be a builtin type, have a constant/syntactic representation,
and be callable.  Hence, typedeffable types would be limited to complex,
dict, float, int, ?object?, list, slice, set, string, and tuple.   No
modification is made to __builtins__ or types, so conversion and/or
reference to the original type is still possible.



The syntax for a typedef is:

    from MODULE typedef ADAPTOR as TYPE

OR

    typedef BUILTINADAPTOR as TYPE



Syntactic constants of a given type are then wrapped with a call:

    ADAPTOR(SOURCELITERAL)

where SOURCELITERAL is the string that appears in the sourcecode

eg:

    from decimal typedef Decimal as float

    i = 1.000000000000000000000000000001

translates as:

    from decimal import Decimal as float

    i = Decimal("1.000000000000000000000000000001")



Syntactic collections of a given type are always provided with a list of
objects, eg:

    from decimal typedef Decimal as float

    from blist typedef BList as list

    i = 1.000000000000000000000000000001

    b = [1.1, 4.2]

translates as:

    from decimal import Decimal as float

    from blist import BList as list

    b = Blist([Decimal("1.1"), Decimal("4.2")])



and

    from collections typedef OrderedDict as dict

    d = {1:"a", 2:"b", 3:"c"}

as:

    from collections import OrderedDict as dict

    d = OrderedDict([(1,"a"), (2,"b"), (3,"c")])


A typedef appears at the start of a module immediately after any __future__
imports.  As no adaptors can be defined in a module before a typedef and
typedefs are in no way a forward declaration, "typedef ADAPTOR as TYPE" only
works for builtins, since to do otherwise would lead to one of two
unpalatable options; either:

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; or

b/ adaptors would be defined after the typedef, which means that you'd have
to handle:

    typedef float as float

   def float():

      pass

or:

    typedef MyObject as object

   class MyObject(object):

       pass

or:

    typedef myfloat as float

    x = 1.1

    def myfloat():

       pass



It is true that if a valid typedef is made, the type can be redefined within
the module; but the "consenting adults" rule applies -- it's possible to
redefine str and float multiple times within a module as well, but that
isn't recommended either (and the typedef at the top of the module at least
indicates that non-standard behaviour is to be expected)



It is a SyntaxError to typedef the same type more than once:

    from decimal typedef Decimal as float

    from types typedef FloatType as float   #SyntaxError("Type 'float'
already redefined.")



Spelling:  "typedef" is prettier than "pragma", and less likely to be in use
than "use" but its behaviour is somewhat different from C's typedef, so
perhaps another term may be preferred.



Theoretical Performance Differences:  Since a typedef is purely syntactic
sugar, and all tranformational work would be done at compilation, running
code should be no slower (there should be no new opcodes necessary) and by
default no faster that performing manual conversion (though they may assist
an optimisation).  Unless optimisation magic is available,
performance-critical code should be careful when typedeffing not to use
typedeffed literals in inner loops.



I know it's considered polite to provide code, but any implementation would
have to be in C, so please accept this extremely fake dummy implementation
which in no way resembles the way things really work as a poor substitute:



typedefs = { FLOATTYPE: None,

                     INTTYPE: None,

                     LISTTYPE: None,

                     DICTTYPE: None,

                     ... }



while True

    line = lines.next()

    type, module, adaptor = parsetypedef(line)

    if type is None:

        break

    if typedefs[type] is not None:

        raise SyntaxError("Typedef redef")

    typedefs[type] = adaptor

    if module is not None:

        emit_bytecode_for_import_from(type, module, adaptor)

    else:

        emit_bytecode_for_assignment(type, adaptor)





parse([line] + lines)

...



def emit_float(...):

    if typedefs[FLOATTYPE] is not None:

        emit_constant(typedefs[FLOATTYPE][0], stringliteral)

    else:

        ... # standard behaviour



def emit_list(...):

    if typedefs[LISTTYPE] is not None:

        emit(LOADGLOBAL, typedefs[LISTTYPE])

    # standard behaviour

    if typedefs[LISTTYPE] is not None:

        emit(CALL_FUNCTION)

    # standard behaviour



All rights are assigned to the Python Software Foundation
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/python-ideas/attachments/20080128/4fec1db9/attachment.htm 


More information about the Python-ideas mailing list