2017-06-21
| 08:40 | ragojae | Why should one chose Aleph of Http-kit for a webapp? |
| 08: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 |
| 08:41 | ragojae | Isn't it possible to get streams out of http-kit as well - thus making it compatible with manifold & core.async? |
| 08:41 | ragojae | If I'm not wrong it even defaults to giving you java streams |
| 08:42 | dysfun | it wouldn't surprise me if you could. aleph seems better maintained |
| 08:44 | dysfun | in general i am fond of ztellman libraries |
| 09: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? |
| 09:24 | foodoo | I want to declare a Var and resolve it later once it is bound at runtime. |
| 09:35 | foodoo | Or, to ask differently: What is the best way to achieve late binding? |
| 09:36 | dysfun | give it a var object |
| 09:41 | foodoo | (declare foo); (def bar foo); (def foo 42); bar -> still unbound |
| 09:41 | foodoo | Maybe I need to elaborate a bit |
| 09:42 | foodoo | (declare foo-step bar-step baz-step) |
| 09:42 | foodoo | (def pipeline-steps [foo-step bar-step baz-step]) |
| 09:43 | foodoo | 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. |
| 09:44 | foodoo | My current idea is to define foo-step etc. as placeholders that will use find-var to evaluate to the latest binding |
| 09:45 | foodoo | (declare-step foo-step); --> {:ns *ns* :name foo-step} |
| 09:48 | foodoo | But I do not know which Clojure constructs I could use to implement this. |
| 09:51 | Frozenlock | dysfun: IIRC Sente now has an Aleph adapter. |
| 09:51 | Frozenlock | https://github.com/ptaoussanis/sente/blob/master/src/taoensso/sente/server_adapters/aleph.clj |
| 09:52 | Frozenlock | ragojae: |
| 09: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 | osan | 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 | osan | 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 | osan | guys which style do you prefer, which do you think is easier to debug, which do you prefer aesthetically? |
| 13:32 | osan | https://pastebin.com/WMZZJFFX |
| 13:33 | justin_smith | I think you're missing something on line 6 |
| 13:34 | justin_smith | usually I used the second one, but with parens (-> login-url (http/get) (:body) (json/read-str)) |
| 13:34 | justin_smith | 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 | ridcully_ | 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 | justin_smith | 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 | ridcully_ | some crisp wording would give the let version more appeal in that case |
| 13:58 | ridcully_ | 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 | justin_smith | either that or it's super weird and just giving you nil or something |
| 14:03 | justin_smith | 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 | osan | 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 | osan | you guys are right |
| 14:07 | osan | 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 | osan | 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 | dysfun | 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 | dysfun | 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 | justin_smith | and threading a function literal into map is weird |
| 17:27 | justin_smith | just use mapv |
| 17:27 | justin_smith | use seq instead of (not (empty? ...)) |
| 17:28 | justin_smith | (which is explicitly mentioned in the doc of empty?) |
| 17:30 | justin_smith | 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 | justin_smith | 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 | justin_smith | 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 | technomancy | 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 | hiredman | 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 | justin_smith | 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 | justin_smith | 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 | lxsameer | 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 | amalloy | 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 | lxsameer | 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 |