Live data from Hacker News

Why your REPL experience sucks

srasu.srht.site

11–20 of 58 posts

Re: Why your REPL experience sucks

#11
Leaving wrong explanation for posterity and to keep thread understandable. See everything after [edit] for corrected explantion

This is an important distinction between (funcall #'foo ...) and (funcall 'foo ...) in Common Lisp as well. #'foo evaluates to the function named by the symbol foo, while 'foo evaluates to the symbol foo itself. So if you redefine the function named by the symbol foo any already compiled forms like (funcall #'foo) will still use the old version but (funcall 'foo) will use the new version.

[edit]

The above explanation is wrong; whenever #'foo is evaluated it will resolve to the current function slot for the symbol foo. Since the form (funcall #'foo) evaluates #'foo each time, it will naturally be affected by changes to the function-slot for foo. If you bind a variable to #'foo (like e.g. a route in a routing library as TFA does for clojure) then the evaluation happens when you bind the variable. See my reply to throwaway1x31 for a full example showing the difference.

Re: Why your REPL experience sucks

#12
post #3

We keep on making fun of php, but it had this problem solved in the 90s. Hit F5 in the browser, get the latest version of your software. No waiting 30s for a rebuild, no stale versions in caches, no headaches.

PHP was and still is great. Make a change and hit refresh. Simple and easy.

Re: Why your REPL experience sucks

#13
post #7

A related question is why would you want to reload the entire file/namespace every time you make a change? Coming from a Common Lisp background, I am used to evaluating single forms/functions. I would sometimes re-evaluate the entire namespace, but that would be relatively rare. I switched to Clojure many years ago and followed the same workflow. Then ClojureScript and tools like figwheel came along and I was somewha…

> I switched to Clojure many years ago and followed the same workflow. Then ClojureScript and tools like figwheel came along and I was somewhat surprised to find that people admire the "auto-reload" functionality so much: save a ClojureScript file and all of it gets re-evaluated in the browser interpreter. I found this to be inefficient, somewhat annoying, and a big step back from evaluating exactly what you wanted to.

It seems to be the default in some tooling in the ecosystem, but you can turn that off and use the "regular" Clojure way in ClojureScript environment too. That's what I usually tend to do.

> And it creates its own problems, like the one the OP solves in the article.

What OP solves in the article doesn't seem to be about reloading an entire namespace, AFAIK. It's certainly not common in the Clojure ecosystem to reload your entire namespace instead of just the function you're working on.

Re: Why your REPL experience sucks

#14
post #7

A related question is why would you want to reload the entire file/namespace every time you make a change? Coming from a Common Lisp background, I am used to evaluating single forms/functions. I would sometimes re-evaluate the entire namespace, but that would be relatively rare. I switched to Clojure many years ago and followed the same workflow. Then ClojureScript and tools like figwheel came along and I was somewha…

Hot reloading is useful when you're making something related to a React-based UI, which you likely are close to 99% of the time in ClojureScript. I seriously doubt it has anything to do with a lack of REPL experience. I use a traditional editor-connected REPL 100% of the time in Clojure and 0% of the time in ClojureScript. I think most of us doing full-stack Clojure work like that.

How is it useful? I've been developing a React app for the last 8 years or so, and I'd much rather eval single functions rather than reload everything. I feel much better in clj and cljc files, where I am not forced to do that.

Re: Why your REPL experience sucks

#16
post #9
post #7

A related question is why would you want to reload the entire file/namespace every time you make a change? Coming from a Common Lisp background, I am used to evaluating single forms/functions. I would sometimes re-evaluate the entire namespace, but that would be relatively rare. I switched to Clojure many years ago and followed the same workflow. Then ClojureScript and tools like figwheel came along and I was somewha…

No friction is better than friction. Having to manually reload parts of a file is friction, and introduces possible heisenbugs... e.g. A,B, C were changed, but you forgot to reload A. There were good reasons for doing it that way when we had 10000x less computing power, but these days? Nah..

Having spent tons of time in jupyter notebooks, I can tell you one thing - loading data and training ML models is not free. Keeping a running system/repl/notebook has immense value.

Re: Why your REPL experience sucks

#17
post #7

A related question is why would you want to reload the entire file/namespace every time you make a change? Coming from a Common Lisp background, I am used to evaluating single forms/functions. I would sometimes re-evaluate the entire namespace, but that would be relatively rare. I switched to Clojure many years ago and followed the same workflow. Then ClojureScript and tools like figwheel came along and I was somewha…

This feels a little too strong to me. DrRacket has as its fundamental UI flow a combination of whole-reloaded-file and a REPL, and obviously the creators of Racket are intimately familiar with Lisp REPLs.

One problem being addressed is the discrepancy between REPL-based development and non-image-based languages: you have to get your code back out into a source file somehow, without forgetting anything. In image-based languages like Smalltalk and APL, you just save your environment after modifying it interactively; there are no separate source files and the problem does not exist. But in file-based languages, you're stuck using the clipboard to copy code back and forth between the REPL and the source file. It can sometimes be easiest to write the code in the source file, then reevaluate it in the REPL environment. If that process is automatic instead of highlighting specific forms and pressing a button, it can sometimes be a slight productivity boost and less error-prone because you won't forget to reevaluate some change you made in the source.

Re: Why your REPL experience sucks

#18
post #7

A related question is why would you want to reload the entire file/namespace every time you make a change? Coming from a Common Lisp background, I am used to evaluating single forms/functions. I would sometimes re-evaluate the entire namespace, but that would be relatively rare. I switched to Clojure many years ago and followed the same workflow. Then ClojureScript and tools like figwheel came along and I was somewha…

> A related question is why would you want to reload the entire file/namespace every time you make a change?

Wait... What change does it make to evaluate a single function or to evaluate that single function plus re-evaluate all the other function in the same Clojure source file? It's not slow. It doesn't break anything?

Regarding figwheel, which I find very convenient (it reloads not just the modifications in .cljs files but also in HTML and CSS files AFAICT), where is the problem and would you reproduce what figwheel does without figwheel?

Most of my Clojure and ClojureScript source file have zero state, zero variable. And from what I can tell many Clojure projects are like that. So what change does it make if I define (or redefine) a function from a REPL or from the source file and have figwheel re-evaluate the whole source file?

Heck... I got "confused" at some point: if I modify a .clj file I need to eval what I modified (or the whole file), to have my REPL "synched" with the file. While with figwheel I don't need to eval but save the file for figwheel to update the front-end's JavaScript in realtime.

So what I did is this: I modified my shortcuts that does "eval buffer" to do "save + eval buffer" and modified my shortcut that does "save" to also do "save + eval buffer".

That way everything works in the same manner and I don't need to remember which one does what.

If I modify a .cljc source file (common to both Clojure and ClojureScript) and either eval the file or save the file, both REPLs see the new definitions and figwheel also hot reloads. I really like that.

And, yet, I still have my two REPLs at all times and I can directly eval stuff at the REPLs if I want to.

> My guess is that lots of those people never worked with a REPL where you eval single forms from the editor, so this auto-reload on each save seemed much better.

OK but for ClojureScript running on the front-end, how would I then go, without figwheel's hot reload, to make a modification and have the (transpiled) JavaScript be updated immediately?

> And it creates its own problems, like the one the OP solves in the article.

But the problem of ring routes not being updated have nothing to do with auto-reload? I may be wrong but wouldn't the problem be exactly the same if I were to re-eval the router var from the REPL (I'll try it and see later on)?

Anyway I'd say that, when worse comes to worse and you screwed your application's state / components lifestyle, a full restart one every blue moon ain't a biggie.

Re: Why your REPL experience sucks

#19
post #7

A related question is why would you want to reload the entire file/namespace every time you make a change? Coming from a Common Lisp background, I am used to evaluating single forms/functions. I would sometimes re-evaluate the entire namespace, but that would be relatively rare. I switched to Clojure many years ago and followed the same workflow. Then ClojureScript and tools like figwheel came along and I was somewha…

This feels a little too strong to me. DrRacket has as its fundamental UI flow a combination of whole-reloaded-file and a REPL, and obviously the creators of Racket are intimately familiar with Lisp REPLs. One problem being addressed is the discrepancy between REPL-based development and non-image-based languages: you have to get your code back out into a source file somehow, without forgetting anything. In image-based…

> In image-based languages like Smalltalk and APL, you just save your environment after modifying it interactively; there are no separate source files and the problem does not exist.

My experience with APL was not based on using the image (longterm), but with Smalltalk, there is a source file paired with the image (you can see this with both Squeak and Pharo). And Iceberg has been around for years allowing you to select specific portions to export to or import from git repos as source files. It was preceded by other version control systems that let you export to and import from source files.

Re: Why your REPL experience sucks

#20
post #7

A related question is why would you want to reload the entire file/namespace every time you make a change? Coming from a Common Lisp background, I am used to evaluating single forms/functions. I would sometimes re-evaluate the entire namespace, but that would be relatively rare. I switched to Clojure many years ago and followed the same workflow. Then ClojureScript and tools like figwheel came along and I was somewha…

This feels a little too strong to me. DrRacket has as its fundamental UI flow a combination of whole-reloaded-file and a REPL, and obviously the creators of Racket are intimately familiar with Lisp REPLs. One problem being addressed is the discrepancy between REPL-based development and non-image-based languages: you have to get your code back out into a source file somehow, without forgetting anything. In image-based…

A system I used you'd edit the source and press some key-combination that injected the current function only from the editor to the running app
Post reply on HN