evaluating file inside let - emacs

If my-variable is globally undefined, and my-file.el uses it,
;; -*- lexical-binding: t; -*-
(let((my-variable 1))
(load "/path/to/my-file.el"))
reports an error:
Debugger entered--Lisp error: (void-variable my-variable)
On the other hand,
;; -*- lexical-binding: t; -*-
(defvar my-variable 11)
(let((my-variable 1))
(load "/path/to/my-file.el"))
works using locally defined value 1.
Why do I have to use defvar?
PS: my-file.el can be a one-liner:
(1+ my-variable)

The file that the let is in is probably using lexical-binding, which means that for:
(let ((my-variable 1))
(load "/path/to/my-file.el"))
There is nothing in the lexical scope of my-variable which uses it.
If you byte-compiled the file, it would tell you:
Warning: Unused lexical variable ‘my-variable’
Adding the defvar marks it as a dynamic scope variable, in which case the code evaluated while my-file.el is being loaded will also see the let-bound value.
Note that (defvar my-variable) with no value is also sufficient to do that, and is what you should use if this isn't where the variable is supposed to be defined.

See Using Lexical Binding:
Lexical binding is also enabled in Lisp Interaction and IELM mode, used in the scratch and ielm buffers, and also when evaluating expressions via M-: (eval-expression) and when processing the --eval command-line options of Emacs (see Action Arguments in The GNU Emacs Manual) and emacsclient (see emacsclient Options in The GNU Emacs Manual).
So, if you evaluate the let in the *scratch* buffer, it uses lexical binding, which means the value of the variable is only bound to the lexical context, i.e. it isn't preserved when loading a different file.
Another possibility is you run it from an .el file with lexical binding turned on. If you turn it off, it should work the way you expected. Use the buffer local variable lexical-binding to enable or disable it.

[Not an answer but I did not want to edit the OP's question willy-nilly with what I see (and it's too long for a comment). I just provide a description of how I reproduce the problem since #choroba seems to get different results]
I have this in /tmp/my-file.el:
(if (= my-variable 1) (message "Yes") (message "N
I start emacs with emacs -Q and evaluate the following in the *scratch* buffer (sneaking in the version info):
(emacs-version '(4))
GNU Emacs 28.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.25, cairo version 1.16.0)
of 2021-03-07nil
(let ((my-variable 1))
(message (format "%d" my-variable))
(load "/tmp/foo.el"))
and I get the following backtrace:
Debugger entered--Lisp error: (void-variable my-variable)
(= my-variable 1)
(if (= my-variable 1) (message "Yes") (message "No"))
eval-buffer(#<buffer *load*> nil "/tmp/foo.el" nil t) ; Reading at buffer position 54
load-with-code-conversion("/tmp/foo.el" "/tmp/foo.el" nil nil)
load("/tmp/foo.el")
(let ((my-variable 1)) (message (format "%d" my-variable)) (load "/tmp/foo.el"))
(progn (let ((my-variable 1)) (message (format "%d" my-variable)) (load "/tmp/foo.el")))
eval((progn (let ((my-variable 1)) (message (format "%d" my-variable)) (load "/tmp/foo.el"))) t)
elisp--eval-last-sexp(t)
eval-last-sexp(t)
eval-print-last-sexp(nil)
funcall-interactively(eval-print-last-sexp nil)
call-interactively(eval-print-last-sexp nil nil)
command-execute(eval-print-last-sexp)
I get exactly the same result with the emacs that is packaged in my distro (Fedora 33): GNU Emacs 27.1 (build 1, x86_64-redhat-linux-gnu, GTK+ Version 3.24.22, cairo version 1.16.0) of 2020-08-20.

Related

How to evaluate Common Lisp code in non-slime buffers?

I'd like to be able to get my SBCL 1.4.5 (Linux x86_64)
Emacs 'inferior-lisp-process' to evaluate a S-Expression (sexp)
in some Emacs buffer that is not the 'slime' buffer - I have
latest quicklisp and slime-2.20 .
I thought this was exactly the same issue as in :
How to run Common Lisp code with Slime in Emacs Lisp
but it is not - my issue is that when I try to run 'slime-eval' or
any slime 'run in inferior-lisp-process' method ALL symbols seem to be
being looked up in ONLY in the SWANK-IO-PACKAGE namespace :
In my Emacs '*scratch*' buffer:
(slime-eval '(symbolp '+) "CL-USER")
Produces a backtrace error:
The function SWANK-IO-PACKAGE::SYMBOLP is undefined.
[Condition of type UNDEFINED-FUNCTION]
Restarts:
0: [CONTINUE] Retry calling SWANK-IO-PACKAGE::SYMBOLP.
1: [USE-VALUE] Call specified function.
2: [RETURN-VALUE] Return specified values.
3: [RETURN-NOTHING] Return zero values.
4: [*ABORT] Return to SLIME's top level.
5: [ABORT] abort thread (#<THREAD "worker" RUNNING {100262C8E3}>)
Backtrace:
0: ("undefined function" SWANK-IO-PACKAGE::+)
1: (SB-INT:SIMPLE-EVAL-IN-LEXENV \
(SWANK-IO-PACKAGE::SYMBOLP (QUOTE SWANK-IO-PACKAGE::+)) \
#<NULL-LEXENV>)
2: (EVAL (SWANK-IO-PACKAGE::SYMBOLP (QUOTE SWANK-IO-PACKAGE::+)))
It makes no difference whether I do :
(slime-eval '(symbolp :+) "CL-USER")
OR
(slime-eval '(symbolp '+))
I still get the same error because '+ and :+ are
always looked up only in the SWANK-IO-PACKAGE namespace.
I found this by simply trying to run, for my first test:
(slime-eval '(+ 2 2) "CL-USER")
which prints in the output buffer another backtrace
The function SWANK-IO-PACKAGE::+ is undefined.
[Condition of type UNDEFINED-FUNCTION]
I did try the code snippet from Question #22456086 :
(require 'slime)
(defun slrepl (str)
"Eval STR as Common Lisp code."
(unless (slime-current-connection)
(let ((wnd (current-window-configuration)))
(slime)
(while (not (and (slime-current-connection)
(get-buffer-window (slime-output-buffer))))
(sit-for 0.2))
(set-window-configuration wnd)))
(let (deactivate-mark)
(cadr (slime-eval `(swank:eval-and-grab-output ,str)))))
So doing:
(slrepl '(symbol-function '+))^X^E
Still results in :
The function SWANK-IO-PACKAGE::SYMBOL-FUNCTION is undefined.
[Condition of type UNDEFINED-FUNCTION]
Access to the default SB_INT namespace seems to be denied .
How to enable it for such cases ?
I'd like to be able to send forms to and read results from the same emacs inferior-lisp-process (sbcl) from any buffer, not just from the slime
'slime repl sbcl' buffer . Is there any way to do this?
Obviously, I can write an Emacs Lisp function to switch-to the
slime repl buffer and evaluate in that buffer.
Of course, all the above examples, eg. (eval '(symbolp '+)) ,
work fine in the slime-repl buffer. I guess there is no way
around switching-to the slime-repl buffer?
This might clarify:
In 'scratch' :
(slime-eval '(SB-INT:symbolp 'SB-INT:+) "CL-USER")^X^E
In slime output buffer:
Invalid protocol message:
The symbol "SYMBOLP" is not external in the SB-INT package.
Line: 1, Column: 26, File-Position: 26
Stream: #<SB-IMPL::STRING-INPUT-STREAM {1002A1CD63}>
(:emacs-rex (SB-INT:symbolp (quote SB-INT:+)) "CL-USER" t 78)
So, in the slime-repl buffer, I can do:
CL-USER> (PROGN (IN-PACKAGE "COMMON-LISP-USER") (+ 2 2))
4
CL-USER> (PROGN (IN-PACKAGE "SB-IMPL") (symbol-function '+))
#<FUNCTION +>
CL-USER> (PROGN (IN-PACKAGE "SB-IMPL") (symbol-function '+))
#<FUNCTION +>
SB-IMPL> (PROGN (IN-PACKAGE "SB-INT") (symbol-function '+))
#<FUNCTION +>
But if I try to run the same 'slime-eval' function in any
other buffer, eg. 'scratch' :
(slime-eval '(PROGN (COMMON-LISP-USER:IN-PACKAGE "COMMON-LISP-USER")
(symbol-function '+)) :COMMON-LISP-USER)
Invalid protocol message:
The symbol "IN-PACKAGE" is not external in the
COMMON-LISP-USER package.
Line: 1, Column: 46, File-Position: 46
I have tried ALL the likely PACKAGE names listed above in the
slime-eval with same results.
The same thing happens whether I use the 'slrepl' code snippet or just plain
slime-eval - no lisp standard syntax symbols are available. Do I need to
load the lisp syntax table or something ?
RE: can I switch to slime repl buffer and do it ? : NO ! :
(require 'slime)
(let ((slbuf (get-buffer "*slime-repl sbcl*")))
(if (eq nil slbuf)
(error "please start slime (M-x slime)")
(progn (set-buffer slbuf)(slime-eval '(+ 2 2) "COMMON-LISP-USER"))
)
)^X^E
Still results in :
The function SWANK-IO-PACKAGE::+ is undefined.
[Condition of type UNDEFINED-FUNCTION]
I am a rusty / returning LISP user and new to SBCL and slime .
I'd really like to integrate Emacs' great Editing and File management
& interacation facilitties with external CL XML & HTML generation & parsing
tools. But to start, I'd just like to get to the root of this problem...
Common Lisp symbols like + and symbolp are in the COMMON-LISP package. Short name CL. These symbols are usually not exported from package CL-USER. Thus symbolp can be referenced as cl:symbolp. These symbols are accessible in package CL-USER, but not exported from there. Thus you can also reference cl:symbolp as cl-user::symbolp -> note the two colons.
CALLING IN-PACKAGE in a form does not have an effect on the form itself, since the form is already read. Though it has an effect calling reader functions or functions like find-symbol.
CL-USER 5 > (defpackage "FOO" (:use))
#<The FOO package, 0/16 internal, 0/16 external>
CL-USER 6 > (progn (in-package "FOO")
(list 'bar (read-from-string "BAR")))
(COMMON-LISP-USER::BAR BAR) ; we now print from package "FOO"
Using SLIME-EVAL in Emacs Lisp
Best use it with a form, that reads the expression on the Common Lisp side and does not involve the Emacs Lisp reader/printer:
ELISP> (slime-eval '(cl:eval (cl:read-from-string "(+ 1 2)")) "CL-USER")
3 (#o3, #x3, ?\C-c)
ELISP> (slime-eval '(cl:eval (cl:read-from-string "'foo")) "CL-USER")
common-lisp-user::foo
But here you see that the result is brought back into Emacs Lisp via the Emacs Lisp reader - where packages don't exist.
Thus SLIME-EVAL makes very little sense as a simple remote execution interface...
This now works! Thanks !
(require 'slime)
(defun CL$ (str)
(let ((slbuf (get-buffer "*slime-repl sbcl*")))
(if (eq nil slbuf)
(error "Please start slime (M-x slime).")
(progn
(set-buffer slbuf)
(slime-eval str "CL")
)
)
)
)
(CL$ '(cl:+ 2 2))
=> 4
But I don't fully understand why I have to prepend all symbols with CL or
why this still does not work:
(slime-eval '(+ 2 2) "CL")
but this does:
(slime-eval '(cl:+ 2 2) "CL")
I thought the third parameter was meant to be made into the current package?
So why do I have to append 'cl' to every symbol .
But thanks for the help, and an otherwise great slime + sbcl .

Symbol's function definition is void: gst Emacs 24.5 smalltalk-mode [duplicate]

i want to use a new comint mode for plink(putty), i put the code in init.el, but if M-x run-plink, i got below error:
let*: Symbol's function definition is void: comint-check-proc
;; path
(defvar plink-file-path "C:/Programme/Putty/plink.exe"
"Path to the program used by `run-plink'")
;; arguments
(defvar plink-arguments '()
"Commandline arguments to pass to `plink'")
;; prompt
(defvar plink-prompt-regexp "^>\s"
"Prompt for `run-plink'.")
;; Run-plink
(defun run-plink ()
"Run an inferior instance of `plink.js' inside Emacs."
(interactive)
(setq plink-buffer "*Plink*")
(let* ((plink-program plink-file-path) (buffer (comint-check-proc "Plink")))
;; pop to the "*plink*" buffer if the process is dead, the
;; buffer is missing or it's got the wrong mode.
(pop-to-buffer-same-window
(if (or buffer (not (derived-mode-p 'plink-mode))
(comint-check-proc (current-buffer)))
(get-buffer-create (or buffer "*Plink*"))
(current-buffer)))
;; create the comint process if there is no buffer.
(unless buffer
(apply 'make-comint-in-buffer "Plink" buffer plink-program plink-arguments)
(plink-mode))))
;; plink-mode
(define-derived-mode plink-mode comint-mode "plink" nil "plink"
(setq comint-process-echoes t)
(setq comint-use-prompt-regexp t)
(setq comint-prompt-regexp plink-prompt-regexp)
; ">" read-only
(setq comint-prompt-read-only t)
(set (make-local-variable 'paragraph-separate) "..'")
(set (make-local-variable 'paragraph-start) plink-prompt-regexp))
You have not loaded library comint. You need to do that before Emacs can know about comint-check-proc.
Add a (require 'comint), either in your init file or near the beginning of run-plink - somewhere before it tries to use comint-check-proc.
To give this question an answer, which is also meaningful for other questions marked as duplicates of this one, but actually are about other packages not being loaded, I will give a more general answer, which should be applicable to the other questions as well.
Generally an error Symbol's function definition is void often indicates, that a package was not loaded, but then someone/something tried to use it.
So the general answer, that you probably need to (require '<package name>) in your init.el, where the package name is the name of the package which provides what is currently void.

new comint mod in emacs for plink (putty): Symbol's function definition is void

i want to use a new comint mode for plink(putty), i put the code in init.el, but if M-x run-plink, i got below error:
let*: Symbol's function definition is void: comint-check-proc
;; path
(defvar plink-file-path "C:/Programme/Putty/plink.exe"
"Path to the program used by `run-plink'")
;; arguments
(defvar plink-arguments '()
"Commandline arguments to pass to `plink'")
;; prompt
(defvar plink-prompt-regexp "^>\s"
"Prompt for `run-plink'.")
;; Run-plink
(defun run-plink ()
"Run an inferior instance of `plink.js' inside Emacs."
(interactive)
(setq plink-buffer "*Plink*")
(let* ((plink-program plink-file-path) (buffer (comint-check-proc "Plink")))
;; pop to the "*plink*" buffer if the process is dead, the
;; buffer is missing or it's got the wrong mode.
(pop-to-buffer-same-window
(if (or buffer (not (derived-mode-p 'plink-mode))
(comint-check-proc (current-buffer)))
(get-buffer-create (or buffer "*Plink*"))
(current-buffer)))
;; create the comint process if there is no buffer.
(unless buffer
(apply 'make-comint-in-buffer "Plink" buffer plink-program plink-arguments)
(plink-mode))))
;; plink-mode
(define-derived-mode plink-mode comint-mode "plink" nil "plink"
(setq comint-process-echoes t)
(setq comint-use-prompt-regexp t)
(setq comint-prompt-regexp plink-prompt-regexp)
; ">" read-only
(setq comint-prompt-read-only t)
(set (make-local-variable 'paragraph-separate) "..'")
(set (make-local-variable 'paragraph-start) plink-prompt-regexp))
You have not loaded library comint. You need to do that before Emacs can know about comint-check-proc.
Add a (require 'comint), either in your init file or near the beginning of run-plink - somewhere before it tries to use comint-check-proc.
To give this question an answer, which is also meaningful for other questions marked as duplicates of this one, but actually are about other packages not being loaded, I will give a more general answer, which should be applicable to the other questions as well.
Generally an error Symbol's function definition is void often indicates, that a package was not loaded, but then someone/something tried to use it.
So the general answer, that you probably need to (require '<package name>) in your init.el, where the package name is the name of the package which provides what is currently void.

How can I get syntax highlighting for common lisp in SLIME's REPL?

I want to learn Common Lisp and have installed emacs (24.3) and slime via the emacs package manager.
In the slime REPL syntax highlighting doesn't work. When I start Lisp-Mode (while in the slime REPL) on the other hand, the values of the expressions don't get printed anymore (when I type, say "Hello World" and hit enter I get a new line instead of the value of the expression.
(If I open lisp files syntax highlighting works)
this works for me
(https://comp.emacs.narkive.com/AWoywbFs/tweaking-slime):
(defvar slime-repl-font-lock-keywords lisp-font-lock-keywords-2)
(defun slime-repl-font-lock-setup ()
(setq font-lock-defaults
'(slime-repl-font-lock-keywords
;; From lisp-mode.el
nil nil (("+-*/.<>=!?$%_&~^:#" . "w")) nil
(font-lock-syntactic-face-function
. lisp-font-lock-syntactic-face-function))))
(add-hook 'slime-repl-mode-hook 'slime-repl-font-lock-setup)
(defadvice slime-repl-insert-prompt (after font-lock-face activate)
(let ((inhibit-read-only t))
(add-text-properties
slime-repl-prompt-start-mark (point)
'(font-lock-face
slime-repl-prompt-face
rear-nonsticky
(slime-repl-prompt read-only font-lock-face intangible))))))

Emacs: the code in the body of a defun or defmacro cannot refer to surrounding lexical variables?

Update 2013 May: As of GNU Emacs 24.3.1, (let .. (defun..)) bytecompiles just fine without warning and the bytecompiled code works the same as not-compiled code. Just don't forget to add the file variable lexical-binding: t to the file to be bytecompiled. Workarounds at the end of this question is now not necessary.
Lexical Binding - Emacs Lisp Manual has this paragraph:
Note that functions like symbol-value, boundp, and set only retrieve or modify a variable's dynamic binding (i.e. the contents of its symbol's value cell). Also, the code in the body of a defun or defmacro cannot refer to surrounding lexical variables.
I am not sure if I am getting the meaning of the second sentence right. In the following code which should be run in lexical binding mode, the code in the body of a defun is successfully referring to the lexical binding value of the name n.
(let ((n 0))
(defun my-counter ()
(incf n)))
(my-counter) ;; 1
(my-counter) ;; 2
Is the sentence simply saying that (let .. (defun ..)) is a bad practice?
Workarounds:
;; -*- lexical-binding: t -*-
;; a way to define the counter function without byte-compile error or warning
(defvar my--counter-func
(let ((n 0))
(lambda ()
(setq n (1+ n)))))
(defun my-counter ()
(funcall my--counter-func))
;; another way to define the counter function, again without byte-compile error or warning
(fset 'my-another-counter
(let ((n 0))
(lambda ()
(setq n (1+ n)))))
And here's the code for testing the above code:
;; run:
;; emacs -q --load path-to-the-el-file-of-this-code.el
(load "path-to-file-defining-my-counter.elc") ;; loading the ELC file to test if byte-compiled code runs as expected.
(print (my-counter)) ;; 1
(print (my-counter)) ;; 2
(print (my-another-counter)) ;; 1
(print (my-another-counter)) ;; 2
The code does not byte-compile well at least in Emacs 24.1.1. I saved the following code in the foo.el file, which uses setq in place of incf in order to avoid any possible effects by the cl library:
;; -*- lexical-binding: t -*-
(let ((n 0))
(defun my-counter ()
(setq n (1+ n))))
When I tried to byte-compile it (M-x byte-compile-filefoo.el), I got the following warning messages:
foo.el:3:1:Warning: Function my-counter will ignore its context (n)
foo.el:3:1:Warning: Unused lexical variable `n'
foo.el:5:11:Warning: reference to free variable `n'
foo.el:5:17:Warning: assignment to free variable `n'
All of the messages are indicating that the code in the body of the defun construct cannot refer to the surrounding lexical variable n as the manual claims.
Actually, when I loaded the byte-compiled code (M-x load-filefoo.elc) and evaluted the (my-counter) form, I got the following erorr:
Debugger entered--Lisp error: (void-variable n)
...
Unfortunately, I'm not sure why the code appears to work when evaluated in the form of source code.
As I replied on gnu.emacs.help, you can use (defalias 'foo (lambda ...)) to work around that limitation.
And that limitation is lifted in Emacs's development code.
It's perfectly fine to refer to variables in lexical scope(*) from within a defun, just as you are doing above, and just as the "my-ticker" example on that manual page does as well.
Either I am missing something the line in the manual that says:
the code in the body of a defun or defmacro cannot refer to
surrounding lexical variables.
should say something more like:
code in the body of a defun can only access lexical variables if they are defined within the same lexical scope.
NOTE: There are comments in the other answers about problems byte-compiling this kind of code. Those should be fixed in the latest emacs. I've verified in v24.2.50.1 that this byte compiles and loads correctly.