Could Emacs be rewritten in Python?

Christian Tanzer tanzer at swing.co.at
Mon Apr 14 10:00:46 CEST 2003


Carl Banks <imbosol-1050127854 at aerojockey.com> wrote:

> Christian Tanzer wrote:
> > Dynmaic scoping is used for lots of things in Emacs. With a different
> > design many of those uses could certainly be replaced by a simpler
> > design. I doubt that one could easily replace all of them, though.
> >
> > As someone else pointed out, dynamic scoping is used to change values
> > of functions called indirectly -- thus converting them into arguments
> > passed around doesn't really work.
>
> No, but lexical closures can do this just fine:
>
>     def a():
>         value_to_be_passed_indirectly = some_calculation()
>         def b():
>             do_something_with(value_to_be_passed_indirecty)
>         call_function_that_calls_callback(b)
>
>
> Not to mention you can do similar stuff with a class:
>
>     def a(self):
>         closure = B(some_calculation())
>         call_function_that_calls_callback(closure.b)
>
>     class B:
>         def __init__(self,value):
>             self.value_to_be_passed_indirectly = value
>         def b(self):
>             do_something_with(self.value_to_be_passed_indirecty)
>
>
> The fact is, arguments have been passed indirectly in Python for a
> long time, happily, and without dynamic scoping.  It will not be hard
> to replace this use of dynamic scoping.

You didn't understand what I tried to express. One last try:

Emacs has lots (thousands?) of variables influencing the behavior of
the editor. Some are global, some are buffer-local, some are
frame-local, some are bound to text properties, ...

To make this more concrete, lets look at an example. Emacs provides
text properties which allow customization of cursor movements in part
of a buffer. Using these influences the behavior of all Emacs
builtins, e.g., goto-char. If you want to implement a function which
needs unencumbered movement for whatever reason, it simply `let`s
`inhibit-point-motion-hooks` to a true value before calling other
functions. What gets called inside the `let` can be an arbitrary
function and that function calls other arbitrary functions the
programmer might know nothing about. But somewhere down the call tree,
some builtin will be called which behaves differently depending on the
value of `inhibit-point-motion-hooks` and the text properties in the
buffer.

All these functions (except the one you're writing) might have been
implemented years before the text properties and
`inhibit-point-motion-hooks` were introduced.

> > One could use a
> > temporary-global-binding approach (or better temporary-object-binding
> > [as in temporarily overriding a buffer attribute]), but without special
> > forms like `with-` style macros it would look rather clumsily.
>
> Even if you did want to do this, it would hardly be clumsy to use a
> try ... finally.

Just compare:

    old_a = buffer.a
    old_b = buffer.b
    old_c = buffer.c
    try :
       buffer.a = fct_a(...)
       buffer.b = fct_b(...)
       buffer.c = fct_c(...)
       some_other_function(...)
    finally :
       buffer.a = old_a
       buffer.b = old_b
       buffer.c = old_c

with :

    (let ((a (fct-a ...))
          (b (fct-b ...))
          (c (fct-c ...)))
      (some-other-function ...))

Note, that you have to guarantee that all temporary changes are popped
before you leave the scope and that you might get exceptions from some
functions called to compute the temporary values.

Of course, you could provide `buffer.push_context/buffer.pop_context`
functions but note that the variables in question might not all be
buffer-local. In Elisp, you don't have to know where they come from
(which is just as well, because that changes over time).

-- 
Christian Tanzer                                         tanzer at swing.co.at
Glasauergasse 32                                       Tel: +43 1 876 62 36
A-1130 Vienna, Austria                                 Fax: +43 1 877 66 92






More information about the Python-list mailing list