Fork me on GitHub
#beginners
<
2017-11-15
>
michael.lombardo02:11:44

I have a few questions would anyone be able to assist me (New to Clojure)

derpocious03:11:31

hey, if anyone could please help me with my issue in calling cljs files from the lein repl I just posted about it in the leiningen channel. thanks. 🙂

derpocious03:11:39

@michael.lombardo what are your questions?

derpocious03:11:04

Not saying I can answer them, but I'll listen to them. 🙂

michael.lombardo03:11:30

I am just having a problem removing particular keys from an array map. I am not sure which would be the correct function to use.

noisesmith03:11:11

@michael.lombardo dissoc is the function that removes keys - but remember that this doesn't change the original map, it creates a new one without those keys

noisesmith03:11:26

you can also use select-keys if you'd rather explicitly say the ones you want

lvbarbosa15:11:11

If I have an agent whose work is basically to select/read from non-blocking channels and drop the messages in a core.async/chan, should I use send or send-off?

lvbarbosa15:11:55

I know send-off should be used for potentially blocking I/O operations. I am doing non-blocking stuff, is it ok to use send?

tonywang89715:11:01

send is like async/go, send-off is like async/thread

tonywang89715:11:54

I think /code send is ok

lvbarbosa15:11:34

It seems like, right? Since I’m not blocking the fixed thread pool threads

tonywang89715:11:19

In my opinion `send is ok

lvbarbosa15:11:07

I agree with you, but I would like to see if someone would not agree and show me the reasons 😅

lvbarbosa15:11:37

let’s do it then, for now

noisesmith17:11:28

@lvbarbosa it’s OK to use send if you don’t attempt the send unless/until the channel read completes, and the function passed to send does a non-blocking write (eg. put!)

noisesmith17:11:10

just clarifying, since this is #beginners and all, that just because it’s a channel doesn’t make your operation non blocking

lvbarbosa17:11:10

Thanks @noisesmith, I did not realize that the >! could block

noisesmith17:11:29

it’s parking - which can look like blocking depending how your code is structured

mail18519:11:16

is there a possibility to change the keybindings of the repl that is being invoked by lein repl?

mail18519:11:33

for example, I find repeating commands/ searching the history kind of tedious. In bash and other readline applications i have bound arrow-up to reverse history search of whatever is before the cursor.

manutter5119:11:22

Hi @mail185 I use rlwrap lein repl at the command line. rlwrap gives you the arrow-up functionality for recalling earlier commands. Works on OS X and Linux

mail18520:11:52

@manutter good idea, thanks for the reply. just added alias repl="rlwrap lein repl" to my .bashrc

noisesmith20:11:23

that breaks tab completion, doesn’t it?

noisesmith20:11:37

or does the rlwrap forward the tab key to the jreadline in the lein repl?

mail18520:11:42

@noisesmith just tried it, tab-completion seems fine.

james-clojure20:11:01

Hey -- am slowly getting used to writing a small sample -main program and interacting with the REPL (via CIDER and Leiningen). Is there any writeup or explanation of REPL stack levels and such, e.g. when the program wants to exit (but really don't want to (System/exit...) just yet, or would need to hook that and substitute throwing an exception, etc.)? I've worked on CLIs/debuggers in the past that were stack-based, but am not sure the Lein REPL is really set up for that.

noisesmith20:11:08

it doesn’t do “sub repls” - that’s not how we organize things at all

noisesmith20:11:25

if you have a -main, and it exits, the vm exits (if you don’t have threads still running)

noisesmith20:11:42

if your repl is running, -main exits and your repl stays running

noisesmith20:11:37

I guess if you prefer to use System/exit you could have an optional :prod flag to -main that tells it to explicitly exit, and leave that arg out in the repl

noisesmith20:11:12

or make -main a small wrapper that calls a secondary main (that you can use from a repl) and also exit explicitly when that exits

james-clojure20:11:33

Hmm, okay. Would project.clj handle passing the :prod flag in the non-REPL case then? Though I think your final suggestion makes the most sense, since I could then just use (main "arg1" "arg2" ...) in the REPL. (BTW, is there a way to tell the REPL to wrap that up for me, so I can just type <some-run-command> " arg1 arg2 ...", without having to quote the args myself?)

seancorfield20:11:49

Or, if you application is all built with Component, then your -main is likely to be something as simple as (component/start (build-system)) which you can execute in the REPL directly.

james-clojure20:11:16

I haven't learned anything about Component yet -- thanks!

seancorfield20:11:40

I tend to have a (comment ...) form at the bottom of a lot of my files which has the forms I would need to evaluate in the REPL to get a system up and running.

seancorfield20:11:04

One of the nice things about that workflow is you can run multiple "applications" in a single REPL.

james-clojure20:11:39

ISTR seeing someone (you?) talk about that on this slack a few days ago? Maybe in a discussion about Atom v Emacs?

seancorfield20:11:07

For working in the REPL, I don't need to deal with port and server so they're hardcoded into the REPL comment. I just place the cursor on each of those forms in turn and hit the "evaluate" hot key, and I have a web app up and running in my REPL and I can develop it by live-eval'ing code into that.

seancorfield20:11:42

If I do something that means the component needs to be restarted, I can just eval the component/stop form, then eval the def again.

seancorfield20:11:05

(I don't both with New Relic monitoring when I'm running the code locally in the REPL, for example)

james-clojure20:11:39

That'll definitely be useful when I work on more levels of the stack...right now I'm still just learning the Clojure equivalents, roughly speaking, of C's main().

seancorfield20:11:08

I would recommend using -main as just a thin wrapper around the function that is your application -- easier to work with in the REPL (and potentially callable from other code). Then -main just handles & args conversion to the arguments that the "application function" would use.

james-clojure20:11:30

That makes sense.

seancorfield20:11:45

(and if you need fancier arg handling than a few positional arguments, look at clojure.tools.cli)

james-clojure21:11:03

Thanks again! On another topic: I've often gotten "CompilerException java.lang.RuntimeException: Unable to resolve symbol: ..." (e.g. for _main) when it turns out the problem is my .clj code file was malformed (missing a close paren or something). Is there some way (maybe this is a #cider question?) to notice and discover "compiler" errors when running cider-jack-in (to start the REPL within CIDER)? I'm probably not asking the right question here (my project.clj has ":main ^:skip-aot ...", which I guess would disable Ahead-Of-Time compilation)....

mail18521:11:57

so this is more of a leiningen question than a clojure question (I think?) - how do i add paths to the classpath? when i set the $CLASSPATH env variable leiningen yells at me and then ignores it.

smith.adriane21:11:14

have you tried :jvm-opts

smith.adriane21:11:33

with the -cp flag?

mail18521:11:14

nope. that sounds good.

seancorfield21:11:25

@james-clojure When you eval code into the REPL, you will get compiler errors displayed if there's a problem. Clojure compiles all code. It compiles it when you load the namespace.

seancorfield21:11:08

cider-jack-in just starts the REPL, it doesn't load any code.

james-clojure21:11:22

I have noticed that for eval'ing code directly. But the REPL that starts up via cider-jack-in will have my code in it if it's correct, but won't be able to find it if not, and I'm not noticing any difference in the REPL window that tells me something's wrong.

james-clojure21:11:53

One mistake I made was to (comment ...) something out near the top of the file, but forgot to add a trailing paren (I'm still new to paredit-mode in Emacs, so don't blame it!). Took me reindenting the entire file to notice the problem. These are among many beginner's mistakes I'm making...been awhile since I Lisp'ed to any significant extent....

seancorfield21:11:10

We specify clojure.main as the :main namespace and avoid AOT completely. Then we use the -m myapp.core arguments when starting the JAR to tell clojure.main which namespace to look in for -main. That also avoids the problem with cider-jack-in trying to load your main namespace at startup I think.

seancorfield21:11:36

It's been so long since I've using Leiningen (and Emacs) that I've sort of forgotten some of these problems... 😐

lvbarbosa21:11:16

What are you using @seancorfield?

seancorfield21:11:17

We switched to Boot two years ago and I switched from Emacs to Atom/ProtoREPL just over a year ago.

seancorfield21:11:22

Boot doesn't auto-load your main namespace at startup anyway, which also prevents this sort of issue (we only specify clojure.main as an entry point when building an uberjar).

seancorfield21:11:40

My team mate is still an Emacs user tho' 🙂

lvbarbosa21:11:32

This made me curious about Boot

james-clojure21:11:44

I've been an Emacs users for a few decades now but have often had teammates that used vi/vim or whatever was the canonical editor on VAX/VMS. It's good to be tolerant of that sort of thing. 😉

lvbarbosa21:11:46

I should give it a try in the next few days

james-clojure21:11:15

Reading https://www.reddit.com/r/emacs/comments/5jaui7/atom_vs_emacs/ is making me LOL -- "...emacs has a small enough memory profile...", which I guess is true by today's standards. (I go back to before it was parodied as Eight Megs And Constantly Swapping.)

seancorfield21:11:36

I was an Emacs user back in the 17.x / 18.x days... just after 19.x came out I went off to IDEs but came back to it in the pre-release builds of 24.x after getting started with Clojure.

mail18521:11:47

@james-clojure "Small enough memory footprint" nowadays means does not need a rendering & javascript enginge to run

mail18521:11:34

Atom basically runs in a browser

james-clojure21:11:46

Yeah, a Chromium clone IIRC. What I don't have a good feel for are the advs/disadvs of that versus all the Emacs code that does the corresponding stuff (rendering and such) -- performance, code reuse, maintainability, etc.

chris21:11:36

the rendering engine in emacs is... not great

chris21:11:11

so, I've looked at atom as an emacs replacement because I want simple things like an autocomplete popup that doesn't push all the other text down the page

james-clojure21:11:19

Yabut, "Render unto CIDER the..." oh wait. 😉

chris21:11:49

but I do still love org-mode and everything, so I stick with it

mail18521:11:54

emacs -nw 😉.

james-clojure21:11:24

(I still regularly run non-X Emacs on my public-facing CentOS server.)

mail18521:11:53

i am afraid to admit this in a lisp-y place like this. but my daily driver text editor is terminal vim

jeff.engebretsen21:11:59

You could always write an electron app that serves as a renderer for emacs -daemon

james-clojure22:11:25

I don't really think of Emacs as "lisp-y" -- a Lisp is its extension language, but when I first tried it out, it wasn't.

seancorfield22:11:25

When I first started looking at Clojure (2010) I was mostly using Eclipse for other stuff but I started with TextMate for Clojure, then tried Sublime Text for a while. I was using a tiny Linux Netbook when traveling (and a big Mac desktop at home) but the hot keys seemed different enough between Linux/Mac in ST that it drove me mad. I even tried Eclipse + CCW for a while (but it ran like a dog on the Netbook). That's when I switched to Emacs. It was an identical experience on Linux/Mac and relatively lightweight. Then I replaced the Netbook with a Windows 8 convertible (Dell XPS 12) -- running Emacs. I still use that (although it's running Windows 10 Fast Ring Insider builds now) and I put up with the fact that Atom has different hot keys on Mac/Windows now 😐

tkjone23:11:37

I have a function like this:

(defn generate-times 
   []
   (do-stuff)
I want to refactor the above to accept 2 arguments, but still support being called without arguments:
;; works
(generate-times)

;; works
(generate-time arg1 arg2)
What would be the best way to do this? multi-arity or default values for the args?

jeff.engebretsen23:11:32

Would default values make sense?

jeff.engebretsen23:11:56

eg. could you come up with default values that work with (do-stuff). or would (.. [] (do-stuff) [arg1 arg2] (do-other-stuff)) make more sense?

tkjone23:11:25

Yes, I have default values that work for it. multi-arity just seemed odd because the same logic would be in both blocks and the only different is one of the values. for example:

(defn generate-times 
   []
   (5 + 10)
   [x]
   (x + 10)
Which made me feel a default value would be nice.

jeff.engebretsen23:11:37

you can call one arity from the other. So it's kind of like default values.

jeff.engebretsen23:11:48

I'm not sure if there's a community preference.

tkjone23:11:15

what does calling one arity from another look like?

jeff.engebretsen23:11:22

(defn generate-times
[]
(generate-times 5)
[x]
(x + 10))

noisesmith23:11:13

this is almost right but each arity needs a set of parens around it

jeff.engebretsen23:11:06

and the infix should be prefix.

tkjone23:11:53

whoa - that is sexy

tkjone23:11:44

yeah, I guess that would do it. As you mentioned though, does anyone have any idea about the best practice here?

jeff.engebretsen23:11:26

I think multi-arity is cleaner.