emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: interactive closure — variables not bound


From: Ricardo Wurmus
Subject: Re: interactive closure — variables not bound
Date: Wed, 28 Sep 2016 23:12:08 +0200
User-agent: mu4e 0.9.16; emacs 25.1.1

Stefan Monnier <address@hidden> writes:

>> The problem with this definition is that it doesn’t work (the other
>> problem is that I’m replacing one ugly hack with another).  At runtime
>> Emacs says that “field-type” is undefined.  At compile time Emacs says
>> that in the callback “xww”, “field-value”, and “field-type” are
>> references to free variables.
>
> Indeed, currently, the `interactive' spec can't be re-created
> individually for every closure.  IOW the spec is built once and forall
> for a given lambda expression and hence can't refer to surrounding
> non-global variables.
>
> I suggest you M-x report-emacs-bug.

Okay, I will report a bug.

> This said, in your example, I don't see what benefit you expect to get
> from writing
>
>          (call-interactively
>           (lambda (str)
>             (interactive
>              (list (cond ((equal "text" field-type)
>                           (read-string "Text: " field-value))
>                          ((equal "password" field-type)
>                           (read-passwd "Password: " nil field-value))
>                          ((equal "textarea" field-type)
>                           (xwidget-webkit-begin-edit-textarea xww 
> field-value)))))
>             (xwidget-webkit-execute-script
>              xww
>              (format "findactiveelement(document).value='%s'" str)))))))))
>
> instead of
>
>          (let ((str (cond ((equal "text" field-type)
>                            (read-string "Text: " field-value))
>                           ((equal "password" field-type)
>                            (read-passwd "Password: " nil field-value))
>                           ((equal "textarea" field-type)
>                            (xwidget-webkit-begin-edit-textarea xww 
> field-value)))))
>           (xwidget-webkit-execute-script
>            xww
>            (format "findactiveelement(document).value='%s'" str)))))))))

I’ve tried this first and I’m getting unexpected behaviour.  Emacs
prompts for a string in the minibuffer as expected, but the process
becomes *very* busy, stays at 100% CPU usage, grows in memory, and key
presses are registered extremely slowly.  Emacs becomes unusable at this
point.  I cannot even abort this with C-g and have to kill Emacs.

The C code is pretty straight forward:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DEFUN ("xwidget-webkit-execute-script", …)
  (Lisp_Object xwidget, Lisp_Object script, Lisp_Object fun)
{
  …
  CHECK_STRING (script);
  if (!NILP (fun) && (!FUNCTIONP (fun)))
    wrong_type_argument (Qinvalid_function, fun);
  …

  // This runs the JavaScript SCRIPT and then calls the C procedure
  // `webkit_javascript_finished_cb', passing FUN.
  webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (xw->widget_osr),
                                  SSDATA (script),
                                  NULL,
                                  &webkit_javascript_finished_cb,
                                  (gpointer) fun);
  return Qnil;                                  
}

…

static void
webkit_javascript_finished_cb (GObject      *webview,
                               GAsyncResult *result,
                               gpointer      lisp_callback)
{
  …
  Lisp_Object lisp_value = … /* JavaScript return value */
  …
  
  // Run the Lisp callback, passing the converted JavaScript return value
  call1 ((Lisp_Object)lisp_callback, lisp_value);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I.e., a user calls `xwidget-webkit-execute-script' with a script and a
lisp callback, the script is executed.  When the script is done, a C
callback will be invoked with a reference to the Lisp_Object holding the
lisp callback.  All that does is retrieve the JS return value and pass
it to the lisp callback.

I guessed that this odd behaviour must be a result of calling the
callback procedure from C with “call1”.  I thought that maybe this is
expected behaviour when calling a procedure that interacts with the user
through the mini-buffer (as read-string does) when it is not using the
“interactive” form.

Is this a bug?  (It looks and buzzes like one…)
Or am I doing something stupid?

> [ Oh, and while I'm here, let me advertize pcase:
>
>      (let ((str (pcase field-type
>                   ("text" (read-string "Text: " field-value))
>                   ("password" (read-passwd "Password: " nil field-value))
>                   ("textarea" ...
>
> ]

Nice!  I’ll keep it in mind.

~~ Ricardo




reply via email to

[Prev in Thread] Current Thread [Next in Thread]