[Python-ideas] Ruby-style Blocks in Python Idea
Guido van Rossum
guido at python.org
Wed Mar 11 15:26:29 CET 2009
On Tue, Mar 10, 2009 at 10:05 PM, Stephen J. Turnbull
<stephen at xemacs.org> wrote:
> Guido van Rossum writes:
> > I'm feeling really dense right now -- I still don't see the difference
> > between the two. Are you saying that you would prefer an expression
> > that creates a *named* function? That seems to be really bizarre --
> > like claiming that you don't like expressions that return anonymous
> > numbers.
> Here's a use-case from Emacs. Various modes have callbacks so that
> users can customize them. A typical case is that a text-mode hook
> will turn on auto-fill-mode, which is documented as an example to be
> done like this:
> (add-hook 'text-mode-hook (lambda () (auto-fill-mode 1)))
> where *-mode functions called with nil toggle the mode, positive
> numbers turn it on, and non-positive numbers turn it off. The
> add-hook function is supposed to be idempotent: it won't add the same
> hook function if it is already in the hook. The problem is if you
> change the lambda and execute that form, the changed lambda is now not
> identical to the lambda on the hook, so the old version won't be
> removed. This
> (add-hook 'text-mode-hook (defun turn-on-auto-fill () (auto-fill-mode 1)))
> neatly avoids the problem by returning the name of the function, the
> symbol `turn-on-auto-fill', which is callable and so suitable for
> hanging on the hook. If you change the definition and execute the
> above form, add-hook *mutates nothing* (the symbol is already
> present), but because the hook is indirect through the function's
> symbol and the defun *is* executed, the definition changes ... which
> is exactly what you want.
Got it -- sort of like using assignment in an expression in C, to set
a variable and return the valule (but not quite, don't worry :-).
> AMK's use-case could be post-processed as something like
I assume you're talking about Andrew Koenig's use case -- ANK is
Andrew Kuchling, who AFAIK didn't participate in this thread. :-)
> (let ((i 0))
> (mapcar (lambda ()
> (let ((name (intern (format "foo-%d-callback" i))))
> (define-function name (aref slots i))
> (aset slots i name)
> (setq i (1+ i))
IIUC (my Lisp is very rusty) this just assigns unique names to the
functions right? You're saying this to satisfy the people who insist
that __name__ is always useful right? But it seems to be marginally
useful here since the names don't occur in the source. (?)
> where slots is the vector of anonymous functions. Providing names in
> this way costs one indirection per callback invocation in Emacs Lisp,
> but the benefits in readability of tracebacks are large, especially
> for compiled code.
> > I don't see the conceptual difference between a "def-expression" (if
> > it were syntactically possible) and a lambda-expression. What is the
> > difference in your view? Are you sure that difference exists? (It
> > wouldn't be the first time that people ascribe powers to lambda that
> > it doesn't have. :-)
> AIUI, a def-expression binds a callable to an object, while a lambda
> expression returns a callable. An anonymous def is just lambda by a
> different name (and I think the code block proponents agree, based on
> their willingness to accept syntax using def instead of lambda).
> I don't see how the kind of thing exemplified above would be useful in
> Python, and from a parallel reply I just saw, I gather Jim agrees.
> The point is to show how a function-defining expression can be useful
> in some contexts. This works in Emacs Lisp because in
> (setq foo (lambda ...))
> tools (including the Lisp interpreter) will not recognize foo as a
> function identifier although its value is a function, while
> (defun foo ...)
> marks foo as a function identifier. But in Python (like Scheme)
> they're basically the same operation, with a little syntactic sugar.
> Anything that is based on the separation of variable namespace from
> function namespace is DOA, right?
Right, and so are separations between value and type namespaces (as
other languages use, e.g. C++ and Haskell).
> The renaming mapper is a different issue, I think; it depends on
> computing object names at runtime (ie, the Lisp `intern' operation),
> not on separate namespaces. I'm not sure offhand how to do that in
> Python, or even it it's possible; I've never wanted it.
You can assign new values to to f.__name__.
>  N.B. Of course modern Emacsen define turn-on-auto-fill as a
> standard function. But this is ugly (because of the single flat
> namespace of Emacs Lisp), and not all modes have their turn-on,
> turn-off variants. auto-fill-mode was chosen because (a) the
> semantics are easy to imagine and (b) the use of lambda in a hook is
> explained by exactly this example in the Emacs Lisp Manual.
--Guido van Rossum (home page: http://www.python.org/~guido/)
More information about the Python-ideas