Fork me on GitHub

Has anyone done Common Lisp? What's missing from Clojure's REPL?

Noah Bogart16:05:30

common lisp is much more "reloadable" than clojure. for example, updating a CLOS object changes all instances in memory whereas changing a defrecord both doesn't change any instances and also will invalidate protocol impls. another example is having to use #' when referencing a function so it isn't made stale when re-evaluating the function definition

Noah Bogart16:05:25

the condition system makes fixing errors much easier: when you hit a bug, the debugger opens and lets you make changes to the code and then re-evaluate the code and then enter the debugger and restart the evaluation at the moment of the bug.


Hum, certain changes to a protocol are fine


Like if I change the function implementation it reflects.


You don't have to use #' in Clojure either, unless you have code explicitly capturing the FN and not the symbol, like higher order functions. But don't you have to do that in CL as well, since you need special syntax to use HOF?

Noah Bogart16:05:13

if you make a hashmap of functions, you gotta reference the var: (def my-fns {:fn1 #'my-fn :fn2 #'bar-fn}), otherwise it'll capture the fn and not the symbol. also true of compojure routes, etc


Ya, that's correct, that's the "unless it captures the FN". But that's all instances of HOF, which would require special syntax in CL no? Maybe I'd need to see the equivalent CL code

👍 1

When I look for some, it all seems to use special syntax even for simple cases, so it seems worse than Clojure:

(funcall #'list 1 2 3)
See the use of #' and the need to use funcall

Noah Bogart16:05:08

yes, that's true, they go the other way where functions are in a different namespace, so you have to do the opposite: (mapcar #'1+ '(1 2 3))

Noah Bogart16:05:50

this is something that scheme (and clojure all other lisp-1s) avoid, but scheme also avoid's clojure's issue of the difference between a function reference and a var


Are you sure? Emacs LISP has the same problem as Clojure, so I'd thought Schemes would as well

Noah Bogart16:05:19

hmm i was but now i'm not lol. lemme load it up and see if it works how i thought it worked

👍 1

Implementation wise, I feel either you force a slow indirect lookup each time, or you pass a function pointer, and with a function pointer, to redef the function you'd need to have the new function overwrite the exact same chunk of memory, that seems like maybe it's not feasible. But maybe scheme has like a compiler options like direct linking in Clojure for when you compile for production.

Noah Bogart16:05:50

As i remember it, Common lisp symbols point to specific memory locations, so when you reevaluate a function definition, it changes the memory location that symbol points to, so any usages of the symbol will now point to the new spot. There’s probably optimizations going on to make such things faster than the simple indirection


Ya I wonder how it optimizes this away. Maybe just it direct links it when you compile it to a binary. I guess Clojure could do the same technically, it could pass vars by default and when doing an AOT you could have a flag.


Is common lisp always AOT? Like when you release the application?


I'm also curious about the CLOS instances, do you mean that I can like add or remove fields on the class, and all instances automatically update to have an extra field or lose an existing one? And I can also change the method implementation and all instances will automatically use the new ones?