[Python-3000] Proposal: Metasyntax operator
Talin
talin at acm.org
Thu Jul 20 10:58:22 CEST 2006
A number of dynamic languages, such as Lisp, support the notion of an
'unevaluated' expression. In Lisp, a macro is simply a function that can
operate on the *syntax* of the expression before it is actually compiled
and interpreted.
A number of Python libraries attempt to use operator overloading to
achieve similar results. A good example is SQLObject's 'sqlbuilder'
module, which allows the user to construct SQL statements using regular
Python operators.
Typically these libraries work by creating a set of standard constants
(i.e. function names, symbols, etc.) and overloading all of the
operators to produce an expression tree rather than actually evaluating
the result. Thus, 'a + b', instead of producing the sum of a and b, will
instead produce something along the lines of '('+', a, b)'.
One weak area, however, is in the treatment of variables. This is
because you can't recover the name of a variable at runtime - the
variable name only exists in the compiler's imagination, and is
generally long gone by the time the program is actually executed.
There have been a number of attempts to get around this limitation. One
approach is to define a limited set of "standard" variables (X, Y, Z,
etc.) Unfortunately, this is quite limiting - having to pre-declare
variables is hardly 'Pythonic'.
The other is to wrap the variables in a class (such as "Variable('x')",
which is cumbersome. Various tricks with __getattr__ can also be done,
such as Variable.x and so on.
All of these are examples of "quoted" variables - which is another way
of saying that the variables are unevaluated, and that their syntactical
rather than semantic attributes are available to the program.
I'd like to propose a standard way to represent one of these syntactical
variables. The syntax I would like to see is '?x' - i.e. a question mark
followed by the variable name.
The reason for choosing the question mark is that this is exactly how
many languages - including expert systems and inference engines -
represent a substitution variable. The other reason, which was only of
minor consideration, is that the '?' is one of the few symbols in Python
whose meaning is not already assigned.
The actual meaning of ? would is very simple:
'?x' is equivalent to '__quote__("x")'
Where __quote__ is a user-defined symbol accessible from the current scope.
There will also be a standard, importable implementation of __quote__
which overloads all operators to create a simple AST. It is likely that
most code that does syntactic manipulation (such as sqlbuilder) could be
modified to use the standard AST created by the built-in quote class.
The reason for this is because the AST itself has no inherent meaning,
its only meaningful to the function that you pass it so. So the SQL
'select()' function could walk through the AST transforming it into SQL
syntax.
The quote operator has one other effect, which is that unlike regular
variables it can overload assignment:
?x = 3
Normally this would be an error, since ?x isn't an L-value. However the
interpretr notes the presence of the ? and allows the __assign__ method
to be called instead. A possible use for this would be to create
syntactical descriptions of keyword arguments that can be inspected at
runtime:
@overload(int,int,?x=int)
Now, one potential objection is what to do about conflicting definitions
of __quote__. My response is that it is up to the user to make sure that
__quote__ is defined to the correct class at the correct places in the
code, even if this means re-assigning it from time to time:
__quote__ = SQLVar
expr = Select( User.name, Where( ?name = 'Fred' ) )
__quote__ = MathVar
formula = ?a + ?b
(I should note that I don't expect this proposal to get very far.
However, its something I've been thinking about for a long time.)
-- Talin
More information about the Python-3000
mailing list