Fork me on GitHub
#beginners
<
2019-10-30
>
NoahTheDuke01:10:07

Hey friends, I have an uberjar running. I want to open a repl to it. Is that possible?

seancorfield01:10:08

@nbtheduke Not from the outside. You need to either a) start the uberjar with JVM opts to tell Clojure to start a Socket REPL or b) program something into the app to explicitly start up some sort of REPL.

๐Ÿ‘ 1
NoahTheDuke01:10:25

Good to know, thank you

seancorfield01:10:17

If you don't mind restarting the app, you can just provide the JVM option to start a Socket REPL. We run local Socket REPLs in a lot of our processes and then tunnel into the server to get access to that.

NoahTheDuke01:10:39

Maybe Iโ€™ll try that next time I restart the app!

dpsutton02:10:22

@seancorfield do yall take any steps to ensure that your socket repl access is "read only" in the sense that you don't redefine anything important?

dpsutton02:10:27

or just kinda scouts honor?

seancorfield02:10:30

We use those Socket REPLs to apply live patches to the running processes sometimes ๐Ÿ™‚

dpsutton02:10:04

I thought I remembered reading a blog of yours that you used to do that but had turned against it lately

seancorfield02:10:44

Someone has to be able to ssh into the server to get at the REPL...

seancorfield02:10:13

...We stopped running nREPL servers in processes. We didn't want the dependencies added.

seancorfield02:10:06

(We used to run nREPL servers with full CIDER middleware enabled... and that was... a bit much... but a Socket REPL is built right in to Clojure so no deps needed for that)

seancorfield02:10:45

We have an optional per-process dot file that the service script picks up so we can decide which processes get a REPL and what port it is on (and any other JVM option level stuff we want, when we want it).

NoahTheDuke02:10:42

How do you set this up? Do you have a blog post detailing?

didibus02:10:38

Ya, that's why I'm a fan of unrepl

didibus02:10:56

I can't wait for the time nRepl can bootstrap itself from a socket repl

seancorfield03:10:54

I just don't get the enthusiasm for nREPL...

seancorfield03:10:07

...I switched from Atom/ProtoREPL (which required a server-side dependency that included nREPL / Compliment etc) to Atom/Chlorine about a year ago, and I've really enjoyed not needing any server-side dependencies, and only minimal code loaded via unrepl (and I sort of wish Chlorine didn't even use that).

seancorfield03:10:53

I thought it was a good day when Chlorine made Compliment optional recently -- and built its own simple auto-complete (that works just fine for me).

seancorfield03:10:57

I suspect if I was still using Emacs, I'd be a big fan of inferior mode or whatever the simplest possible package that can connect to Socket REPL ๐Ÿ™‚

didibus03:10:07

I don't know what features are provided by nRepl. But what I do need is auto-complete, go to definition, debugging, pretty print, interrupt, run test, etc.

seancorfield03:10:45

What "debugging" do you rely on?

didibus03:10:57

Cider debug

didibus03:10:06

It's pretty amazing

seancorfield03:10:12

I have no idea what that does.

didibus03:10:47

It instruments a form or function, and then it can break, continue, in, out, inspect, trace, etc as you see fit

seancorfield03:10:16

Hmm, I've never cared for that sort of thing much, in any language TBH.

didibus03:10:17

I've stopped having to add my own print lines or def since it's so convenient

didibus03:10:32

Well, in other languages it's pretty annoying

didibus03:10:55

But in Cider its integrated as part of the repl

seancorfield03:10:18

I guess I've never felt the need. I like having tap> available built-in (and I use REBL alongside Atom) but really I'm more in Stu's camp of simple tools...

seancorfield03:10:50

I've had to use breakpoint debugging a few times during my years of Java (and years of C++ before) but that was because the language/tooling was otherwise just so awful.

seancorfield03:10:25

I really liked Stu's debugging example where he redefined the exception handler to just print "boom!" and provide no info at all ๐Ÿ™‚

didibus03:10:27

It's not that you need it. And there's a lot I'm not a fan of with cider defaults. But that debug feature honestly is awesome. I feel it's a little unknown secret though

โ˜๏ธ 2
didibus03:10:37

It just means instesd.of taking 5 to 10 minutes to add prints and defs and try/catches manually and all, it now takes me 1min to debug the same

didibus03:10:03

I don't know if that means it needs nRepl and all its dependencies though

didibus03:10:08

I actually have inf-clojure and unrepl as well that I use in my emacs, because I don't think the issue is necessarily simple in the sense of featureless. But what cider lacks is simplicity in setup and usage

seancorfield03:10:37

I think part of my fundamental objection to that level of intrusive debugging -- breakpoints -- is that you can't use it on a production app while it is running, whereas you can use the tap> (or println) approach...

๐Ÿ’ฏ 1
didibus03:10:28

Hum... well you could use cider-debug in prod, but you probably shouldn't, since it'll pause your thread

bfabry03:10:30

huh, til tap. seems nice. seems like it would mesh very well with something like http://honeycomb.io

didibus03:10:06

For prod I wouldnt say I need all these things. Mostly goto, auto-complete, and doc would be nice for a prod repl. I like to use rebel-readlines in prod actually. I just ssh and start a rebel-readline repl

seancorfield03:10:02

See, I like to be able to use the exact same tools and approach no matter where the app is that I'm working on / debugging.

seancorfield03:10:23

That way I won't accidentally use the "wrong" tool in the wrong environment ๐Ÿ™‚

didibus03:10:33

I see. Yes I know people who value that a lot.

didibus03:10:13

In my case, I'm not allowed to open remote ports anyways to prod, and I can't ssh tunnel either ๐Ÿ˜”

didibus03:10:24

So rebel-readline is an amazing alternative

seancorfield03:10:10

I remember you talking about your work environment a bit... it sounded pretty corporate and locked-down... I'm surprised somewhere like that even uses Clojure ๐Ÿ™‚

bfabry03:10:31

โ€œit runs on javaโ€ cures many ills ๐Ÿ˜†

๐Ÿ‘ 2
seancorfield03:10:14

Hah... Neal Ford's sneaking Clojure in through the back door stuff...

seancorfield03:10:20

(it was Neal Ford, right?)

mg03:10:27

Yeah, he has this "we use Java with the Clojure library" schtick

seancorfield03:10:55

Well, hey, all it takes for a Java app is adding Clojure as a dependency, add a JVM option, and -- bingo! -- you have a live REPL into your legacy/enterprise Java app ๐Ÿ™‚

seancorfield03:10:27

(after all, that's how come we have a REPL into our legacy ColdFusion apps! ๐Ÿ™‚ )

David Rueda07:10:34

Sounds cool, which JVM option do you add?

David Rueda09:10:27

Thatโ€™s awesome, thank you!

๐Ÿ‘Œ 1
jumar09:10:57

Btw. this might be useful when connecting to a socket repl running on a machine inside a private network available only via "bastion" host (e.g. on AWS):

# run in separate window
ssh -N -L 55550:localhost:5555 -J [email protected] [email protected]

# then use unravel to connect
unravel localhost 55550

๐Ÿ‘ 1
Mehdi H.11:10:12

Hi everyone! Would someone with experience on working with pedestal.vase and datomic-pro be available for the assistance I require?

Mehdi H.11:10:08

I am trying to use vase standalone with datomic-pro. The thing is I can't seem to find the latest uberjar online at the link of the doc, and anyway it would be built for datomic-free. I tried to git clone the current github repo but it doesn't "lein uberjar" well even as is. I went back to the 0.9.2 release, commented out the datomic-free dep and added the datomic-pro (with the version I have a licence key to). lein uberjar suggested I excluded com.google.guava/guava, and then the uberjar was completed. But now I am thinking I can't use a .fern config, and I am wondering whether I am missing a way simpler option for all this...

jaihindhreddy11:10:41

^ You might wanna ask in #datomic

Mehdi H.11:10:28

Thanks man yeah haha that makes a lot of sense. I am new to clojurians slack, didn't even explore the channels available apart from the automatic ones

Shuai Lin11:10:44

Hi, I have question: Any mature open source system to learn about writing a system in clojure? (I posted on reddit, but think may get additional answers here) https://www.reddit.com/r/Clojure/comments/dp1p2t/any_mature_open_source_system_to_learn_about/

Watching the talk "The Language of System" () inspired me to learn practical clojure programming, by studying the source code of some open source systems written in clojure. 

My criteria for such systems are:

* Not a library, not a framework, not a command line tool - but a full-fledged system or application. This is because designing/implementing a system has many unique considerations, e.g. a command line tool can simply abort on error, but a real-world system has to bear with it.
* stands to the tests of real world usage (no research/toy projects even if it has lots stars on github)

For other languages it's easy to find lots of candidates:

* python: zulip, openstack, ansible, etc.
* go: tons of CNCF projects (docker, kubernetes, etc)
* java: tons of apache projects (hadoop, hbase, zookeeper etc.)
* c/c++: countless of open source applications (xwindow, chromium, etc.)

However for clojure it's hard to collect candidate projects, maybe due to me short history with clojure itself, here are a few:
* apache storm (another project from the same author )
* metabase ()

Do you have any suggestions?

jumar13:10:54

@UNMKEJQ1E I've just replied to the post. Thanks for raising this question

Shuai Lin15:10:27

Seems circleci's frontend is a good candidate for learning large-scale real-world cljs applications, but it's not updated for two years, anyone knew what happended to it? https://github.com/circleci/frontend

jumar18:10:37

In a recent REPL podcast they mentioned they are moving to JavaScript/React: https://www.therepl.net/episodes/29/ For various reasons, I think mostly community/tooling (React/JavaScript just has a lot more support) and hiring

Shuai Lin01:10:40

Thanks for the info @U06BE1L6T!

bbloom16:10:57

sorry, i was only engaged with circleci for a short time and donโ€™t have much insight in to what happened after i gave that talk. you could try reaching out to some of the (much bigger than me!) contributors, or on twitter

indy16:10:19

Hi, can anyone let me know how to suppress output when I use swap!

hiredman16:10:43

What kind of output?

indy16:10:43

so when I use swap! to assoc some items into an atom that is a map, the contents of the atom are printed in the repl and also when i run it through lein run

hiredman16:10:55

Something to keep in mind is the function passed to swap! may be called multiple times, so any side effects (like output) you don't want happening repeatedly shouldn't be in that function

hiredman16:10:25

There is nothing about swap! that prints things

indy16:10:03

(def k (atom {})) => #'lisp-interpreter.core/k (swap! k assoc ๐Ÿ˜› 10) => {:b 10}

bfabry16:10:22

this is just swap! returning the value

hiredman16:10:25

You are using a repl

hiredman16:10:33

Read eval print loop

hiredman16:10:41

It prints the result

indy16:10:01

I ran the -main function using lein run and it still prints the same thing to the std out

andy.fingerhut16:10:14

For any Clojure expression that has a result returned that you do not want printed in a REPL, you can do something like (def tmp <expression>) where tmp is some var you don't care about

indy16:10:00

I tried do with the last exp as nil

hiredman16:10:00

(do whatever nil)

indy16:10:13

but now it prints nil so I've to add another check

andy.fingerhut16:10:29

What does your code in -main look like?

hiredman16:10:20

You may have some annoying lein plugin breaking things

andy.fingerhut16:10:14

Your -main function is implementing your own custom REPL, it appears?

indy16:10:02

@andy.fingerhut your solution certainly will works but is there is a better solution?

andy.fingerhut16:10:19

Are you saying you don't want it to do the (println (pr-str res)) part, and removing that code makes it do what you want? I'm confused what printing output you are seeing that you want, vs. what you do not want.

indy16:10:22

Yeah tried writing my own lisp interpreter as learning project

bfabry16:10:41

I like (nil? expr) because itโ€™s very short and tells me something thatโ€™s sometimes useful

indy16:10:16

@andy.fingerhut and @hiredman thanks for the help, I think I'm good for now with the suggestions

bfabry16:10:27

oh but (= expr) is even shorter!

noisesmith17:10:09

I might be misinterpreting but

user=> (= nil)
true

bfabry17:10:33

yeah it just always returns true. so not as informative as nil?

noisesmith17:10:55

it can't provide information because it returns true for all arguments

indy17:10:12

is shorter isn't it?

andy.fingerhut17:10:12

You can always define a tiny macro whose name is a single letter long that expands to whatever you want, if you are trying to save characters of typing, e.g. expanding to (do expr nil) or (let [res expr] (nil? ret))

alexmiller19:10:37

you can do it by using either a macro or eval

alexmiller20:10:43

user=> (def possible-keys [::all ::the ::keys])
#'user/possible-keys
user=> (eval `(s/def ::special-map (s/keys :opt-un [[email protected]])))
:user/special-map
user=> (s/form ::special-map)
(clojure.spec.alpha/keys :opt-un [:user/all :user/the :user/keys])

alexmiller20:10:00

(note that even with :opt-un, you need qualified keys)

alexmiller20:10:35

in spec 2, there are several ways to do this and you can use it without any macros at all if needed

alexmiller20:10:29

in spec 2, one option is to resolve a symbolic spec and use register (no macros here):

alexmiller20:10:58

user=> (require '[clojure.spec-alpha2 :as s])
nil
user=> (def possible-keys [::all ::the ::keys])
#'user/possible-keys
user=> (s/register ::special-map (s/resolve-spec `(s/keys :opt-un [[email protected]])))
:user/special-map
user=> (s/form ::special-map)
(clojure.spec-alpha2/keys :opt-un [:user/all :user/the :user/keys])