#clojure logs

2017-06-21

08:40ragojaeWhy should one chose Aleph of Http-kit for a webapp?
08:41dysfunhttp-kit integrates with sente, so if you use sente, it's a good choice. aleph uses manifold, so if you use manifold or core.async, it might be a good choice
08:41ragojaeIsn't it possible to get streams out of http-kit as well - thus making it compatible with manifold & core.async?
08:41ragojaeIf I'm not wrong it even defaults to giving you java streams
08:42dysfunit wouldn't surprise me if you could. aleph seems better maintained
08:44dysfunin general i am fond of ztellman libraries
09:23foodooHi, I need a fn that takes a hash-map {:ns *ns* :name name} and translates this to (find-var (:ns m)/(:name m)); how can I accomplish this?
09:24foodooI want to declare a Var and resolve it later once it is bound at runtime.
09:35foodooOr, to ask differently: What is the best way to achieve late binding?
09:36dysfungive it a var object
09:41foodoo(declare foo); (def bar foo); (def foo 42); bar -> still unbound
09:41foodooMaybe I need to elaborate a bit
09:42foodoo(declare foo-step bar-step baz-step)
09:42foodoo(def pipeline-steps [foo-step bar-step baz-step])
09:43foodoowhen I later create bindings to foo-step, bar-step and baz-steps, the object references in pipeline-steps will still point to the old, uninitialized objects.
09:44foodooMy current idea is to define foo-step etc. as placeholders that will use find-var to evaluate to the latest binding
09:45foodoo(declare-step foo-step); --> {:ns *ns* :name foo-step}
09:48foodooBut I do not know which Clojure constructs I could use to implement this.
09:51Frozenlockdysfun: IIRC Sente now has an Aleph adapter.
09:51Frozenlockhttps://github.com/ptaoussanis/sente/blob/master/src/taoensso/sente/server_adapters/aleph.clj
09:52Frozenlockragojae:
09:55foodooI found (ns-resolve). That should do the job :)
11:07osanwhen running (require '[clojure.string :as clj-str]) in the repl i get a return of nil but then if i try to call (clj-str/subs "hello, world!" 0 5) i get a runtime exception saying no such var as clj-str/subs
11:07osananyone got any idea why?
11:07noncombut are you sure there's such a var?
11:08foodooosan: Because subs is part of clojure.core and not clojure.string?
11:08noncomiirc subs is available without requiring anything
11:08osanoh it is?
11:08osanmy bad, cheers
11:08foodooosan: Intuition has led you astray ;)
11:08osanindeed :P
11:09foodooIt would indeed make more sense to have subs in clojure.string
11:09osani agree
13:27osanguys which style do you prefer, which do you think is easier to debug, which do you prefer aesthetically?
13:32osanhttps://pastebin.com/WMZZJFFX
13:33justin_smithI think you're missing something on line 6
13:34justin_smithusually I used the second one, but with parens (-> login-url (http/get) (:body) (json/read-str))
13:34justin_smithalso, often with line breaks
13:45runejuhl[m]IMO it depends on the context, but I prefer the threaded one. It makes it really to add a line of debug printing (e.g. `taoensso.timbre/spy`), although stepping through the function in the CIDER debugger becomes a bit harder
13:48ridcully_you can also do that okish with let: _ (println prevvar)
13:48ridcully_or put a doto around
13:49runejuhl[m]Yes, lots of ways to skin that cat :)
13:51ridcully_yet i'd got for the threading too. but i would just name it load-json or something -- other than the naming of the function and the param this is not that much special to login flows
13:51justin_smithif anything the let version is more flexible than the threaded one
13:51justin_smithyou can spy inside a let too
13:55runejuhl[m]Not sure if the let version is more flexible, but visually it can easily get a bit messy with a bunch of let statements compared to threading. Knowing that the expressions are processed top-down without any unrelated variables in between (as you could have in a let) makes it easy to skim and get an idea about what's happening
13:56justin_smithrunejuhl[m]: "not sure" - I'm 100% sure it is more flexible, let allows operations that can't be done directly in threading
13:56dysfunlike "do this, then do this"
13:57justin_smithof course, things that are more powerful are often more messy - the weaker tool is usually preferrable if both work
13:57dysfunrather than do this, then do this on that
13:57ridcully_also to be extra picky, the naming there in the let is overly verbose and it's off (first name e.g.)
13:58ridcully_some crisp wording would give the let version more appeal in that case
13:58ridcully_e.g. response, body, payload
13:59runejuhl[m]...and a `C-c space` to align it
13:59justin_smithright, when you only use the symbols locally they don't need to be as specific because their context is clear in that block
14:02osanjustin_smith: no it works i ran the code both ways
14:03justin_smithosan: (json/read-str) should be throwing an error
14:03justin_smitheither that or it's super weird and just giving you nil or something
14:03justin_smithto duplicate the other code you'd have to call it on login-flows-json-str
14:05osanjustin_smith: there's a (:require [] :as json) in (:ns)
14:05osanjustin_smith: why do you think it should be throwing an error?
14:06ridcully_in the code you pasted earlier, you are calling (json/read-str) in the let example
14:06osanjustin_smith: clojure.data.json.read-str takes one arg
14:06ridcully_one would expect, that json/read-str would take one argument of a string, that is the actual json to parse
14:06osanoh yeah
14:06osanyou guys are right
14:07osandno how that happened
14:26amalloyosan: you don't have to pick one or the other. give names to intermediate variables that can be given useful names, and leave the others anonymous by threading them through
14:27osanamalloy: true
14:28amalloyand even when making something anonymous, you don't have to thread it. i would probably have written something like (-> (:body (http/get login-url)) (json/read-str)), to emphasize the important :body and http/get stuff and deemphasize json/read-str, which feels like more of a bookkeeping detail to me
14:45osanamalloy: good advice
14:45osanamalloy: thanks
16:24lxsameerhey guys, I'm looking forward to design an extensible library. but I'm not sure which is the best approach to it, do you know any reading matterial about this ?
16:31amalloythat is quite a broad, generic question, which can really only be answered in a broad, generic way: use functions
16:32lxsameeramalloy: ok, then how my user can extend the lib based on his/her needs
16:32dysfunby writing more functions!
16:33dysfunfunctions are extensible because you can build new functions that use them
16:33amalloyyes, i don't just mean that you should defn things. your functions should accept functions as arguments, and you should have functions that return functions so that you can compose them in interesting ways
16:35lxsameeraha now i get it
16:35dysfunyour basic categories of extensibility are higher order functions, prototypes/interfaces, inheritance and multimethods
16:35dysfunpick and choose according to what problem you're trying to solve
16:35amalloy(and all of those are just special cases of higher-order functions)
16:36dysfunand indeed if you can just keep it as higher order functions, it would be easier
16:36lxsameerdysfun: amalloy cool, thanks guys
17:24osanwhat do you guys think of this code? anyways to improve it you think? https://share.riseup.net/#vzf4LaY_yKLH2O4Xv1iBWg
17:26justin_smithI would find it a lot more readable if the forms weren't all one liners
17:26justin_smithand threading a function literal into map is weird
17:27justin_smithjust use mapv
17:27justin_smithuse seq instead of (not (empty? ...))
17:28justin_smith(which is explicitly mentioned in the doc of empty?)
17:30justin_smithfor example, the body of get-all-login-types-strings would be much more readable as (mapv #(get % "type") (get-all-login-types-hasmaps login-url))
17:31justin_smithfor personaly preference, I find that names that long make things less readable
17:31osanjustin_smith: thanks, any suggestions for alternative name?
17:31justin_smithfor example, the namespace ends in "login" and every single thing you define in the namespace has "login" in the name and every function binds an arg to a name with "login" in it
17:32justin_smithI think the code would become more readable if "login" were just assumed context based on the ns and doc strings, and the word login were removed from all other names
17:33osanjustin_smith: thanks i agree
18:24technomancyI have a test that's 50 lines of "make this HTTP request and then check the response and use the response to generate another response" and it's just a huge let block with a bunch of res (http/get ...)\n _ (is (= 200 (:status res)))\n res (http/get ...) back and forth
18:26technomancyanyone have a preferred way to clean this up? http://p.hagelb.org/let-tests.html
18:27hiredmanI have been writing the same kind of tests, and I feel like you should be able to do something with as->, but haven't nailed it down
18:31hiredmananother thought I've had is to make your tests in to a finite state transducer (responses are inputs, requests are ouputs) and then assert it reaches an accepted state at the end
18:32paolo`?
18:33hiredman(which would support some level of non-determinsm in the tests, a response could be X or Y sort of things)
18:33technomancythat would certainly make them shorter =)
19:09lxsameeris it possible to attach meta data to hash-map keys
19:10justin_smithonly if the keys are instances of IMeta
19:10justin_smithfor example keywords can't take metadata
19:11lxsameerjustin_smith: thanks
19:12justin_smithlxsameer: but symbols can have metadata
19:12justin_smithpeople might think you are weird for using symbols though
19:12amalloyi would think you're weird for putting metadata on keys of a map specifically
19:12lxsameerjustin_smith: hmmmm i have big hash-map containing some configuration, i wanted to some how attach some docs to each key
19:13lxsameeramalloy: :)) thanks for the heads up
19:13amalloylike if you're using a symbol as a key, sure, and the symbol happens to already have some metadata on it, and you put that in a map: no problem
19:13amalloybut in your hashmap you already have plenty of space to store information about an entry: in the value!
19:14lxsameeramalloy: yeah that's right
19:14lxsameerthanks
19:14amalloy{:max-memory {:doc "how much memory" :value 1000000}, :language {:doc "what language to speak to the user in" :value "english"}}
19:17lxsameeramalloy: thanks man