Stephen, hi, and thanks for the critique.
On Jan 30, 2008 8:59 AM, Stephen J. Turnbull email@example.com 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 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
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