swank-clj 0.1.0 - a refactored swank-clojure, with sldb support

78 views
Skip to first unread message

Hugo Duncan

unread,
May 11, 2011, 11:31:08 AM5/11/11
to clo...@googlegroups.com
For the intrepid, the first release of swank-clj is out.

This is a refactored swank-clojure, and features sldb integration.

Some highlights:

* line based breakpoints
* stepping
* exception restarts

See the readme at https://github.com/hugoduncan/swank-clj

--
Hugo Duncan

George Jahad

unread,
May 21, 2011, 2:09:24 PM5/21/11
to Clojure
just watched the video: http://vimeo.com/23932914

looks awesome!

Sam Aaron

unread,
May 22, 2011, 4:59:24 PM5/22/11
to clo...@googlegroups.com
Very cool!

Out of interest, how do swank-clj and swank-clojure (with merged in cdt stuff) compare?

Sam

---
http://sam.aaron.name

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

Jason Wolfe

unread,
May 22, 2011, 6:09:50 PM5/22/11
to Clojure
Looks really awesome -- I've been waiting for this since I switched to
Clojure from CL!

I played around with it a bit, and there are a couple issues that
prevent it from being usable out of the box for me.

1. The usual repl entry point is not used, and so, e.g., (set! *warn-
on-reflection* true) fails.

2. I could not figure out a way to browse exception chains.
Typically the "real" stack trace for an exception is reached by
repeatedly calling .getCause on the exception until the innermost
exception is reached, but right now I can't see how to access causes
in the swank-clj debugger. For example try:

(defn foo [x] (map - x))
(foo (for [x (range 10)] (if (= x 8) "foo" x)))

to see a useless stack trace (in 1.2). I see a couple places in the
code that deal with causes, so maybe I'm just missing how to access
them?

If you want, I'm happy to help out on these. Thanks for the great
work!

-Jason

On May 11, 8:31 am, "Hugo Duncan" <duncan.h...@gmail.com> wrote:
> For the intrepid, the first release of swank-clj is out.
>
> This is a refactored swank-clojure, and features sldb integration.
>
> Some highlights:
>
> * line based breakpoints
> * stepping
> * exception restarts
>

Ken Wesson

unread,
May 22, 2011, 10:15:17 PM5/22/11
to clo...@googlegroups.com
On Sun, May 22, 2011 at 6:09 PM, Jason Wolfe <ja...@w01fe.com> wrote:
> Looks really awesome -- I've been waiting for this since I switched to
> Clojure from CL!
>
> I played around with it a bit, and there are a couple issues that
> prevent it from being usable out of the box for me.
>
> 1.  The usual repl entry point is not used, and so, e.g., (set! *warn-
> on-reflection* true) fails.
>
> 2.  I could not figure out a way to browse exception chains.
> Typically the "real" stack trace for an exception is reached by
> repeatedly calling .getCause on the exception until the innermost
> exception is reached, but right now I can't see how to access causes
> in the swank-clj debugger.  For example try:
>
> (defn foo [x] (map - x))
> (foo (for [x (range 10)] (if (= x 8) "foo" x)))
>
> to see a useless stack trace (in 1.2).  I see a couple places in the
> code that deal with causes, so maybe I'm just missing how to access
> them?

Well, if the exception gets bound to *e, you can use this:

(defn pcause
([]
(pcause *e))
([e]
(if-let [c (.getCause e)]
(recur c)
e)))

...

=> (do-something quux mumble 42)
#<Boom!>
=> (pcause)
Exception java.lang.ArithmeticException: divide by zero
at clojure.lang.Numbers.divide (Numbers.java:138)
at com.mycompany.myproject.foo$hairy_calc.invoke (foo.clj:192)
at ... etc.

or something like it.

If it's not getting bound to *e, the above pcause can still be useful with

(defmacro pe [& body]
`(try
~@body
(catch Throwable t (pcause t))))

...

=> (testing-somefn foo 3.141 xyzzy)
#<Kablooey!>
=> (pe (testing-somefn foo 3.141 xyzzy))
Exception java.io.IOException: stream closed
at java.io.FileInputStream.read (FileInputStream.java:177)
at com.mycompany.myproject.bar$some-func.invoke (bar.clj:211)
at ... etc.
=> (defn some-func ... (doall ... ))
#'com.mycompany.myproject.bar/some-func
=> (pe (testing-somefn foo 3.141 xyzzy))
42
=>

Of course, if the exception is being thrown in some other thread, such
as in the evaluation of a pmap or future, all bets are off. Try
temporarily not using the parallelizing construct. In case of failed
Agents, obviously try (pcause (agent-error agnt)).

--
Protege: What is this seething mass of parentheses?!
Master: Your father's Lisp REPL. This is the language of a true
hacker. Not as clumsy or random as C++; a language for a more
civilized age.

Hugo Duncan

unread,
May 23, 2011, 8:23:19 AM5/23/11
to clo...@googlegroups.com
On Sun, 22 May 2011 16:59:24 -0400, Sam Aaron <sama...@gmail.com> wrote:

> Very cool!

Thanks.

> Out of interest, how do swank-clj and swank-clojure (with merged in cdt
> stuff) compare?

I would have to let others comment on the user experience, not having used
the cdt support in swank-clojure. From reading the code, I see two
differences.

i) swank-clj uses SLDB vs the use of GUD in swank-clojure,

ii) swank-clj starts two jvms, one for the debugger and one for the
debuggee. If I understand correctly, CDT uses a single jvm process.

In swank-clj at the moment, a swank server runs in both jvms, but I am
working towards being able to run using just JPDA/JDI to talk to the
debugee. At that point it will be possible to attach the debugger to any
jvm process running with debugging enabled.


--
Hugo Duncan

Hugo Duncan

unread,
May 23, 2011, 8:49:07 AM5/23/11
to clo...@googlegroups.com
On Sun, 22 May 2011 18:09:50 -0400, Jason Wolfe <ja...@w01fe.com> wrote:

> 1. The usual repl entry point is not used, and so, e.g., (set! *warn-
> on-reflection* true) fails.

Thanks, I raised an issue to track this
https://github.com/hugoduncan/swank-clj/issues/8

> 2. I could not figure out a way to browse exception chains.
> Typically the "real" stack trace for an exception is reached by
> repeatedly calling .getCause on the exception until the innermost
> exception is reached, but right now I can't see how to access causes
> in the swank-clj debugger. For example try:

There is no support for exception chains. The reasoning behind this is
that swank-clj can catch the original exception, before it gets caught and
re-thrown in the program. At the moment, there is some rigid filtering of
exceptions that means in some cases the original exception is not caught.

I am hoping that improved (user modifiable) filtering of exceptions based
on thrown type, throw location and catch location, will obviate the need
for handling exception chains in the interface. Does that sound
reasonable?

> If you want, I'm happy to help out on these. Thanks for the great
> work!

All help appreciated - if you can, I would prefer pull requests from
feature branches. There is lots to be done, especially around adding test
cases to get the project to the point where we can make changes with
confidence.

Raising issues for broken slime features would also be useful.

--
Hugo Duncan

Sam Aaron

unread,
May 23, 2011, 9:10:44 AM5/23/11
to clo...@googlegroups.com

On 23 May 2011, at 13:23, Hugo Duncan wrote:
>> Out of interest, how do swank-clj and swank-clojure (with merged in cdt stuff) compare?
>
> I would have to let others comment on the user experience, not having used the cdt support in swank-clojure. From reading the code, I see two differences.
>
> i) swank-clj uses SLDB vs the use of GUD in swank-clojure,
>
> ii) swank-clj starts two jvms, one for the debugger and one for the debuggee. If I understand correctly, CDT uses a single jvm process.
>
> In swank-clj at the moment, a swank server runs in both jvms, but I am working towards being able to run using just JPDA/JDI to talk to the debugee. At that point it will be possible to attach the debugger to any jvm process running with debugging enabled.
>


Thanks for the explanation. I'm relatively new to Emacs - and certainly new to any debugging support. I hadn't heard of the Slime debugger or the "Grand Unified Debugger" before. Given my current understanding of the Emacs ecosystem it doesn't surprise me that there is more than one supported approach to debugging :-)

What I do think is interesting is that there are two different approaches to Clojure debugging within Emacs that are relatively young in terms of implementation maturity. Competing systems can be good for cross-fertilisation and motivation - however they can also be confusing to the newcomer when faced with a choice. Currently I'm that newcomer and I have been using swank-clojure only because it was the only way I knew. George's work on the CDT has been very exciting and I was thrilled to see it get merged in with swank-clojure. However, I now see swank-clj which also seems remarkably exciting - truly cool stuff.

It appears both approaches are incompatible - is this true? If so, I'm wondering what the merits of SLDB over GUD and visa versa are. SLDB sound great cos it has slime in the name and, after all, I'm using slime. However, GUD sounds amazing cos it has the words grand and unified in the title. My initial thoughts are focussed and bespoke vs generalised and abstract. Which personally makes me think SLDB. Clearly choosing purely by name is utter madness though. So if anyone has any more information that can help people decide which approach to invest their time learning that would be much appreciated.

Sam

---
http://sam.aaron.name

Jason Wolfe

unread,
May 28, 2011, 9:48:54 PM5/28/11
to Clojure


On May 23, 5:49 am, "Hugo Duncan" <duncan.h...@gmail.com> wrote:
> On Sun, 22 May 2011 18:09:50 -0400, Jason Wolfe <ja...@w01fe.com> wrote:
> > 1.  The usual repl entry point is not used, and so, e.g., (set! *warn-
> > on-reflection* true) fails.
>
> Thanks, I raised an issue to track this  https://github.com/hugoduncan/swank-clj/issues/8
>
> > 2.  I could not figure out a way to browse exception chains.
> > Typically the "real" stack trace for an exception is reached by
> > repeatedly calling .getCause on the exception until the innermost
> > exception is reached, but right now I can't see how to access causes
> > in the swank-clj debugger.  For example try:
>
> There is no support for exception chains. The reasoning behind this is  
> that swank-clj can catch the original exception, before it gets caught and  
> re-thrown in the program. At the moment, there is some rigid filtering of  
> exceptions that means in some cases the original exception is not caught.
>
> I am hoping that improved (user modifiable) filtering of exceptions based  
> on thrown type, throw location and catch location, will obviate the need  
> for handling exception chains in the interface.  Does that sound  
> reasonable?

Is the advantage of doing it this way that the stack frames are still
intact, so you can get access to the locals etc.? That makes sense;
but having a sane default that doesn't swallow unexpected exceptions
or expose expected ones also seems key. I don't know enough to guess
whether a simple policy like "only show exceptions that would be
caught by clojure.*" would be good enough -- and if it's not perfect,
a way to see causes might be a handy backup.

George Jahad

unread,
May 30, 2011, 9:26:51 PM5/30/11
to Clojure
Just to clarify, there is an older GUD based front end to cdt, but
swank-cdt, the one that I integrated with swank-clojure a few months
ago, uses sldb.


On May 23, 5:23 am, "Hugo Duncan" <duncan.h...@gmail.com> wrote:
Reply all
Reply to author
Forward
0 new messages