Restricted language
Hi Armin, in order to start considerations about how to implement Python-in-Python, here some initial questions. Yes, we should begin with the RISP processor :-) (Reduced Instruction Set Python). There are some issues where I have to navigate around in my little tests that I've done already. One thing is the lack of a switch statement in Python, which either leads to zillions of elifs, or to the use of function tables and indexing. We should come up with some "how to do this". Another thing is common for-loops in C. Almost all of them which I tried to translate into Python became while-loops. Is that ok? Data types. How do we model the data types which are used internally by Python? Somebody already showed a small Python interpreter for Python 2.0 (very sorry, I can't find who it was), which was implemented on top of basic Python objects. This was a nice attempt and makes sense to start with. But I gues, for a real Python in Python, we also need to re-build the data structures and cannot borrow lists, tuples and dicts and "Lift them up" into the new level. Instead, these need to be built from a minimum Python "object set" as well. How far should we go down? I was thinking of some basic classes which describe primitive data types, like signed/unsigned integers, chars, pointers to primitives, and arrays of primitives. Then I would build everything upon these. Is that already too low-level? Do you think this should be started using the builtin objects right now, and these should be replaced later, or from the beginning? How far should it go: Are we modelling reference counting as well? And since you said that whether to use reference counting at all, or a classical GC, or object/type tuples returned as register pairs, I'm asking how we should do the proper abstraction? This means clearly to me, that I should *not* repeat the Py_INCREF/Py_DECREF story from Python, but we need to do a more abstract formulation of that, which allows us to specify it in any desired way. So I guess we are not fine by just repeating the C implementation in Python, but we need some kind of "upsizing" the algorithms, away from a flat write-down in C, up to a more abstract defintion of what we want to do. I could even imagine that there are lots of other cases where the C source code already is much to verbose, over-specifying, and obfuscating what the code really is supposed to do. Would you propose to "start dumb", literally like the C source, and add abstractions after the initial thing works, or does this have to happen in the first place? Very many things are done in a specific way in C, just because of the fact that you have to use C. But when I know I have Python, I would most probably not use C string constants all around, but use Python strings. It is C that forces us to use PyString_FromString and friends. Do you think we should repeat this in the Python implementation? This is just the beginning of a whole can of worms to be considered. Just to start it somehow :-) all the best -- chris -- Christian Tismer :^) <mailto:tismer@tismer.com> Mission Impossible 5oftware : Have a break! Take a ride on Python's Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/ 14109 Berlin : PGP key -> http://wwwkeys.pgp.net/ work +49 30 89 09 53 34 home +49 30 802 86 56 pager +49 173 24 18 776 PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04 whom do you want to sponsor today? http://www.stackless.com/
Hi Christian, [Christian Tismer Sat, Jan 18, 2003 at 11:03:34PM +0100]
in order to start considerations about how to implement Python-in-Python, here some initial questions. Yes, we should begin with the RISP processor :-) (Reduced Instruction Set Python).
cool, we are getting to implementation strategy! Hopefully you don't mind if i comment even i am not Armin :-) I'm curious about his oppinion on this, too.
There are some issues where I have to navigate around in my little tests that I've done already.
One thing is the lack of a switch statement in Python, which either leads to zillions of elifs, or to the use of function tables and indexing. We should come up with some "how to do this".
Maybe make a list with 256 entries and use the bytecode as an index to get to a frame-method (store_attr etc.)? A specialised compiler could later inline the method bodies and turn any attribute access on 'self' (the frame object) into a local name operation. So there would be the first restriction: always use 'self' to refer to the instance within a frame method.
Another thing is common for-loops in C. Almost all of them which I tried to translate into Python became while-loops. Is that ok?
yes, why should it not?
Data types. How do we model the data types which are used internally by Python? Somebody already showed a small Python interpreter for Python 2.0 (very sorry, I can't find who it was),
I think several people mentioned doing something like this. Look at http://codespeak.net/moin/moin.cgi/MinimalPython where i gathered two links about python-in-python implementations. If i forgot anyone: it's a wiki so just insert a paragraph about your stuff. Never forget to describe a link!
which was implemented on top of basic Python objects. This was a nice attempt and makes sense to start with. But I gues, for a real Python in Python, we also need to re-build the data structures and cannot borrow lists, tuples and dicts and "Lift them up" into the new level.
I wouldn't do this for starters.
Instead, these need to be built from a minimum Python "object set" as well. How far should we go down?
Redoing the basic types can be deferred IMO. Basically we need to do typeobject.c in python, right?
I was thinking of some basic classes which describe primitive data types, like signed/unsigned integers, chars, pointers to primitives, and arrays of primitives. Then I would build everything upon these. Is that already too low-level? Do you think this should be started using the builtin objects right now, and these should be replaced later, or from the beginning?
replaced later IMO. First get a working interpreter and eliminate anything that stands in the way.
How far should it go: Are we modelling reference counting as well?
I'd try without. For the time beeing, CPython does it for us until we come up with a scheme. But the scheme is best experimented with when we have a working interpreter.
So I guess we are not fine by just repeating the C implementation in Python, but we need some kind of "upsizing" the algorithms, away from a flat write-down in C, up to a more abstract defintion of what we want to do.
I regard a python-in-python interpreter as Pseudo-Code which can be turned into other representantions (in C or another bytecode machine) by an appropriate compiler. Using Python to describe the abstract descriptions makes sense to me. So we eliminate any C-isms (like switch statements, reference counting, signalling exceptions by NULL returns etc.).
Very many things are done in a specific way in C, just because of the fact that you have to use C. But when I know I have Python, I would most probably not use C string constants all around, but use Python strings. It is C that forces us to use PyString_FromString and friends. Do you think we should repeat this in the Python implementation?
No. The goal is: get a working interpreter in python running on CPython. An interpreter where you can run the unittests against. Don't care about any low-level stuff. That is handled by CPython and later on will be handled by custom compilers (to C, MMIX, assembler, whatever). I am still thinking about Roccos issue of how to "differentiate" host system (CPython) exceptions from exception of the code we interprete in python. My first take is to catch any exception, rewrite the traceback information (using the python-frames) and reraise it. The exceptions must look the same as if i executed with CPython:ceval.c all the best, holger
Hi Holger,
[Christian Tismer Sat, Jan 18, 2003 at 11:03:34PM +0100]
in order to start considerations about how to implement Python-in-Python, here some initial questions. Yes, we should begin with the RISP processor :-) (Reduced Instruction Set Python).
cool, we are getting to implementation strategy!
Hopefully you don't mind if i comment even i am not Armin :-) I'm curious about his oppinion on this, too.
No, this is great. These things need to be discussed and we need to agree on a path to go. Interestingly, your opinion is quite different from Armin's, and the latter brought me to ask these questions. [switch and such]
Maybe make a list with 256 entries and use the bytecode as an index to get to a frame-method (store_attr etc.)?
Sure, I know all the possible variants, the question is whether we like it or not. If we are recoding Pythpn in Python, then with the final idea in mind, that in some future, this might become the real implementation of Python. But then, it should not look worse than in C. ...
Another thing is common for-loops in C. Almost all of them which I tried to translate into Python became while-loops. Is that ok?
yes, why should it not?
Try to re-code some C code of the interpreter and the builtin objects into Python. After the third work-around to some C construct, you begin to ask for more expressive constructs. Instead of upgrading to better abstraction, I find myself emulating C constructs. This is not what I wanted. <snip/>
we also need to re-build the data structures and cannot borrow lists, tuples and dicts and "Lift them up" into the new level.
I wouldn't do this for starters.
I understand you approach. But here we begin to see conflicting ideas. Citing Armin: """ (1) write a Python interpreter in Python, keeping (2) in mind, using any recent version of CPython to test it. Include at least the bytecode interpreter and redefinition of the basic data structures (tuple, lists, integers, frames...) as classes. Optionally add a tokenizer-parser-compiler to generate bytecode from source (for the first tests, using the underlying compile() function is fine). """ ...
Redoing the basic types can be deferred IMO. Basically we need to do typeobject.c in python, right?
I thought so, too, but I'm not sure if my overview of the whole thing is good enough to judge this early. ...
How far should it go: Are we modelling reference counting as well?
I'd try without. For the time beeing, CPython does it for us until we come up with a scheme. But the scheme is best experimented with when we have a working interpreter.
... I can't decide here. Need Armin's input, whether it makes sense to postpone the detail problems in the beginning. This surely gets us a simple start, but I hope it will not hinder us from tackling the real problems. A Python interpreter in Python is not a real problem. But hopefully a goot start to tackle them.
No. The goal is: get a working interpreter in python running on CPython. An interpreter where you can run the unittests against. Don't care about any low-level stuff. That is handled by CPython and later on will be handled by custom compilers (to C, MMIX, assembler, whatever).
Ok. I'm eager to hear what the comments will be :-)
I am still thinking about Roccos issue of how to "differentiate" host system (CPython) exceptions from exception of the code we interprete in python. My first take is to catch any exception, rewrite the traceback information (using the python-frames) and reraise it.
This is the "world on the wire" problem. In a direct mapping, back to C code, we could simple repeat the Null-check strategy as it is now. See "From PyPy to Psyco", (3a). In the case where we need to run interpreter Python from Python, we have to emulate exceptions in a way, and I think we cannot "borrow" them, but we need to interpret them ourselves. If you look at the eval_frame code, there we already have to handle the block stack, so we can do our own exceptin handling as well. There is one problem with "borrowed" objects: If you have a dictionary for instance, which is not implemented by our Python, but from the standard, then this might raise exceptions, which we have to catch and turn into our emulated exceptions. Again the big picture: ---------------------- I don't want to disappoint anybody, but please don't think the initial Python-in-Python interpreter is such a big deal. It is the tip of the iceberg. IMHO, the real hard work is to re-write the whole C library. It is a major subject of the project to turn that into something more flexible, and this is the real target. Whatever path we choose, we need to ensure that we find a connected path to that goal. So what I'm trying to do is to do tiny proof-of-concept things, and try to build a chain of refinements, which leads to a stepwise implementable final project. We need to break the C barrier as early as possible, or I can's see how Python can get rid of CPython. cheers - chris -- Christian Tismer :^) <mailto:tismer@tismer.com> Mission Impossible 5oftware : Have a break! Take a ride on Python's Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/ 14109 Berlin : PGP key -> http://wwwkeys.pgp.net/ work +49 30 89 09 53 34 home +49 30 802 86 56 pager +49 173 24 18 776 PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04 whom do you want to sponsor today? http://www.stackless.com/
Hello Christian, On Sun, Jan 19, 2003 at 03:16:55PM +0100, Christian Tismer wrote:
Redoing the basic types can be deferred IMO. Basically we need to do typeobject.c in python, right?
I thought so, too, but I'm not sure if my overview of the whole thing is good enough to judge this early.
I'm not sure typeobject.c has a special role to play here. We might at first just rely on built-in Python objects to implement all our classes, including type objects.
I am still thinking about Roccos issue of how to "differentiate" host system (CPython) exceptions from exception of the code we interprete in python. My first take is to catch any exception, rewrite the traceback information (using the python-frames) and reraise it.
Here we are confusing the two levels of Python. Let's call them the interpreter-level and the application-level. Each application-level object is emulated by an interpreter-level instance of a class like class PyObject: v_ob_type = property(...) ... Let's compare this with a C compiler which must manage a complex data structure for every variable of the C program it compiles. The PyObject class is this data structure. If a variable of the C program is found to be a constant, then the C compiler will internally use a special structure which holds (among other management data) the constant immediate value as a C-compiler-level value. So let's call an "immediate" a C-program-level value which is directly implemented by a C-compiler-level value. Non-immediate values would be e.g. variables that are stored in the stack. Similarily, if we want to implement, say, dictionaries using real Python dictionaries, it is an application-level object that must be implemented using a more complex structure which holds, among other things, a real interpreter-level dictionary. It's just the same as immediates in C programs: class ImmediateObject(PyObject): def __init__(self, ob): ... An application-level dictionary (say created by the BUILD_DICT opcode) is constructed as "ImmediateObject({})". In a first phase we need only ImmediateObjects because (almost?) all application-level objects can be implemented this way. Now let's talk about exceptions. There are also application-level exceptions (the ones that can be caught by except: in the interpreted application) and interpreter-level exceptions (e.g. a bug in the interpreter raising some IndexError). The former must be emulated, not used directly at the interpreter-level. It is just a coincidence that an application-level exception generally also means the stack of calls made by the interpreter must be popped up to the main loop's block handlers. To perform the latter we need a new exception: class EPython(Exception): pass Then the immediate translation of the CPython code PyErr_SetString(PyExc_IndexError, "index out of bounds"); return NULL; is SetException(ImmediateObject(IndexError), ImmediateObject("index out of bounds")) raise EPython where the ImmediateObject()s are here because an application-level exception stores application-level values. The main loop catches EPython exceptions. If we want to follow the C code less closely but be more Pythonic, we can drop the above SetException() which would store information into something like CPython's PyThreadState. Instead, we can directly embed this information into the EPython class: class EPython(Exception): def __init__(self, v_type, v_value): ... I prefix the argument names with 'v_' to remind us that an application-level object is expected (i.e. an instance of PyObject), not e.g. ValueError or a string. Then the code becomes raise EPython(ImmediateObject(IndexError), ImmediateObject("index out of bounds")) which I believe clearly shows the distinction between application-level and interpreter-level exceptions. Oh, and if you got it right, you must see why the 'v_ob_type' property of 'class PyObject' earlier in this mail must never hold a real type like 'int' or 'list', but instead an application-level type object like 'ImmediateObject(int)' or 'ImmediateObject(list)'. A bientot, Armin.
[armin on using a simple PyObject emulation class ...]
Let's compare this with a C compiler which must manage a complex data structure for every variable of the C program it compiles. The PyObject class is this data structure. If a variable of the C program is found to be a constant, then the C compiler will internally use a special structure which holds (among other management data) the constant immediate value as a C-compiler-level value. So let's call an "immediate" a C-program-level value which is directly implemented by a C-compiler-level value. Non-immediate values would be e.g. variables that are stored in the stack.
using Bengt's suggestion we could say that an "immediate" C-program-level value is represented by a C-compiler-level value.
Similarily, if we want to implement, say, dictionaries using real Python dictionaries, it is an application-level object that must be implemented using a more complex structure which holds, among other things, a real interpreter-level dictionary. It's just the same as immediates in C programs:
class ImmediateObject(PyObject): def __init__(self, ob): ...
your class definition "tags" an CPython object as an "immediate" object, right?
An application-level dictionary (say created by the BUILD_DICT opcode) is constructed as "ImmediateObject({})". In a first phase we need only ImmediateObjects because (almost?) all application-level objects can be implemented this way.
ImmediateObjects would be tagged CPython objects. I don't see immediate use, though :-)
Now let's talk about exceptions. There are also application-level exceptions (the ones that can be caught by except: in the interpreted application) and interpreter-level exceptions (e.g. a bug in the interpreter raising some IndexError). The former must be emulated, not used directly at the interpreter-level. It is just a coincidence that an application-level exception generally also means the stack of calls made by the interpreter must be popped up to the main loop's block handlers. To perform the latter we need a new exception:
class EPython(Exception): pass
Then the immediate translation of the CPython code
PyErr_SetString(PyExc_IndexError, "index out of bounds"); return NULL;
is
SetException(ImmediateObject(IndexError), ImmediateObject("index out of bounds")) raise EPython
IMHO the python level interpreter should not deal with exceptions like this. E.g. CPython's BINARY_SUBSCR bytecode implementation raises the above exception as an optimization to avoid calling the generic PyObject_GetItem (which does lots of checks itself). But i'd like to implement BINARY_SUBSCR like this: def BINARY_SUBSCR(self): w = self.valuestack.pop() v = self.valuestack.pop() self.valuestack.push(w.__getitem__(v)) With CPython this could raise an exception if 'v' would be "out of bound" or 'w' doesn't implement the getitem-protocol or whatever. The tricky part (to me) is catching the (CPython-) exception and executing the application-level except/finally code in the current bytecodestring. I have done some stuff with "exception/finally" handling wrapped into an object in this CPython-Hack: http://codespeak.net/moin/moin.cgi/IndentedExecution It introduces an object (and strange xml-ish syntax :-) which wraps except/finally handling so that the 'except:' or 'finally:' code is *not* in the current bytecode-string. If reading it, don't look at the namespace interaction bits, they are distracting for our context. I think i'd like to try out an approach where no bytecode needs more than a few lines of python implementation and exception handling is easy to understand. IMO it is especially important to me that all the optimization stuff (like in BINARY_SUBSCR) is removed. Hopefully only the main dispatching loop will have to deal with exceptions & their (re)presentation to the application-level ... cheers, holger
Hello Holger, On Mon, Jan 20, 2003 at 04:40:04AM +0100, holger krekel wrote:
using Bengt's suggestion we could say that an "immediate" C-program-level value is represented by a C-compiler-level value.
It fells like you made exactly the confusion that I was trying to prevent people from making. A C-program-level value is *not* *just* a C-compiler-level value. I mean, your "immediate value" in your C program might be in a variable 'x', but in the C compiler it is not in any variable. Instead, it is embedded within a complex structure, e.g. struct program_variable { bool is_constant; union { struct { // non-constant case int in_which_register; ... } struct { // constant case long immediate_value; ... } } };
ImmediateObjects would be tagged CPython objects. I don't see immediate use, though :-)
You cannot use real CPython objects to represent application-level objects. If you do, you are confusing the two levels. It will lead you into tons of problems; for example, you can only use immediates for the application-level objects. It is similar to a C compiler in which the above struct program_variable would not exist; all program variables would be represented as a long. You can only represent immediates like this. For example, if you want later to design your own "class MyList" implementing lists, and use this instead of real list objects to represent application-level lists, it looks fine; you change the implementation of BUILD_LIST to create an instance of MyList, and work with that instead of a real list. But then, the class must work *exactly* like a list for this to work. The problem is that it cannot. If you want to give another implementation you cannot inherit from the built-in "list" type. You are stuck. At best you will change *all* your interpreter to contain tests like "if isinstance(x, MyList)" to know if the object 'x' is an immediate object or something that needs special care. Hence the class ImmediateObject is absolutely essential. If you get confused think about implementing a Python interpreter not in Python but in another similar language. You will be forced to define classes like lists, tuples, dicts and so on, and give direct mappings between what the interpreted application wants to do on instances of these classes and what the interpreter itself can do with the underlying implementing object. The case of Python-in-Python gets confusing because these mappings are trivial in the case of the above class ImmediateObject. But you cannot remove them. You have a similar problem with exceptions: you must not confuse the exceptions that the application wants to see and the exceptions that are used internally in the interpreter because it is a nice programming technique to use in your interpreter. Here again, think about Python-in-some-similar-language. You will see that you need a way to say which Python exception must be thrown in the application. Then you need a way for the interpreter to come back from a couple of nested calls to the main loop, and so you create an "EPython" exception to raise for this purpose. As above it is easy to get confused because ImmediateObjects have a trivial mapping between what the application wants to see and what the operation on the underlying implementing object actually raises. In other words, if you implement a list with a CPython list 'a', then when you try to do the PyObject_GetItem operation, you will end up doing this: try: return a[index] except Exception, e: SetException(ImmediateObject(e)) raise EPython Note how 'e' is embedded inside an ImmediateObject().
But i'd like to implement BINARY_SUBSCR like this:
def BINARY_SUBSCR(self): w = self.valuestack.pop() v = self.valuestack.pop() self.valuestack.push(w.__getitem__(v))
Here we are using Python's __getitem__ protocol to implement Python's __getitem__ protocol. I see nothing wrong in that, but it is easy to get confused. To make things clearer I would way: self.valuestack.push(w.getitem(v)) where all non-abstract classes inheriting from PyObject should have a getitem() method; for example, in class ImmediateObject: def getitem(self, index): try: return self.ob[index.ob] except Exception, e: SetException(ImmediateObject(e)) raise EPython This level of indirection is quite necessary. Seen otherwise, you cannot store arbitrary CPython objects into the self.valuestack list, because otherwise you can only store CPython objects representing themselves, and you are stuck as soon as you want to represent things differently. Think about the type() function; it could not return the real type of the implementing object, because you couldn't implement lists or ints with a custom class. And it cannot call a new method __type__() of the object, because you cannot add such a new method to all already-existing built-in objects. You could hack something that calls __type__() if it exists and returns the real type otherwise, but you are running into trouble when interpreting programs that define __type__() methods for their own purpose. This is the kind of confusion we are bound to run into if we are not careful. With all correctly set up it is trivial to catch the EPython exception in the main loop and, in its exception handler, unwind the block stack just like CPython does in its main loop. If another exception (not EPython) is raised in the interpreter, it will not be caught by default; it is the normal behavior of Python programs and means there is a bug (in this case, a bug in the interpreter). A bientôt, Armin.
Hello Christian, On Sat, Jan 18, 2003 at 11:03:34PM +0100, Christian Tismer wrote:
Would you propose to "start dumb", literally like the C source, and add abstractions after the initial thing works, or does this have to happen in the first place?
I would suggest that wherever we feel that CPython is stuck with a "bad" way to express things, let's think a moment or two if there is a cleaner way to do it Pythonically. Only if no consensus is found, we stick with the CPython way.
One thing is the lack of a switch statement in Python, which either leads to zillions of elifs, or to the use of function tables and indexing.
For the main loop in eval_frame(), I would say use a list or a dict of functions. It is more flexible because it would let us experiment with adding opcodes dynamically. With some specific support from the "static compiler" it can later be translated into a regular C switch.
Another thing is common for-loops in C. Almost all of them which I tried to translate into Python became while-loops. Is that ok?
Here again I would say use "for i in range(...)" whenever it is clearly what the C code means. Compared to "while i < ...", it has the advantage that if "..." is a complex expression it tells that this expression can be computed only once. In C you would have to use workarounds to help the compiler in this case.
Data types. How do we model the data types which are used internally by Python?
We need a common abstraction for all objects, like a base PyObject class with an ob_type property, maybe nothing more. In a first place we can implement objects staightforwardly with the corresponding basic Python objects. Then we can provide alternate object implementations which look like CPython's implementations. We must allow still other implementations to be added later. The first phase would be done with a single class which maps attribute manipulation and method calls to an internal, "real" Python object. This may only work for objects like lists and dicts which we have a great deal of control over from Python; it may not be sufficient for frame objects, for example.
I was thinking of some basic classes which describe primitive data types, like signed/unsigned integers, chars, pointers to primitives, and arrays of primitives. Then I would build everything upon these. Is that already too low-level?
Something along these lines. Maybe a little bit higher-level with no explicit pointers, mutable/immutable flags, and arrays that know their length (althought out-of-bounds checks are not guaranteed, e.g. the no-debug C implementation would not have them). Required pointer indirections can often be deduced automatically from this info; e.g. tuples can store the array of items in-place because it is of immutable length. Lower-level hints may later be added or experimented with (e.g. in the current CPython implementation, dicts have a small cache area that is only used if it is small enough, while lists don't). I feel that a good way to find out which level of abstraction we should target would be to think that we may later emit not C code but OCaml code (for example).
This means clearly to me, that I should *not* repeat the Py_INCREF/Py_DECREF story from Python, but we need to do a more abstract formulation of that, which allows us to specify it in any desired way.
I believe that the above data representation (with maybe the help of more flags) should be enough to deduce how to make a reference-counting interpreter. It may occasionally contain more Py_INCREF/Py_DECREF than the hand-tuned CPython, but I say never mind. If it is a real issue in a specific case then we can always fix it manually with more hints.
I know I have Python, I would most probably not use C string constants all around, but use Python strings.
When the interpreter uses Python strings internally just because handling C strings is more complex, then of course don't repeat the PyString_FromString() calls. We will see later how internal string handling may be translated to C. Reserve PyString_FromString() for places where we need a real object visible from the interpreted program.
This is just the beginning of a whole can of worms to be considered. Just to start it somehow :-)
Sure :-) By the way, I feel that if one routine deserves some special treatment (like refactoring) it is the main loop in eval_frame(). For example, using exceptions to signal "break" or "continue" statements. We already mentionned catching "EPython" exceptions raised by called functions to signal an exception visible in the program we interpret (instead of the "if result!=NULL" trick), and using a table of functions instead of a big switch. If I think about Psyco it is also the place where extra code must be added, like checking the code object for an already-compiled version or collecting statistics. I guess this is also where special treatment is required for a stackless-style CPS interpreter. So I would say, as a general rule, let's be as Pythonic as we like for the main loop, but let's keep globally close to the original C code for everything else. This is also crucial for compatibility. (Yes, I think we will also be able to emit C code almost fully binary compatible with CPython and its extension modules.) A bientot, Armin.
On Sat, Jan 18, 2003 at 11:03:34PM +0100, Christian Tismer wrote:
Hi Armin,
Sorry, I'm not armin either.
Yes, we should begin with the RISP processor :-) (Reduced Instruction Set Python).
As already said in private, I like that name. Very descriptive :-)
Data types. How do we model the data types which are used internally by Python? Somebody already showed ... and cannot borrow lists, tuples and dicts and "Lift them up" into the new level. Instead, these need to be built from a minimum Python "object set" as well. How far should we go down?
As already said on the list, I like Mozart/Oz but not its syntax. Here are two links that I hope useful: 1. oz kernel language http://www.mozart-oz.org/documentation/tutorial/node1.html#label2 It says that other language constructs are built on top of that. 2. hierarchy of primary types http://www.mozart-oz.org/documentation/tutorial/node3.html#label14 What about reusing the idea of record that serves as a basis for a lot of higher-level constructs (dictionnaries, tuples, classes and objects, etc.) See also http://www.mozart-oz.org/documentation/tutorial/node3.html#label19 IMHO, the goal we are trying to achieve can not be a new idea. Looking around for research papers and research languages is a good way not to completely reinvent the wheel. HTH. -- Nicolas Chauvat http://www.logilab.com - "Mais où est donc Ornicar ?" - LOGILAB, Paris (France)
[...]
As already said on the list, I like Mozart/Oz but not its syntax. Here are two links that I hope useful:
1. oz kernel language http://www.mozart-oz.org/documentation/tutorial/node1.html#label2
It says that other language constructs are built on top of that.
2. hierarchy of primary types http://www.mozart-oz.org/documentation/tutorial/node3.html#label14
What about reusing the idea of record that serves as a basis for a lot of higher-level constructs (dictionnaries, tuples, classes and objects, etc.) See also http://www.mozart-oz.org/documentation/tutorial/node3.html#label19
This is really interesting and definatelly goes in the direction Stackless might have taken in the future (that is a network transparent runtime environment).
IMHO, the goal we are trying to achieve can not be a new idea. Looking around for research papers and research languages is a good way not to completely reinvent the wheel.
I don't know if this helps (probably confuses more than anything else :-) The other day I had a look at a smalltalk environment (squeaky. For the intersted german reader, there is a smalltalk article in the latest c't). Anyway, the interesting part is that the smalltalk runtime engine is written in, guess what, smalltalk. What you are really running is of course compiled C Code, but the smalltalk environment is able to compile the virtual machine smalltalk code to C. Stephan
HTH.
participants (4)
-
Armin Rigo -
Christian Tismer -
holger krekel -
Nicolas Chauvat