This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-08-11
Channels
- # announcements (2)
- # beginners (30)
- # biff (6)
- # calva (4)
- # cider (4)
- # clj-yaml (3)
- # clojure (14)
- # clojure-europe (43)
- # clojure-nl (8)
- # clojure-norway (34)
- # clojure-uk (2)
- # clojurescript (11)
- # clr (2)
- # conjure (3)
- # cursive (1)
- # datomic (18)
- # helix (1)
- # humbleui (6)
- # hyperfiddle (110)
- # java (25)
- # kaocha (2)
- # lsp (29)
- # missionary (7)
- # off-topic (9)
- # pathom (106)
- # polylith (27)
- # rdf (12)
- # re-frame (9)
- # releases (4)
- # spacemacs (2)
- # tools-build (4)
- # tools-deps (6)
When setting up a REPL in production that you can SSH to, is there any reason to use socket REPLs over nREPL?
I believe there are good reasons for it. • socket repls don’t “steal your main”. you can continue to use the normal entry point of your uberjar and add some jvm options to get a socket repl up. • you don’t need extra dependencies. Often prod builds won’t have nrepl at all. So you’d need to add it and start it, or your prod builds always have nrepl bundled • nrepl does some subscribing for out which isn’t always cleaned up I don’t think. Can change how your application behaves
I agree and we used socket REPLs for a long time in production -- and rlwrap telnet to access them. But that meant we had none of our editor niceties so eventually we decided to add nrepl as a (production) dependency and write a small amount of code that would start an nrepl server at app startup if a JVM property was supplied. The editor complains about the lack of cider support but provides all of the basic eval support you'd expect so we can work from a scratch file in an editor instead of a plain terminal repl. We added portal as a dependency in a couple of production apps too (internal-facing, but they have access to the same DB as customer-facing), so that we can have the full nrepl/portal editor experience with staging and production that we have locally (again, sans cider). Then I automated the whole thing with Joyride for VS Code 🙂 Now I can start my vpn, hit ctrl+alt+b p to start an ssh tunnel and connect to a repl on production and copy the portal port file from production to local, then ctrl+alt+space p to start two portal windows inside VS Code that are powered by production. ctrl+alt+b q would "browse qa" instead of production.
Is there a reason you can't use cider? I was just testing with nrepl and seeing if I can get calva to connect to Prod with support, so I can just evaluate stuff in VSCode and have it work on prod
Seems doable
it might be CIDER that adds a forking printer on the out that can linger if you don’t shut down correctly.
I just don't want all the cider middleware and the "fancy" stuff it does... and, yeah, it can do weird stuff semantically... great for local dev, not so great for a production process.
My vscode-calva-setup repo has most of the config/machinery including keymaps, joyride scripts, custom calva repl snippets...
i think sometime in the past it used to reset the System out. Seems like it doesn’t do that any more but i have a vague memory that it could change output in some way
I haven't quite gotten into joyride yet.
You use emacs, right Sean? I don't think there's a way to work with nREPL using Calva without cider
☝️:skin-tone-2: All the above is VS Code/Calva. I used to use Emacs (on and off for decades).
Calva warns that some functionality won't work without CIDER, but all basic eval stuff works fine.
See https://github.com/seancorfield/vscode-calva-setup (and maybe some stuff from https://github.com/seancorfield/dot-clojure -- aliases and my local dev repl start script)
Thanks!
Hello, I'm following BraveClojure and having some trouble about basic understanding. Help me please!
((first '((first [+ 0]) 1 2 3)) 4 5 6) ; it raise `Unhandled java.lang.ClassCastException
`
I inferred like this:
(first '((first [+ 0]) 1 2 3))
; this actually returns (first [+ 0])
; and (first [+ 0]) will return +
; so, ((first [+ 0]) 4 5 6) will return 15
I don't understand why it raise exception, and the real problem is that I have no idea how to debug this error from repl's stacktrace.in a repl, i put my cursor at the end of the form and evaluated it and i get the error
user=> ((first '((first [+ 0]) 1 2 3)) 4 5 6)
Execution error (ClassCastException) at user/eval197627 (REPL:12).
class clojure.lang.PersistentList cannot be cast to class clojure.lang.IFn (clojure.lang.PersistentList and clojure.lang.IFn are in unnamed module of loader 'app')
this error says I don’t know how to treat a list as a function. So somewhere we’re trying to invoke (some-list args)
like ((1 2 3) 4)
and i don’t know what that should do, so an error sounds correctevaluating a subpart of it i see
user=> (first '((first [+ 0]) 1 2 3))
(first [+ 0])
and there’s your issue. you’ve got a quote
user=> '((first [+ 0]) 1 2 3)
((first [+ 0]) 1 2 3)
If you would use vector instead it would work as you expect:
((first [(first [+ 0]) 1 2 3]) 4 5 6)
Thank you dpsutton and Ewa.
First, the quote was intentional. I wonder why this is not evaluated natually.
Then from the Ewa's hint, I figured out that there is eval
function, which is what I needed in this expression.
I think I went one step forward with your help! 😄 Have a nice day.
Could you paste here your final code?
sure!
((eval (first '((first [+ 0]) 1 2 3))) 4 5 6) ; return 15
I guess this is not optimal for this case, but it seems enough for now 😅quote
exists to block "natural evaluation", but then we (@U05MHC4E6UC) hit a need for evaluation via eval
, so there may be a deeper misunderstanding afoot. Where exactly are you in Brave Clojure?
Is it so? I was on https://www.braveclojure.com/do-things/#Calling_Functions in Chapter 3:
((first [+ 0]) 1 2 3)
; => 6
In the previous part, I learned some data structures including list. So with those combination, I made a hypothesis:
• I can make a list with a single quote.
• list is not evaluated. Instead, it is treated as a value. e.g., I can't write (1 2 3)
, but I can write '(1 2 3)
• if I write '((first [+ 0]) 1 2 3)
instead of ((first [+ 0]) 1 2 3)
, then (first [+ 0])
would be just a first value of four-sized list
◦ wait, it seems suspicious....
• (first '((first [+ 0]) 1 2 3))
returns (first [+ 0])
and I thought this is still value. uh... isn't it?
• then I guess the eval
evaluate the value as a expression (not sure it is called like this)
• So I tested (eval (first '((first [+ 0]) 1 2 3)))
. it shows #function[clojure.core/+]
which seems the same as I expeted.
• The rest is nothing special. ((eval (first '((first [+ 0]) 1 2 3))) 4 5 6)
would be (+ 4 5 6)
and it worked like that.
While writing this, I found some missing link in my guess: I unconsciously '((first [+ 0]) 1 2 3)
and '('(first [+ 0]) 1 2 3)
will be the same.
user> (do (println (first '('(first [+ 0]) 1 2 3))) (println (first '((first [+ 0]) 1 2 3))))
; => (quote (first [+ 0]))
; => (first [+ 0])
Ok it's totally different. But really confusing...I dislike using quote for "just" writing a list. If i need a list I'll write (list ,,,)
First of all. congrats on your exploring and confident nature! Second of all, Beware the REPL!
(first '((first [+ 0]) 1 2 3))
=> (first [+ 0])
;; yay! we extracted the function!
;; Maybe. The REPL can mislead. Better check...
(fn? (first '((first [+ 0]) 1 2 3)))
=> false
;; Yikes. What is it then?
(type (first '((first [+ 0]) 1 2 3)))
=> clojure.lang.PersistentList
;; What list? If we ask the first element we will just get confused. Try the second:
(second (first '((first [+ 0]) 1 2 3)))
=> [+ 0]
;; Ugh. It /is/ a list. Well, at least we got the vector of the function + and 0! Hmmm...
(type (second (first '((first [+ 0]) 1 2 3))))
=> clojure.lang.PersistentVector
;; Booyow! This is starting to make sense. And it holds a function and a long, right?
(type (first (second (first '((first [+ 0]) 1 2 3)))))
=> clojure.lang.Symbol
;; Hunh? I need a sanity check...
(type (first [+ 0]))
=> clojure.core$_PLUS_
;; Hmmmm. One more sanity check...
(type (first '[+ 0]))
=> clojure.lang.Symbol
;; Consistency! And so quote returns nothing but symbols and lists of symbols!!!! Right?
(type (second '[+ 0]))
=> java.lang.Long
;; *sob*
Hth!Bold explorers die young. 🙀 Your brave exploration plunged you into John McCarthy's profound insight, the grand unification of code and data, aka homoiconicity. quote
makes lexical code into data. eval
brings it back. You could not explore extracting the function part of ((first [+ 0]) 1 2 3)) 4 5 6)
without blocking the evaluation by quoting, so you quoted and were doomed. The good news? You have now qualified for the chapter on Macros, where we must juggle deftly code as data to produce code. Courage.
Thank you for such a huge explanation kennytilton! To be honest, I dind't understand all of your saying but it is clearer to certain extent than before, which makes me feel better. I hope you have smooth weekend. 👍