Fork me on GitHub

@lockdown- the common idiom you see for that is (->> z (fun-b) (fun-a x y))


(it expands to what you showed, but makes the steps of processing clear)


I see, but in general the concept is not crazy then?


one exception I'd make is (println "foo" "bar" (pr-str baz-data)) - that's perfectly clear with the nested call


crazy as in leads to sloppy/unmaintainable code


Not crazy, but can be hard to read/maintain.


it's a straightforward way to show a series of operations that use the result of the previous operation, which is legitimate, and clearly what you ware doing


you can also use a let block to bind intermediate data, but I'd prefer to see -> or ->> if each step only consumes data from the immediately preceding step


Right. To clarify, the idea of using the evaluation of one form as a parameter to another is not innately bad/crazy/sloppy. But there are a number of ways to make it more maintainable/easier to read: ->, ->>, let, et al.


oh yes, agreed


@noisesmith the let approach is what I'm doing, fun-b inside fun-a in a let but fun-b side effects, was thinking of passing a fun-b call as an arg to make fun-a pure


but what you do above doesn't pass the call - it passes the result of the call (maybe this distinction doesn't matter here)


but you are on the right track - deal with side effects by pulling it up the abstraction stack to callers, rather than pushing it down the stack into callees


yeah, fun-b just returns data, making fun-a just work with values


that way more of your code is pure


sometimes an OO mindset (or something similar) makes people want to hide IO at the bottom of a stack of abstractions, which just multiplies your problems by increasing the amount of side-effecting functions in the codebase


that's what I'm afraid of, but here, these are the same two functions, not more code


when making the change


don't really want to hide it, just group them better to have simpler/better tests


right, getting the value out of IO and passing it into the pure function is the right way to do this when possible


great, thanks


recently saw a video where side-effects are described with maps (returned by functions) and then a "system" takes the descriptions and executes all the side-effects


the author mentioned that is how re-frame does it, but sounded a bit overkill for small apps


yeah, this is an adaptation of a lib for JS where structured data defines updates to be done in a batch because it's a bad idea to do DOM updates directly


but it happens to accomplish this same thing I'm advocating - moving IO and state to the top of your stack of function calls, and pushing pure things to the bottom


well wait, I do a need a third function, can't just put something like (->> z (fun-b) (fun-a x y)) at a top-level


well, you could but it would be bad form


yeah, gross, there should be no side-effects until -main is called


at least in my case, I think it should be that way


right - and a common gotcha for beginners is that even a (def foo ...) will do side effects at file load or even just compilation if ... has side effects


@noisesmith by compilation you mean if someone is doing AOT?


It's not always practical to hoist all of your side-effects right up to the top tho' -- much depends on how write-heavy your app is -- but separating pure and impure is a worthy goal.


This is an experiment of mine in terms of trying to do that separation completely in a generic way. The resulting code was hard to read and certain convenient idioms were hard to express.


true, adding a third fn for every two fns to make one pure doesn't make sense, but adding one to make 10-20 pure seems worth it


hihi all, I'm looking at generating an oauth api token for a service I want to integrate with. I'm not using ring in my application so far, but I found this library: -- has anyone used this in a non-ring context?


Based on your info you shouldn't need to generate oauth token at all


What Sean mentioned is usually enough. Use clj-http client or equivalent to get access token based on the "authorization code" you receive when the user accepts your app as authorized on the OAuth provider's consent page.


@johnjelinek Are you trying to integrate with that service as an OAuth client? Or are you hoping to be an OAuth provide so the service can call you?


@johnjelinek Then you should be able to get the token from the service somehow by authenticating with it.


@seancorfield: at the moment, I want to spin up a datomic ion (HTTP Direct) to receive the auth code from the external service. Then in my repl, I can initiate the oauth2 flow and the service will turn it into a token that I can play with for the duration of my repl session


it looks like this lib is no longer maintained, but it seems to work in a non-ring context so far (for the initiation of the oauth2 flow)


I've never used a library for dealing with OAuth tokens as a client. Just simple HTTP calls has always been enough.

Ahmed Hassan05:05:38

In which directory I should keep my my main.js JavaScript file when using Pedestal to be loaded in index.html? In the body of function named index which is served by interceptor I have put [:script {:src "resources/public/js/main/main.js"}].

Eric Scott13:05:37

Hi- A question about namespaces Suppose you have Two libraries: A-lib and B-lib, each with a module x.core. ;; In A-lib:

(ns x.core)
(defn foo [] (println "Greetings fromm A-lib"))
;; In B-lib:
(ns x.core)
(defn foo [] (println "Greetings fromm B-lib"))
Now you start an app myapp and have these dependencies:
                 [A-lib/x "0.1.0-SNAPSHOT"]
                 [B-lib/x "0.1.0-SNAPSHOT"]
The ambiguity seems to be resolved by arbitrarily picking one:
(ns myapp.core (:require [x.core]))
You get:
"Greetings from A-lib"
Assuming you have no access to the source code of either A-lib or B-lib, is there a way to retroactively disambiguate our 'x' module, either in our project declaration or in the require clause? Thanks.


@eric.d.scott At the bottom, the source for dependencies are resolved from the classpath


(So it is really a question below Clojure/Script.)


Or, another way to put it: Clojure/Script provides no direct way to deal with this issue.

Eric Scott13:05:14

That's what I suspected. I was hoping there would be some provision for doing this. Thanks.


Coming from the pytest python world, I'm used to having parametrize to run a test with multiple cases. What's the clojure way of doing that. Run a simple function with input/output pairs so I don't have to write so many is statements. ( for reference)


I guess are is pretty close to the same thing.


@UHUG06517 I’ve also seen ‘doseq’ used to achieve that. I don’t love that solution but it gets the job done


which framework recommend for a restapi?


@comparalf you could also try bit higher level, works directly from the API in a YAML file.


I'll take a look at both, thanks!

Mario C.15:05:09

I am trying to use the figwheel repl from nRepl. I am using this as a guide but I keep getting Could not locate cljs/stacktrace__init.class or cljs/stacktrace.clj on classpath

Mario C.15:05:31

When calling (use 'figwheel-sidecare.repl-api)

Mario C.15:05:03

I added "src/main/cljs" to my source-paths but keep getting the same error


@mario.cordova.862 what version of CLJS are you using?

Mario C.15:05:00

To start the repl I use lein with-profile clj,dev repl :headless and I have added it to the source-paths for both clj, and dev profiles


try updating to the latest CLJS version - should be 1.10.something

Mario C.15:05:52

Let me check the dep tree

Mario C.15:05:33

Still get the issue, even after fixing the dependency issues

Mario C.15:05:49

Actually i think i know what the problem is

Mario C.15:05:29

It wasn't that I had old CLJS. It was that I didn't have CLJS listed at all in my dependencies for those profiles 😅



Drew Verlee15:05:36

Finally getting around to reading straight through Joy of clojure. I found this remark very interesting > you generally shouldn’t assume seq has been called on your collection arguments, but instead call seq in the function itself and process based on its result. Using this approach fosters a more generic handling of collections, a topic that we explore in great detail in chapter 5. It seems i can't wait for chapter 5 🙂, does this advice suggest that you call seq on all collections arguments? I don't see this widely done, though maybe im not looking hard enough.

Drew Verlee15:05:18

I mean, i'm not sure how it helps really. dont most functions that work on collections convert them to seqs?


I think most of the time when we work with things as seqs, we are using functions that already implictly call seq


so this would be advice for making new collection functions that aren't built on the existing ones?


How can I update all dependencies in project.clj? Is it generally a good idea to update them all?


at least the project owner diisapproves of that, but there's a plugin (lein-ancient) that helps find deps that have new versions and even automatically update your project file iirc


Struggling with time stamps. I have a luminus h2 database with a timestamp field. I have a test that posts a time using java.util.Date. then I check to make sure it updated and I get a difference like:

- {:last_login #inst "2019-05-29T19:28:30.456-00:00"}
+ {:last_login #object[java.time.LocalDateTime 0x7c1b5b8f "2019-05-29T15:28:30.456"]}
Test looks like:
(let [time (java.util.Date.)]
      (is (= 1 (db/update-time!
                {:user_name  "sam_smith"
                 :last_login time})))
      (is (= {:user_name   "sam_smith"
              :last_login time}
             (db/get-user t-conn {:user_name "sam_smith"}))))
Any advice on working with java datetimes like this?


Sounds like something in Luminus has extended's protocols for column reading to produce Java Time values.


Which is probably a good thing -- and might encourage you to also use Java Time instead of java.util.Date?


(java.time.LocalDateTime/now) is the modern equivalent to (java.util.Date.)


Ahhh...That makes more sense to me. Their tutorial had just used java.util.Date. so I grabbed that one. Worked like a charm!


Yeah, a lot of tutorials still refer to java.util.Date. because it's been around forever but since Java 8 came out that's a bit of an anachronism really... but the default behavior of is to traffic in the older types (`java.sql.Date` and java.sql.Timestamp as well as java.util.Date) -- because that's what the JDBC drivers all do by default.

Tangible Dream21:05:28

I’m trying to test with clojure. For some reason I am not able to include clojure.test into my code

Tangible Dream21:05:48

(ns clojure.test)
(testing "Arithmetic"
  (testing "with positive integers"
    (is (= 4 (+ 2 2)))
    (is (= 7 (+ 3 4))))
  (testing "with negative integers"
    (is (= -4 (+ -2 -2)))
    (is (= -1 (+ 3 -4)))))

Tangible Dream21:05:58

clojure blah-test.clj 
Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: testing in this context, compiling:(/Users/test/blah-test.clj:2:1)
	at clojure.lang.Compiler.analyze(
	at clojure.lang.Compiler.analyze(
	at clojure.lang.Compiler$InvokeExpr.parse(
	at clojure.lang.Compiler.analyzeSeq(
	at clojure.lang.Compiler.analyze(
	at clojure.lang.Compiler.analyze(
	at clojure.lang.Compiler$BodyExpr$Parser.parse(
	at clojure.lang.Compiler$FnMethod.parse(
	at clojure.lang.Compiler$FnExpr.parse(
	at clojure.lang.Compiler.analyzeSeq(
	at clojure.lang.Compiler.analyze(
	at clojure.lang.Compiler.eval(
	at clojure.lang.Compiler.load(
	at clojure.lang.Compiler.loadFile(
	at clojure.main$load_script.invokeStatic(main.clj:278)
	at clojure.main$script_opt.invokeStatic(main.clj:338)
	at clojure.main$script_opt.invoke(main.clj:333)
	at clojure.main$main.invokeStatic(main.clj:424)
	at clojure.main$main.doInvoke(main.clj:387)
	at clojure.lang.RestFn.applyTo(
	at clojure.lang.Var.applyTo(
	at clojure.main.main(
Caused by: java.lang.RuntimeException: Unable to resolve symbol: testing in this context
	at clojure.lang.Util.runtimeException(
	at clojure.lang.Compiler.resolveIn(
	at clojure.lang.Compiler.resolve(
	at clojure.lang.Compiler.analyzeSymbol(
	at clojure.lang.Compiler.analyze(
	... 21 more

Tangible Dream21:05:59

same with

(require '(clojure.test))


which does the same thing :refer :all does. neither are recommended nowadays. to make yours work, you could make it something like:

(ns blah-test
  (:require [clojure.test :refer :all]))

Tangible Dream21:05:23

let me try the repl


note that (ns ...) at the top of your file should not be clojure.test (that’s the name of the testing library) but something matching your file hierarchy


your problem is you created a namespace named clojure.test in the repl with your first ns form, which isn't the clojure.test you want

Tangible Dream21:05:44

That worked zirth

Tangible Dream21:05:32

Thanks for the necessary step I was not adding @hiredman


if you restarted your repl and tried again with a different namespace name it would likely work


Hi there! This is the first time that I've had to handle circular function calls in Clojure. In the snippet below parse-expr calls parse-oper-exprs, and parse-oper-exprs calls parse-expr to parse sub-expressions. What the is idiomatic way to avoid the "Unable to resolve symbol: parse-expr in this context" error caused by calling parse-expr on line 3 of the code below? Is there a way to lazily refer to a function that will be defined "later"?

(defn parse-oper-exprs [oper exprs]
  (->> exprs
       (map parse-expr)
       (map #(str "(" % ")"))
       (string/join (str " " oper " "))))

(defn parse-expr [oper exprs]
    (= oper "+")
    (parse-oper-exprs "+" exprs)


Have a look at clojure.core/declare.

💯 4

Great! Thanks, @U050CT4HR! I'm clearly still getting to know the core language.


Everyone starts somewhere. 🙂 Keep going!


other options include letfn which allows circular references, and trampoline which allows a work around for no tail call elimination, but here declare should be fine


Wow! Thanks, @noisesmith. That brings this issue up to 3xTIL for me 😜


declare is the straightforward one, and what you usually want


Yeah, it does seem like the best fit for the situation. Regardless, I appreciate the introduction to more core functions I was unaware of 🙂