#clojure log - Jun 21 2017

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

8:40 ragojae: Why should one chose Aleph of Http-kit for a webapp?

8:41 dysfun: http-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

8:41 ragojae: Isn't it possible to get streams out of http-kit as well - thus making it compatible with manifold & core.async?

8:41 If I'm not wrong it even defaults to giving you java streams

8:42 dysfun: it wouldn't surprise me if you could. aleph seems better maintained

8:44 in general i am fond of ztellman libraries

9:23 foodoo: Hi, 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?

9:24 I want to declare a Var and resolve it later once it is bound at runtime.

9:35 Or, to ask differently: What is the best way to achieve late binding?

9:36 dysfun: give it a var object

9:41 foodoo: (declare foo); (def bar foo); (def foo 42); bar -> still unbound

9:41 Maybe I need to elaborate a bit

9:42 (declare foo-step bar-step baz-step)

9:42 (def pipeline-steps [foo-step bar-step baz-step])

9:43 when 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.

9:44 My current idea is to define foo-step etc. as placeholders that will use find-var to evaluate to the latest binding

9:45 (declare-step foo-step); --> {:ns *ns* :name foo-step}

9:48 But I do not know which Clojure constructs I could use to implement this.

9:51 Frozenlock: dysfun: IIRC Sente now has an Aleph adapter.

9:51 https://github.com/ptaoussanis/sente/blob/master/src/taoensso/sente/server_adapters/aleph.clj

9:52 ragojae:

9:55 foodoo: I found (ns-resolve). That should do the job :)

11:07 osan: when 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:07 anyone got any idea why?

11:07 noncom: but are you sure there's such a var?

11:08 foodoo: osan: Because subs is part of clojure.core and not clojure.string?

11:08 noncom: iirc subs is available without requiring anything

11:08 osan: oh it is?

11:08 my bad, cheers

11:08 foodoo: osan: Intuition has led you astray ;)

11:08 osan: indeed :P

11:09 foodoo: It would indeed make more sense to have subs in clojure.string

11:09 osan: i agree

13:27 guys which style do you prefer, which do you think is easier to debug, which do you prefer aesthetically?

13:32 https://pastebin.com/WMZZJFFX

13:33 justin_smith: I think you're missing something on line 6

13:34 usually I used the second one, but with parens (-> login-url (http/get) (:body) (json/read-str))

13:34 also, often with line breaks

13:45 runejuhl[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:48 ridcully_: you can also do that okish with let: _ (println prevvar)

13:48 or put a doto around

13:49 runejuhl[m]: Yes, lots of ways to skin that cat :)

13:51 ridcully_: 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:51 justin_smith: if anything the let version is more flexible than the threaded one

13:51 you can spy inside a let too

13:55 runejuhl[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:56 justin_smith: runejuhl[m]: "not sure" - I'm 100% sure it is more flexible, let allows operations that can't be done directly in threading

13:56 dysfun: like "do this, then do this"

13:57 justin_smith: of course, things that are more powerful are often more messy - the weaker tool is usually preferrable if both work

13:57 dysfun: rather than do this, then do this on that

13:57 ridcully_: also to be extra picky, the naming there in the let is overly verbose and it's off (first name e.g.)

13:58 some crisp wording would give the let version more appeal in that case

13:58 e.g. response, body, payload

13:59 runejuhl[m]: ...and a `C-c space` to align it

13:59 justin_smith: right, when you only use the symbols locally they don't need to be as specific because their context is clear in that block

14:02 osan: justin_smith: no it works i ran the code both ways

14:03 justin_smith: osan: (json/read-str) should be throwing an error

14:03 either that or it's super weird and just giving you nil or something

14:03 to duplicate the other code you'd have to call it on login-flows-json-str

14:05 osan: justin_smith: there's a (:require [] :as json) in (:ns)

14:05 justin_smith: why do you think it should be throwing an error?

14:06 ridcully_: in the code you pasted earlier, you are calling (json/read-str) in the let example

14:06 osan: justin_smith: clojure.data.json.read-str takes one arg

14:06 ridcully_: one would expect, that json/read-str would take one argument of a string, that is the actual json to parse

14:06 osan: oh yeah

14:06 you guys are right

14:07 dno how that happened

14:26 amalloy: osan: 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:27 osan: amalloy: true

14:28 amalloy: and 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:45 osan: amalloy: good advice

14:45 amalloy: thanks

16:24 lxsameer: hey 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:31 amalloy: that is quite a broad, generic question, which can really only be answered in a broad, generic way: use functions

16:32 lxsameer: amalloy: ok, then how my user can extend the lib based on his/her needs

16:32 dysfun: by writing more functions!

16:33 functions are extensible because you can build new functions that use them

16:33 amalloy: yes, 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:35 lxsameer: aha now i get it

16:35 dysfun: your basic categories of extensibility are higher order functions, prototypes/interfaces, inheritance and multimethods

16:35 pick and choose according to what problem you're trying to solve

16:35 amalloy: (and all of those are just special cases of higher-order functions)

16:36 dysfun: and indeed if you can just keep it as higher order functions, it would be easier

16:36 lxsameer: dysfun: amalloy cool, thanks guys

17:24 osan: what do you guys think of this code? anyways to improve it you think? https://share.riseup.net/#vzf4LaY_yKLH2O4Xv1iBWg

17:26 justin_smith: I would find it a lot more readable if the forms weren't all one liners

17:26 and threading a function literal into map is weird

17:27 just use mapv

17:27 use seq instead of (not (empty? ...))

17:28 (which is explicitly mentioned in the doc of empty?)

17:30 for 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:31 for personaly preference, I find that names that long make things less readable

17:31 osan: justin_smith: thanks, any suggestions for alternative name?

17:31 justin_smith: for 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:32 I 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:33 osan: justin_smith: thanks i agree

18:24 technomancy: I 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:26 anyone have a preferred way to clean this up? http://p.hagelb.org/let-tests.html

18:27 hiredman: I 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:31 another 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:32 paolo`: ?

18:33 hiredman: (which would support some level of non-determinsm in the tests, a response could be X or Y sort of things)

18:33 technomancy: that would certainly make them shorter =)

19:09 lxsameer: is it possible to attach meta data to hash-map keys

19:10 justin_smith: only if the keys are instances of IMeta

19:10 for example keywords can't take metadata

19:11 lxsameer: justin_smith: thanks

19:12 justin_smith: lxsameer: but symbols can have metadata

19:12 people might think you are weird for using symbols though

19:12 amalloy: i would think you're weird for putting metadata on keys of a map specifically

19:12 lxsameer: justin_smith: hmmmm i have big hash-map containing some configuration, i wanted to some how attach some docs to each key

19:13 amalloy: :)) thanks for the heads up

19:13 amalloy: like 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:13 but in your hashmap you already have plenty of space to store information about an entry: in the value!

19:14 lxsameer: amalloy: yeah that's right

19:14 thanks

19:14 amalloy: {:max-memory {:doc "how much memory" :value 1000000}, :language {:doc "what language to speak to the user in" :value "english"}}

19:17 lxsameer: amalloy: thanks man

Logging service provided by n01se.net