Fork me on GitHub
#beginners
<
2020-06-28
>
Jovanny Cruz00:06:32

Hello! Question about Leiningen... How can I declare "global" alises like profiles using ~/.lein/profiles.clj? Is it even possible or aliases can only be declared at project level?

zhuxun202:06:27

Is it possible to add a dependency into deps.edn and have it available in the repl without restarting the repl?

zhuxun202:06:51

Like some sort of "refresh"?

noisesmith02:06:43

there's code that can do it, but it's not part of deps (which exits before your process starts), and it's kind of hacky

noisesmith02:06:50

it can be added to your project as a dep

Lucy Wang03:06:34

just found the old chat can be found on https://clojurians.zulipchat.com/ (not reachable on slack anymore due to the free plan limit), is this a feature provided by zulipchat, or it's something the community builds maually?

seancorfield04:06:16

The @UFNE73UF4 can be added to any channel here to archive conversations to Zulip. It was built by a community member (who also started the Zulip Clojurians community). It's very useful for searching old conversations 🙂 And it's keyboard-driven, which I love!

💯 3
seancorfield04:06:33

There is also @U055W814A which archives conversations to https://clojurians-log.clojureverse.org/ -- also built by a community member (the founder of ClojureVerse I think? Or maybe he took it over from the original author?)

TEYE NARTEY04:06:01

Am Teye and a beginner in Clojure and want someone to mentor me

seancorfield04:06:14

@ics.learncomputer Feel free to ask questions here as you need -- everyone in this channel has opted in to helping beginners!

seancorfield04:06:29

There is a #mentoring channel but folks will want to see how you interact here first before they'll be willing to volunteer as a mentor. So asking questions here will give folks a good sense of where you are in your journey and what your style of learning is...

adam14:06:18

I am experiencing an odd behavior with Ubuntu 20.04/JDK 11 (headless) when I run my uberjar. If I reboot the server, and I launch it, it consistently launches between 5 to 10 seconds. Which is good. But when I stop it and try to launch it again without rebooting the server, it takes forever to relaunch (consistently more than 2 minutes). It just took more than 6 minutes to relaunch. Any idea why that is happening? RAM and CPU usage is low (it’s a DigitalOcean instance with 1GB RAM 2GB swap).

jumar14:06:57

What kind of app it is? How do you know it’s up and running?

jumar14:06:11

Is there something in logs?

adam14:06:16

It’s a Ring app. I am launching it on port 8000. On first launch, it quickly gets launched:

java -jar mypro-0.1.0-SNAPSHOT-standalone.jar
2020-06-28 02:00:29.442:INFO::main: Logging initialized @2886ms to org.eclipse.jetty.util.log.StdErrLog
WARNING: seqable? already refers to: #'clojure.core/seqable? in namespace: clojure.core.incubator, being replaced by: #'clojure.core.incubator/seqable?
2020-06-28 02:00:35.674:INFO:oejs.Server:main: jetty-9.4.28.v20200408; built: 2020-04-08T17:49:39.557Z; git: ab228fde9e55e9164c738d7fa121f8ac5acd51c9; jvm 11.0.7+10-post-Ubuntu-3ubuntu1
2020-06-28 02:00:35.759:INFO:oejs.AbstractConnector:main: Started ServerConnector@4e111e08{HTTP/1.1, (http/1.1)}{0.0.0.0:8000}
2020-06-28 02:00:35.762:INFO:oejs.Server:main: Started @9206ms
Started server on port 8000
On second launch I quickly get to:
2020-06-28 02:01:20.112:INFO::main: Logging initialized @2880ms to org.eclipse.jetty.util.log.StdErrLog
WARNING: seqable? already refers to: #'clojure.core/seqable? in namespace: clojure.core.incubator, being replaced by: #'clojure.core.incubator/seqable?
then it gets stuck until it shows the remaining after several minutes.

adam14:06:42

I just upgraded the server to 8GB RAM 4 CPUs and still have the exact same issue.

adam14:06:08

Maybe I am missing some settings in

:jvm-opts
? I don’t have any set.

adam14:06:09

Picked up JAVA_TOOL_OPTIONS: -Xmx256m <- not helping

hiredman16:06:45

How are you stopping the process? A clean shutdown or just killing it?

hiredman16:06:46

My guess is you are just killing it, so the kernel entry for the socket you are listening on is still in place, and that kernel state is causing the long start times, and rebooting is clearing the state in the kernel which is why you get short start times

adam16:06:50

@U0NCTKEV8 I tried both. killall -9 java and systemctl stop/start myproj.service My SystemD entry looks like this:

[Unit]
Description=App server
After=network.target

[Service]
WorkingDirectory=/home/app
EnvironmentFile=-/home/app/.env_vars
SuccessExitStatus=143
ExecStart=/usr/bin/java -jar /home/app/proj-0.1.0-SNAPSHOT-standalone.jar
User=myuser

[Install]
WantedBy=multi-user.target 

jsn16:06:57

Is it a virtual machine?

adam16:06:21

@UTQEPUEH4 yes, a DigitalOcean instance

jsn16:06:42

Is there any other activity on that virtual machine?

adam16:06:53

Absolutely nothing

adam16:06:21

Just the Clojure app/nginx/postgres for the app itself

jsn16:06:25

A wild guess then: it might be something like reading /dev/random

jumar16:06:37

I’d be surprised if killing the process wouldn’t release all (socket) descriptors opened by the process but it’s an interesting idea...

jsn16:06:00

@UAX4V32SZ try -Djava.security.egd=file:/dev/urandom perhaps?

adam16:06:13

Recreating the server now to try that. I got so frustrated I terminated the server a little while ago lol

hiredman16:06:40

I've had servers where after stopping server for minutes after you get errors when trying to listen on the same socket

jsn16:06:08

@UAX4V32SZ actually, make it -Djava.security.egd=file:/dev/./urandom

🙏 3
adam16:06:25

@UTQEPUEH4 that actually solved the issue!!! I tried restarting 3 times and now it’s restarting in under 15 seconds.

adam16:06:35

Thanks so much

adam16:06:47

What does it do?

jsn16:06:48

Glad I could help. Some software (java too, apparently) reads one of /dev/random or /dev/urandom on Linux to initialize their random numbers generators

jsn17:06:38

There's a very widespread misconception that /dev/random is the proper way to do it. That's wrong, but many programs do it anyway. The proper way to do it is actually /dev/urandom.

jsn17:06:18

One of the unfortunate differences is that reading /dev/random may block if there's "not enough entropy" in the system

jsn17:06:16

Since entropy is gathered via "true random" hardware events, it might be problematic on systems with no load (no other activity, no network activity) and/or on virtual machines

jsn17:06:41

That option just tells java to do the right thing and use non-blocking /dev/urandom instead

adam17:06:33

So some package I am using is reading from /dev/random, or Java itself?

jsn17:06:53

It's Java itself

jumar17:06:49

Does it explain why it works after the restart but the second attempt “fails”?

jsn17:06:37

Yes, there might be a bit more entropy available right after the boot -- because booting a system is a lot of "activity"

jumar17:06:20

Interesting I don’t think I have ever seen this issue before....

jumar17:06:00

One way to discover the root cause could perhaps be running strace.

jsn17:06:14

Yes, strace -f should've shown it

jsn17:06:10

But it's a recognizable issue; I've never seen that with java, but I definitely know the pattern to instantly suspect that it's java doing the /dev/random thing

👍 3
jsn17:06:51

And quick googling then confirmed that it very well could be it

adam17:06:41

Rebooted the server and tried restarting a few more times and it’s coming up as it should. I still can’t believe it 😄

jumar18:06:37

Btw. It seems that related issue has been solved a long time ago, at least for Linux and Solaris: https://bugs.openjdk.java.net/browse/JDK-4705093 But here they say that java's SecureRandom class still uses /dev/random for generating seed information: https://security.stackexchange.com/questions/40633/java-securerandom-doesnt-block-how

adam19:06:08

Maybe Ubuntu 20.04 has not been tested enough yet

adamflax16:06:10

Hi guys I'm fairly new to clojure is there a better way of doing the following? https://pastebin.com/zpuj5nBc My solution works but I feel like there should be a simplier way then combining get and map for what I imagine is a really common task

delaguardo16:06:07

(map :target (zone :a))

delaguardo16:06:58

A map and a key both can be called as a function.

adamflax17:06:27

oh thats really handy to know, I thought having to use :get all the time seemed pretty verbose

adamflax17:06:23

thanks for the help

Stephen Lester18:06:52

I feel dumb but I have been stuck and this is hard to search for.

(ns mynamespace.core
  (:require [hiccup.core :refer :all]
            [hiccup.util :refer :all]))

(raw-string "") ;; "raw-string cannot be resolved"
Same goes for trying hiccup.util/raw-string and I'm not sure what I'm doing wrong here.

Stephen Lester18:06:25

When I inspect it, too, the code doesn't match what is in the repo from 3+ years ago 😮

Stephen Lester18:06:04

/Users/stephen/.m2/repository/hiccup/hiccup/1.0.5/hiccup-1.0.5.jar!/hiccup/util.clj doesn't have any mention of raw-string ... https://github.com/weavejester/hiccup/blob/master/src/hiccup/util.clj#L67

zhuxun218:06:34

Why is https://search.maven.org not able to find most clojure artifacts? I tried "timbre" "datascript" etc. and none of them returned any results ...

phronmophobic19:06:58

many(most?) clojure artifacts are on clojars, https://clojars.org/

zhuxun219:06:10

Thanks @U7RJTCH6J. Unfortunately I am not a fan of http://Clojars.org since the results are sorted terribly... they never put the best-fitting result first

phronmophobic19:06:48

what kind of search are you trying to do?

phronmophobic19:06:08

you may have better luck just searching google/duckduckgo with "clojure <library name>"

phronmophobic19:06:34

or if you're just generally interested in what clojure libraries are out there, https://www.clojure-toolbox.com/

👍 3
zhuxun219:06:01

If you search for "datascript", the first item in the result is "datascript-transit", if you search for "timbre" the first result is "timbre-logstash"

phronmophobic19:06:59

I can't think of a reason for searching clojars directly

phronmophobic19:06:46

if you just do a web search for "clojure datascript", the first result is the github repo which is probably the best result

zhuxun219:06:01

I was looking for the latest version of a particular package

zhuxun219:06:23

You are right about google in general, however, when I'm trying to be precise I don't want to be misguided by occasional wrong first-results in Google.

phronmophobic19:06:28

i would probably still check the website or github repos for this info, but googling "clojars datascript" will also generally work

zhuxun219:06:54

yeah that's what I do most of the time. When I'm trying to be precise I go to https://mvnrepository.com/

👍 3
zhuxun219:06:41

Too bad http://Clojars.org is the "official" one when it's closed to useless

phronmophobic19:06:15

clojars has worked great for me, but if you think there's improvements to be made, it's open source, https://github.com/clojars/clojars-web

zhuxun202:06:50

@U7RJTCH6J Thanks! I should have said it more clearly -- I think clojars is great as a platform and as a tool for publishing clojure packages; my only complaint is that its search engine on its web interface could have been more useful if they could fix the result sorting. I will definitely look into the source code and see if there's anything I can do about it.

👍 3
zhuxun219:06:40

On the other hand, https://mvnrepository.com/ seems to be able to find all the clojure packages

zhuxun219:06:04

Is there any quick way to find out which of my deps are outdated, like `yarn upgrade-interactive` for NodeJS?

Tzafrir Ben Ami19:06:11

if you are using lein, you can use the lein-ancient plugin https://github.com/xsc/lein-ancient to find outdated dependencies

👍 3
zhuxun219:06:18

I am using shadow-cljs so I looked up deps-ancient (a port of ancient to deps) and it seems to work https://github.com/slipset/deps-ancient

jacklombard19:06:03

I want to aot compile my project, is it enough if I add the :gen-class directive to my core namespace which contains the main function?

seancorfield19:06:16

@UJG7AN8LD :gen-class is needed for your main namespace so the -main function gets compiled to a Java main method, but it's not enough by itself to trigger AOT.

seancorfield19:06:30

What tooling are you using? Clojure CLI? Leiningen?

jacklombard19:06:43

I am using lein, yes I think I know the remaining steps, add :aot [my-proj.core] to project.clj and then do a lein uberjar

jacklombard19:06:05

My question was whether I need to add it to any other name spaces

jacklombard19:06:06

Am I missing any other steps? @U04V70XH6

seancorfield19:06:56

No. :gen-class is just to cause the -main function to become a Java-callable method. - is the default prefix for methods. If you had (defn -foo [s] (str "Hello, " s "!")) in that namespace, it would be compiled to a Java-callable foo method of the class.

seancorfield19:06:44

AOT is just calling clojure.core/compile on one or more namespaces. :gen-class signals how a specific namespace should be compiled. Does that help?

seancorfield19:06:41

(if you omit :gen-class, the namespace will still be compiled but you won't have the special treatment of functions starting with - becoming Java-callable methods)

jacklombard19:06:50

Thanks a lot for the response, I understood what you said. And I require the main to become a Java-callable method because when I run the jar file, I will have this main method ready as the entry point? Am I understanding it correctly?

jacklombard20:06:40

The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method, or the namespace has not been AOT-compiled.
This is what I got when I did a lein uberjar and adding gen-class solved the problem. So I am guessing something is looking for a main class when I run the jar and gen-class created that class and the Java-callable method for me.

seancorfield20:06:04

Yup, that's right. In a JAR file, Java expects to call a main() method in the main class (your main namespace).

seancorfield20:06:48

Without :gen-class, the -main function is compiled to class directly with an invoke() method (all Clojure functions are normally compiled that way).

jacklombard20:06:09

Great! Thanks a lot :)

Kazuki Yokoyama19:06:27

Hello, does anyone have a good resource to learn more about assert-expr of clojure.test? Its documentation seems very scarce. Thank you.

noisesmith19:06:25

I've found it very confusing when it was used by coworkers, and I recommend avoiding it

😞 3
noisesmith19:06:40

the tl;dr is that it's a multimethod that lets you make new kinds of is expressions

noisesmith19:06:22

if your whole team is on the same page about them, they can be a useful way to make tests more idiomatic / easier to write and maintain

seancorfield19:06:33

Yeah, it's a pretty low-level piece of functionality https://clojuredocs.org/clojure.test/assert-expr

seancorfield19:06:15

And it's weird because it's a multmethod but it behaves like a macro.

noisesmith19:06:26

the concrete problem I'm referencing when I suggest avoiding it, is that usually when you see (foo x) in a form, you can go in a repl and look at the source or doc of foo

noisesmith19:06:25

but no, with assert-expr, as @U04V70XH6 says, it behaves like a macro but it's a multimethod extension, so you end up with this weird kind of code you never see anywhere else

noisesmith19:06:07

in theory, the solution could be educating about and refining that pattern of dispatch, but we have so many great forms of extension, it's easier to just suggest not using this one unless you know you really know what you are doing

noisesmith19:06:13

if you have collaborators at least

noisesmith19:06:10

luckily in my case I could find the assert-expr via grep of the source files, and work back from there, but if I was using a library, even that would not be an option

noisesmith19:06:27

it undermines the normal self-documentation and inspectability you get with clojure

seancorfield19:06:29

It is only useful if you're writing extensions to clojure.test. I had to learn how to use it when I wrote expectations.clojure.test but it's not easy to use properly.

noisesmith19:06:40

right - I was thinking for a moment, what if more code was written that way? but I don't think that would be a good thing :D

Kazuki Yokoyama19:06:50

And the way to learn it is try and error? It is for a personal project, I see it as an opportunity to learn (and practice a little macro)

Kazuki Yokoyama19:06:58

And what should I use instead to turn the tests more idiomatic?

Kazuki Yokoyama19:06:34

I'll take a look at that! Thank you

seancorfield20:06:26

I did it so I can write (expect ::some-spec (some-expr)) and under the hood it expands to (is (=? ::some-spec (some-expr))) which then goes through assert-expr (for the =? smart equality operator)

Brian Amadio19:06:00

Hi all, I’m a total Clojure noob, and new to the Slack as well. Looking forward to learning from you all and building some fun projects!

Brian Amadio19:06:12

I’m also new to lisps and functional programming, but have a lot of experience with C++, Python, and Go. Any tips on learning materials for newbies would be great!

9
jacklombard20:06:17

I am somewhat of a beginner too and have been doing clojure for the past 7 months professionally. The REPL is your best friend when learning clojure and also while doing anything else.

jacklombard20:06:07

I mean apart from all resources Sean Corfield has listed below

seancorfield20:06:39

Yup, big +1 on the REPL since you can use doc and source to look at how core functions work.

Brian Amadio20:06:46

@U014BBTEFK6 What kind of projects do you build with Clojure?

jacklombard20:06:49

A lot of our microservices run in clojure. From powering a CMS to wrapping elastisearch to analytics

Brian Amadio20:06:10

Nice! Have you built microservices in Golang or Python before? I’m curious about the differences in developer experience and productivity

Brian Amadio20:06:23

I’m building full-stack tools for Data Scientists at my company, and I really like the idea of being able to do the backend and UI in the same language with clojurescript

Brian Amadio20:06:44

Currently we write backend in Golang/Python and UI in Javascript but I’d prefer if I never had to write another line of Javascript again

practicalli-johnny22:06:38

https://practicalli.github.io/ has free learning content for Clojure (and a bit of ClojureScript). Includes videos and online books

👍 3
jacklombard11:06:30

@U0166NHED3M No I havent used them before for microservices. Clojure is really beautiful and makes you really productive, the only caveat is that I miss the auto documentation of types sometimes. Hopefully spec is able to help here

seancorfield20:06:34

Free online stuff includes Clojure for the Brave and True, and Clojure from the Ground Up.

seancorfield20:06:35

Good books to get started include Living Clojure. If you prefer video material, I think Eric Normand has some free stuff on http://PurelyFunctional.tv (his paid courses are excellent).

seancorfield20:06:17

There's also the @jr0cket stuff (I haven't looked at that so I'm not sure what he offers, but I know he does a lot of good learning material).

seancorfield20:06:57

There's also a lot of good stuff linked from https://clojure.org/guides/getting_started

seancorfield20:06:21

This page in particular is a treasure trove of resources https://clojure.org/community/resources

Brian Amadio20:06:14

Alright! Thanks for all the links and tips!

Stephen Lester22:06:01

Anyone have an idea? 😞

dpsutton22:06:36

clj -Sdeps '{:deps {hiccup {:mvn/version "1.0.5"}}}'
Clojure 1.10.1
user=> (require 'hiccup.core 'hiccup.util)
nil
user=> (apropos "raw-string")
()
user=> (apropos "raw")
()
doesn't seem to be any raw-string function. what leads you to believe there is one?

dpsutton22:06:11

also, its pretty uncommon to see :refer all these days. require things with an alias

dpsutton22:06:59

ah. the latest release is 1.0.5 from 2014. 2.0.0 has been in alpha since 2017. if you use the latest alpha, you will have the function.

clj -Sdeps '{:deps {hiccup {:mvn/version "2.0.0-alpha2"}}}'
Downloading: hiccup/hiccup/2.0.0-alpha2/hiccup-2.0.0-alpha2.pom from clojars
Downloading: hiccup/hiccup/2.0.0-alpha2/hiccup-2.0.0-alpha2.jar from clojars
Clojure 1.10.1
user=> (require 'hiccup.util)
nil
user=> (apropos "raw-string")
(hiccup.util/raw-string hiccup.util/raw-string?)
user=>

Stephen Lester22:06:40

"alpha since 2017" explains a whole lot, thanks so much. Not enough coffee today.