"Hot swapping" code with swank clojure, and crash resilience - clojure

I've been messing around with developing a game in clojure, and one thing I've been really excited about is hot swapping in code.
I've been using swank clojure and emacs with the lein-swank plugin.
My main problem has been that of typos. Say I update a function, make a small error, and then hit Ctrl-C Ctrl-C to send it off to the REPL:
(if (> (rand) .5) (println "yay") (println "boo"))
(I should have written 0.5, not .5.)
In that case, the entire program will simply crash and burn, and I'll need to restart the whole thing. Hot swapping is great, but if I can't make even a tiny error then what's the point?
So what exactly is the workflow here? Am I missing something? Or is there a way to make swank clojure more resilient to these little errors? (I imagine that the best thing would simply be to reset to a previous working state, although that may be a little difficult.)
Thanks!

The program shouldn't “crash and burn”—it should raise an exception and throw you into the debugger, which you can dismiss by hitting Q (sldb-quit). After dismissing the debugger, the program is supposed to continue running normally. If this is not what happens, your SLIME configuration is probably broken somehow.

Personally I recommend C-M-x over C-c C-c. I don't think either one should have the problem you're experiencing, though, so switching may not fix it.

Related

Is there a way to store and retrieve the history of shadow-cljs' REPL over different sessions? How to use commands used in previous sessions?

I am using Emacs, CIDER, and shadow-clj/shadow-cljs to develop a project
in Clojure/ClojureScript. All this in a macOS Monterey 12.5.
Before that, I was used to programming with Emacs, Slime, Common Lisp, and SBCL.
Sometimes, I want to have a similar UX in this new lisp environment similar to my
previous experience on the other lisp land.
I am having multiple hassles (as expected) and pains with the new environment.
One thing, in particular, has been quite annoying.
After executing cider-jack-in-cljs, shadow-cljs, shadow (REPL),
and app (for the build), the REPL does not "remember" the
previous session. I can't access the commands that I executed before quitting. It only remembers the commands executed on the current session. This is hindering my interactive programming productivity.
In Slime, this was possible! And quite handy.
Moreover, after executing describe-mode in Emacs, I have:
Enabled minor modes: Auto-Composition Auto-Compression Auto-Encryption
Column-Number Counsel-Projectile Delete-Selection Display-Line-Numbers
Doom-Modeline Eldoc Electric-Indent File-Name-Shadow Font-Lock
Global-Auto-Revert Global-Display-Line-Numbers Global-Eldoc
Global-Font-Lock Ivy-Prescient Ivy-Rich Line-Number Override-Global
Paredit Projectile Rainbow-Delimiters Recentf Save-Place Savehist
Shell-Dirtrack Show-Paren Transient-Mark Which-Key Wrap-Region
Wrap-Region-Global
(Information about these minor modes follows the major mode info.)
REPL[cljs] mode defined in ‘cider-repl.el’:
Major mode for Clojure REPL interactions.
Inside Cider Major mode, I have the command bellow fully working:
C-c M-p cider-repl-history
But, it works only for current session.
In addition, an user suggested that maybe cider-repl-history-mode was not enabled. Indeed, it seems that it has not been enabled - since I can't see it.
If I try to execute the command cider-repl-history-mode a weird thing happens ParEdit appears indicating a problem in parenthesis and the mini buffer echoes:
paredit-mode: Unmatched bracket or quote
This is really weird because although ParEdit is related to Clojure, it seems unrelated to Cider for the case in hand.
Is there some way to preserve CIDER's REPL's history over sessions?
Use cider-repl-backward-input and cider-repl-forward-input to go forward and backward in command history over sessions.
See CIDER // docs - REPL history browser.

cl-opengl under SLIME on MacOS crashing SBCL... bug?

I'd like to do some OpenGL programming in Common Lisp, under Emacs and SLIME. I'm not set on it, but I'm currently trying to use SBCL. If I open up emacs from the start, create a new file with just this one line:
(ql:quickload :cl-opengl)
And then I do M-x slime (and wait for it to load), followed by C-c C-c to compile and run that line, SBCL crashes immediately, every time, prompting a dialog box that says sbcl quit unexpectedly:
I've saved the output that's accessible by clicking the "Report..." button; if that's useful, I can add that here (or put it on pastebin or something)... the short version is it's getting a SIGTRAP.
This happens every time I try to run this under SLIME... but, interestingly, it doesn't happen if I run SBCL from the command-line.
So, the question: Is this a bug in SBCL? In cl-opengl? Something I have mis-configured? Other? Any insights would be greatly appreciated.
Note:
I've done some google searching, and I found a page which provides a workaround of putting the following in ~/.swank.lisp:
(setf swank:*communication-style* :fd-handler)
Indeed, that gets me past the immediate crash, and gets me able to do some work. If that's simply the answer, someone please post it as an answer with an explanation of why that's the thing to do, so that others may find it. Otherwise, I'm imagining this to be a bug, though, that could be fixed, rather than worked around... and/or at least something that I could be helped to better understand; I still don't have a responsive REPL with my current code (basically on brian's brain, as a test case) running (via run), which may or may not be a separate question? Did changing the swank config change that situation for me?
Platform details:
OS: MacOS 10.6.8
SBCL: sbcl#1.1.10_0+fancy from MacPorts; launch header This is SBCL 1.1.10, an implementation of ANSI Common Lisp.
Emacs: macports-installed Emacs Version 24.3 (9.0) (per the GUI about window, or GNU Emacs 24.3.1 (x86_64-apple-darwin10.8.0, NS apple-appkit-1038.36) of 2013-04-07 per M-x version, or the emacs-app#24.3_1 port)
Slime: slime#20130630 from MacPorts
It sounds like a thread support issue with SWANK
The :fd-handler option changes the way SWANK communicates from the default, which is to use separate threads for communication, to using a loop approach (http://www.common-lisp.net/projects/slime/doc/html/Communication-style.html).
There used to be quite a few complaints about using SBCL with threading on Mac OS, these were largely fixed from the look of it; maybe SWANK is having similar issues?
I'm not 100% sure this is the sole cause of your problems, but it's the best explanation I could find.
I have been looking through my setup to see what was different
OS X 10.9
SBCL 1.1.8.0-19cda10
slime-20131003
But the most likely offender is still slime/swank.
I really recommend using quicklisp to manage your slime setup rather than macports, this will keep both slime and swank in sync and up to date. I've been using slime this way for a year or two and have had no issues so far.
From the quicklisp page:
To install and configure SLIME, use:
(ql:quickload "quicklisp-slime-helper")
Then follow the directions it displays. quicklisp-slime-helper will
create a file you can load in Emacs that configures the right
load-path for loading Quicklisp's installation of SLIME
I also made a small video showing how to install emacs+sbcl+quicklisp+slime under windows. The slime part is still relevant on all platforms.
Hope it helps.

CL-OPENGL: "Aborted" on translate

While writing a simple game using SBCL, CL-OPENGL, and Lispbuilder-SDL, I can across a strange error. Soon after I got the game working, I decided to clean out all my debugging cruft (print statements, etc). I did so, but when I ran the game afterwards I received the message "Aborted" and my entire Lisp process died, with no other error message and no debugger prompt. Using print statements I managed to isolate the problem to a call to gl:translate. The strange thing is, if I put a break statement before that line and attempt to single-step, I receive no error and the code runs fine. Seems like a race condition almost, but I'm not using threads. Any ideas?
EDIT: It appears that the call to gl:translate isn't the problem. If I do something like the following:
(print 'first)
(print 'second)
(gl:translate ...)
I get the output
FIRST
Aborted
Like I said, I'm not using threads.
EDIT 2:
It works in CLisp.
EDIT 3:
Nevermind, it doesn't.
I fixed it by switching back to pure SDL, which is disappointing, but it works.

Forcing Cake to reload functions from my .clj files

I'm new to Clojure, and after too much of my life have been already wasted on waiting for Leiningen to run my code, I'm trying to move to Cake. While Cake's persistent JVM loads up blazing fast - it presents a bigger problem - my functions are also persistent!
To demonstrate the problem, I've started a cake project(using cake new mess-up-with-cake), and wrote this in core.clj:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
)
(println "I'm in core.clj, not inside in any function")
And this is project.clj:
(defproject mess-up-with-cake "0.0.1-SNAPSHOT"
:description "TODO: add summary of your project"
:dependencies [[clojure "1.2.0"]])
(use 'mess-up-with-cake.core)
(deftask my-task
(println "I'm in my task")
(main-function)
)
When running it with cake my-task, I get:
I'm in core.clj, not inside in any function
I'm in my task
I'm in the main function
No surprise here.
Now, I've changed core.clj to this:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
(println "I've made a change in the main function")
)
(println "I'm in core.clj, not inside in any function")
(println "I've made a change outside the main function")
And when I run it, I get
I'm in core.clj, not inside in any function
I've made a change outside the main function
I'm in my task
I'm in the main function
core.clj was clearly reloaded, but the change I've made inside the main function was not printed! Only when I stop the JVM with cake kill and rerun it I get the desired result - but if I have to restart the JVM every time I change a function, I might as well go back to lein...
Any idea how to force cake to reload my functions(and only my functions - reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM..)?
This may not directly answer your question, though I hope it helps:
It sounds like your workflow if you where using leiningen would be to run:
lein run
wait for the JVM to start up .... get bored ...
observe result
edit code
repeat
This is a very common pattern in most languages and it's occasionally used for Clojure development (and Cake is very helpful here). It is much more common for Clojure development to use a single instance of the project and connect the editor to that instance using nrepl (or Slime and Swank). Because most everyone leaves the project running while they do the development not many people feel this pain and so the solutions are not as good in my opinion. Cake has largely been merged into Leiningen and the future direction of the Cake project is not clear to me (I could very well be wrong on this point). Of the Clojureians I know, all of them have moved to Leiningen and connect to their project from an editor like Emacs or vim.
a common workflow is:
start Emacs
M-x nrepl-jack-in
Ctrl-c Crtl-l to reload all the namespace and all it's dependent namespaces (this is close to a solution to your problem)
hack, load, repeat ;-)
This workflow is not Emacs or VI specific, the same method is used from Eclipse and Intelij
re: " reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM".
I find it to be no more than two seconds even with my larger projects
I used to struggle with the slow JVM startup speed as well, and had mixed success with Cake. You might want to take a look at the excellent autoexpect plugin for Leiningen, explained in some length in the author's blog post. Basically autoexpect reloads your code every time the working directory tree is updated (and evaluates any expect clause, reporting any test failures). Makes continuous testing a dream -- I sometimes have two shells going in Emacs -- one for the output of lein autoexpect, one for a connected REPL to send snippets of code to as the other poster is suggesting.
I like the continuous testing style so much I wrote a similar utility in Python for my non-Clojure development (described in this blog post) -- for Clojure, I use autoexpect.

read-line not working in clojure REPL

Whenever I call a clojure function that gets a users' console input using (read-line) through SLIME or a normal REPL, the function returns immediately. I've resorted to jar'ing up my project and running it to test but this obviously isn't quick or sustainable.
Is there some trick to getting console interaction through a REPL working or is it not possible? If not are there any good workarounds?
This will work now with swank-clojure 1.4.0-SNAPSHOT if you wrap the call to read-line in swank.core/with-read-line-support like this
(with-read-line-support (println "a line from Emacs:" (read-line))
https://github.com/technomancy/swank-clojure/commit/f4a1eebc4d34f2ff473c4e5350f889ec356f5168
Currently there doesn't seem to be any way of reading console input through swank-clojure; calling (read-line) simply returns nil in 1.4.0-SNAPSHOT and hangs in earlier versions. Installing 1.4.0 as a user-level leiningen plugin seems to be the best bet right now. At least the REPL will return to your control at some point.