2014-08-31
| 00:20 | meoblast001 | is there a way to map in clojure and get the previous item without using reduce? |
| 00:33 | xeqi | ,(map (juxt identity inc) [1 2 3]) |
| 00:33 | clojurebot | ([1 2] [2 3] [3 4]) |
| 00:33 | xeqi | meoblast001: ^ ? |
| 00:34 | maravillas | ,(let [c (range 4)] (map vector c (drop 1 c))) |
| 00:34 | clojurebot | ([0 1] [1 2] [2 3]) |
| 00:34 | meoblast001 | hmm. that works i think |
| 00:34 | xeqi | or did you mean the previous in the list? |
| 00:34 | meoblast001 | previous or next works really |
| 00:34 | maravillas | ,(map identity (partition 2 1 (range 4))) |
| 00:34 | clojurebot | ((0 1) (1 2) (2 3)) |
| 00:35 | xeqi | meoblast001: then something like maravillas's answer |
| 00:35 | meoblast001 | hmm |
| 00:35 | meoblast001 | i don't think i understand juxt :/ |
| 00:36 | meoblast001 | maravillas: ah, yes. just throwing the partition in could do it |
| 00:36 | meoblast001 | thanks |
| 00:36 | maravillas | welcome :) |
| 00:36 | gws | ,(map (juxt inc) [1 2 3]) |
| 00:37 | clojurebot | ([2] [3] [4]) |
| 00:37 | gws | ,(map (juxt inc dec) [1 2 3]) |
| 00:37 | clojurebot | ([2 0] [3 1] [4 2]) |
| 00:38 | gws | meoblast001: does that help? |
| 00:39 | meoblast001 | hmm |
| 00:39 | gws | so juxt produces a new function which will call each of the functions you passed to it on the element you give the new 'juxt-function', and return a vector with those results |
| 00:39 | meoblast001 | so it takes arbitrary functions with 2 parameter |
| 00:39 | meoblast001 | and creates one function with 1 parameter |
| 00:40 | gws | you can give juxt as many functions as you like |
| 00:40 | gws | as i did above |
| 00:40 | meoblast001 | that 1 parameter is a list,and it applies those arbitrary functions to all of those functions to each element in the list |
| 00:40 | meoblast001 | hmmm okay |
| 00:40 | meoblast001 | makes sense. thanks |
| 00:40 | gws | ,(map (juxt inc dec inc dec) [1 2 3]) |
| 00:40 | clojurebot | ([2 0 2 0] [3 1 3 1] [4 2 4 2]) |
| 00:41 | meoblast001 | ,((juxt inc dec) 5) |
| 00:41 | clojurebot | [6 4] |
| 00:41 | meoblast001 | yeah, makes sense |
| 00:50 | wildnux | when i do (seq "abcd") it shows ("a", "b", "c", "d") in clojurescript but shows (\a, \b, \c, \d) in clojure, why is it different, and how do i know which "seq" funtion i am using? |
| 00:51 | wildnux | how do i know the full namespaced form of a function or var? |
| 00:52 | rhg135 | wildnux, in js there are no characters, they're single char strings |
| 00:53 | wildnux | rhg135: aah :) |
| 00:53 | wildnux | rhg135: how do i get the full namespaced form of a function/symbol/vars in clojure? |
| 00:53 | wildnux | i thought #'varname would show but it doesnot :D |
| 00:53 | rhg135 | ,(symbol (resolve '+)) |
| 00:53 | clojurebot | #<ClassCastException java.lang.ClassCastException: clojure.lang.Var cannot be cast to java.lang.String> |
| 00:53 | rhg135 | hmm |
| 00:55 | rhg135 | ,(symbol (-> (resolve '+) str (subs 2))) |
| 00:55 | clojurebot | clojure.core/+ |
| 00:55 | rhg135 | very hackish tho |
| 00:55 | verma | the syntax quote should work too right? |
| 00:55 | verma | ,`+ |
| 00:55 | clojurebot | clojure.core/+ |
| 00:55 | rhg135 | oh |
| 00:55 | rhg135 | duh |
| 00:55 | rhg135 | thank you |
| 00:56 | verma | :) |
| 00:56 | wildnux | what does resolve do? |
| 00:56 | rhg135 | resolves a symbol to a var in clj |
| 01:02 | fifosine | ,(let [word "0123"] |
| 01:02 | fifosine | (loop [coll (butlast word)] |
| 01:02 | fifosine | (if (empty? coll) |
| 01:02 | fifosine | (println (last word)) |
| 01:02 | fifosine | (do |
| 01:02 | fifosine | (println (first coll)) |
| 01:02 | fifosine | (println "join") |
| 01:02 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 01:02 | fifosine | (recur (rest coll)))))) |
| 01:07 | opqdonut | fifosine: you should've given the whole sexp on one line |
| 01:15 | fifosine | What's a macro that will take something like |
| 01:15 | fifosine | ,(take 5 (repeat '(println 5))) |
| 01:15 | clojurebot | ((println 5) (println 5) (println 5) (println 5) (println 5)) |
| 01:15 | fifosine | and wrap it in a do form? |
| 01:57 | blaenk | I realize this may be a very broad/open question, but can anyone imagine why it takes two sends for my core.async to register a receive? |
| 01:58 | blaenk | I made the channel with (chan), and am only using put! and <! |
| 02:16 | harja | Hi all, a very dumb question, how do I perform a long lasting calculation once and bind it to a name in the ns? I tried (def foo (filter ... pmap ....)) |
| 02:17 | harja | hm, now it was instantaneous... what the |
| 02:17 | harja | So that is the right way then? :) |
| 07:50 | kqr | haroldwu, your question isn't entirely clear, but it's possible that filter/map doesn't perform the computation until it is needed, and then it's only done once |
| 07:50 | kqr | haroldwu, never mind |
| 07:50 | kqr | haroldwu, that was meant for someone else who isn't hear anymore and i'm tired enough to not notice the tab completion going wrong |
| 07:54 | Rhainur | kqr: haha I was trying to figure out where the question was |
| 08:18 | martinklepsch | in the core.async documentation functions like map< have a note "Deprecated - this function will be removed. Use transformer instead" — whats a transformer in that context? |
| 08:18 | john2x | hello. how do I stop a function from running in a CIDER repl? |
| 08:19 | john2x | martinklepsch: I think they refer to transducers http://blog.cognitect.com/blog/2014/8/6/transducers-are-coming |
| 08:21 | john2x | the post includes an example using it with channels.. so the doc could be a typo/needs updating.. |
| 08:21 | kqr | yeah that looks like that'd be it |
| 08:23 | john2x | ah here "So, reducing function transformers are getting a name - 'transducers', and first-class support in Clojure core and core.async." |
| 08:30 | kqr | is there some version of contains? that works for a set of keys, and checks if all of them exists in the indexable? (as opposed to some which only checks for if at least one of them exists) |
| 08:31 | martinklepsch | john2x: that was the first thing that popped to my mind as well but the name confused me. thanks! |
| 08:32 | kqr | ah, (every?) does that, it seems |
| 08:32 | kqr | wait no |
| 08:32 | kqr | that's not quite it either I don't think |
| 08:35 | john2x | kqr: superset? |
| 08:35 | john2x | ah but both needs to be sets |
| 08:36 | kqr | yeah |
| 08:36 | kqr | if it helps, what is happening is that i'm trying to write a test for a function that returns a map |
| 08:36 | kqr | that map is supposed to have a few things |
| 08:36 | kqr | though now that I say it |
| 08:36 | kqr | i think I might be doing the entire thing wrong |
| 08:52 | kqr | but how *do* I express "I want this map to be equal to this map except it might contain some more things?" |
| 08:52 | kqr | it's not a transitive relation, but it shouldn't be too weird anyway, I think |
| 08:53 | kqr | it's like superset? but for maps |
| 08:54 | kqr | I guess I can convert to sets and then check superset? |
| 08:54 | ephemeron | kqr: There are many ways to approach the problem; if you would like to use sets, you can just extract the keys from the map with `keys`. |
| 08:55 | kqr | ephemeron, in this case I realised I want keys and values |
| 08:55 | john2x | hmm why does `((fn [] [:a :b]))` work but `(#([:a :b]))` doesn't? |
| 08:55 | kqr | ephemeron, so I have a function that returns {:name "kqr" :age 27 :occupation :unemployed} and I want to check that it contains *at least* {:name "kqr" :age 27} |
| 08:55 | kqr | but it can contain more than that |
| 08:56 | kqr | john2x, it evaluates the thing inside #() as something inside normal parens |
| 08:56 | kqr | john2x, with the exception of argument expansion |
| 08:57 | kqr | john2x, so it tries to interpret your vector as a function or special form, I guess? |
| 08:57 | kqr | john2x, #(quote [1 2]) works |
| 08:57 | kqr | john2x, so does #(identity [1 2]) |
| 08:58 | ephemeron | kqr: Are you looking to validate the values, or just check if they are present? |
| 08:58 | john2x | oh so it's more ((fn [] ([:a :b])))? |
| 08:58 | kqr | john2x, exactly |
| 08:58 | john2x | ok, makes sense. thanks |
| 08:58 | kqr | ephemeron, i'm writing a test for a parser. i give it a string and I want to check that it gives me the correct map back (which contains the result of the parse) |
| 09:01 | ephemeron | kqr: If you trust the values and only want to verify that the required keys are present, |
| 09:02 | ephemeron | you could do e.g. (superset? (into #{} (keys some-map)) required-keys) |
| 09:02 | kqr | ephemeron, I don't trust the values :> |
| 09:07 | ephemeron | If it is just for a one-off predicate, you could convert both the to-be-tested map and the test-map to sets; for full validation, you might want to seek a library. |
| 09:09 | kqr | thanks |
| 09:09 | ephemeron | e.g. (into #{} {:a 1 :b 2 :c 3}) is a superset of (into #{} {:a 1 :b 2}) |
| 09:09 | ephemeron | but not of (into #{} {:a 1 :b 3}). |
| 09:12 | kqr | is there a particular reason to use (partial into #{}) instead of (set)? |
| 09:12 | gfredericks | kqr: into uses transients |
| 09:12 | gfredericks | until 1.7, then clojure.core/set should be upgraded to use transients as well |
| 09:13 | kqr | ah |
| 09:40 | kqr | wow I went from trying to write a few tests to majorly reworking parts of my design to be much better |
| 09:40 | kqr | that's what I really like about tests |
| 10:44 | kqr | hm |
| 10:44 | kqr | what I don't like is that so many functions return nil when they fail |
| 10:46 | mi6x3m | kqr: why is this? |
| 10:47 | kqr | maybe that's just me but it feels like I have to do so many explicit checks |
| 10:47 | kqr | though perhaps I should just set up a precondition on my function that guarantees no nils creeping in |
| 10:51 | kqr | mi6x3m, what my function does is it takes a map, and then produces a new map from it |
| 10:51 | kqr | mi6x3m, but if the original map doesn't have all the values it's supposed to, the new map will contain nils in certain places |
| 10:51 | kqr | mi6x3m, which is bad |
| 10:52 | kqr | mi6x3m, because then i'll use the new map expecting it to have no nils in those places, and whenever the program finally crashes or shows bad behaviour, the cause is far from the effect |
| 10:55 | thesaskwatch | Hi, why when I do (swap! (atom "abc") str "def") I get abcdef instead of def? |
| 10:57 | thesaskwatch | ok, now I know |
| 10:57 | thesaskwatch | nvm |
| 10:57 | ephemeron | thesaskwatch: `swap!` passes the current value of the atom to the applied function. |
| 10:57 | ephemeron | You most likely want `reset!` |
| 10:58 | thesaskwatch | ephemeron: thanks .. you I should just read the friendly manual |
| 10:58 | thesaskwatch | you -> yeah |
| 10:59 | jbaiter | when i open a repl with 'lein repl', how can I add the current working directory to the classpath? |
| 11:00 | jbaiter | when i try to do '(use my-ns)' it says that it can't find "my_ns.clj" on the classpath, even though a file with that name exists in the directory i start the repl from |
| 11:18 | fifosine | I've got these two function which follow the same form https://www.refheap.com/89623 in which a no-arg, side-effectful function is executed in between the execution of a one-arg, side-effectful function for each element in a list. Is there a way to write a function that abstracts this form based on the two functions and the collection? |
| 11:25 | mi6x3m | fifosine: some more info please? |
| 11:25 | mi6x3m | I see they are quite similar |
| 11:25 | fifosine | mi6x3m: What info do you need? |
| 11:25 | mi6x3m | yet how many such functions do you expect to have? |
| 11:25 | fifosine | I expect 1 function to abstract the similar functionality seen in the paste |
| 11:26 | mi6x3m | ehm, i'm not sure if I am going to do that |
| 11:26 | mi6x3m | in fact, in their current form |
| 11:26 | mi6x3m | both functions are extremely hard to comprehend |
| 11:27 | mi6x3m | for someone else than you |
| 11:28 | fifosine | maybe I can make more sense of them: the doseq is there only to execute the list of functions that's being created. the list of functions is created by the interposing of 1) a sleep function and 2) a function that makes a noise for each dit-dah in a khar |
| 11:28 | fifosine | that's in the first function |
| 11:29 | fifosine | the second is the same but the sleep function is different and it makes noises for each khar in a word instead of dit-dah in a khar |
| 11:33 | mi6x3m | fifosine: I see |
| 11:33 | mi6x3m | well, I would first start by abstracting the xyz-to-sound function |
| 11:34 | mi6x3m | because they are quite similar |
| 11:34 | fifosine | right, that's what I'm asking for help on |
| 11:35 | mi6x3m | fifosine: first, let's see about the states |
| 11:35 | mi6x3m | word-to-sound has side effects so I think 'read-word!' is more suitable |
| 11:35 | mi6x3m | or something like that |
| 11:36 | mi6x3m | then instead of using interpose |
| 11:36 | mi6x3m | you can just do li |
| 11:37 | mi6x3m | (doseq [c (charater...)] |
| 11:37 | mi6x3m | (read-char! c) |
| 11:37 | mi6x3m | (sleep)) |
| 11:37 | mi6x3m | this would make it a bit more readable |
| 11:37 | fifosine | but then there's an added sleep at the end. This is the purpose of the transpose call |
| 11:39 | mi6x3m | well you are introducing aritificial complexity right now with all the anonymous functions |
| 11:39 | mi6x3m | so output the first element separately and then the doseq loop |
| 11:43 | mi6x3m | fifosine: something like that, for starters |
| 11:43 | mi6x3m | http://pastebin.com/ciLKD9mh |
| 11:43 | fifosine | ok, that makes sense, thanks! |
| 11:44 | mi6x3m | fifosine: then you immediately see the pattern for abstraction |
| 11:44 | mi6x3m | 1. the function, read-char! |
| 11:44 | mi6x3m | 2. the delay |
| 11:44 | mi6x3m | 3. the collection, chars |
| 11:45 | mi6x3m | read-with-delay! f d col |
| 12:02 | justin_smith | kqr: hey, have you considered using schema to verify your maps? |
| 12:04 | kqr | justin_smith, no! what's that? |
| 12:04 | justin_smith | https://github.com/Prismatic/schema |
| 12:04 | justin_smith | kqr: it's a lib designed to verify the structure and contents of clojure data |
| 12:04 | justin_smith | which sounds perfect for what you are trying to do |
| 12:05 | justin_smith | you can use it to annotate functions, giving a name to the structure of data it should take or return |
| 12:06 | kqr | that looks amazing |
| 12:09 | justin_smith | sure beats a bunch of calls to nil? |
| 12:12 | kqr | sure does |
| 13:01 | fifosine | ,(doseq [x '((println 1) (println 2))] x) |
| 13:01 | clojurebot | nil |
| 13:02 | fifosine | why does that not print? |
| 13:02 | teslanick | Because it's just a list of symbols. |
| 13:05 | llasram | ,(for [x '((println 1) (println 2))] x) |
| 13:05 | clojurebot | ((println 1) (println 2)) |
| 13:07 | fifosine | teslanick, llasram: I'm trying to write a macro that wraps doseq. I have this so far, but as you pointed out teslanick, it just yields a list of symbols. |
| 13:07 | fifosine | (defmacro wrap-doseq [body] `(doseq [~'x '~body] ~'x)) |
| 13:08 | fifosine | how do I get it to eval? |
| 13:08 | bbloom | fifosine: it seems like you're just using ~ and ' indiscriminately |
| 13:08 | justin_smith | fifosine: the point of doseq is that it do something - but the ~'x in the body won't do anything that the expansion of ~body did not do |
| 13:08 | bbloom | fifosine: it's worth experimenting with ` without defmacro |
| 13:08 | fifosine | bbloom: I might be, I'm using this as an exercise to learn how to use quoting etc |
| 13:08 | bbloom | fifosine: forget macros for a moment and play with the quoting operators in your repl |
| 13:09 | bbloom | fifosine: it will let you iterate much faster and you'll probably figure it out on your own |
| 13:09 | bbloom | and also experiment with x# instead of ~'x |
| 13:09 | fifosine | What is x#? |
| 13:09 | bbloom | fifosine: try it in your repl and it should become clear pretty quickly |
| 13:09 | bbloom | (with quoting) |
| 13:10 | fifosine | how do you mean |
| 13:10 | bbloom | fifosine: you've got a repl right? |
| 13:10 | fifosine | if you could provide a quick example, I'll start experimenting |
| 13:10 | fifosine | yes |
| 13:10 | justin_smith | ,`(let [x# 1] x#) |
| 13:10 | clojurebot | (clojure.core/let [x__93__auto__ 1] x__93__auto__) |
| 13:10 | bbloom | ,x# |
| 13:10 | arrdem | does anyone know of a Clojure java.net.URI wrapper which allows for multimethod dispatch on URI type when attempting to slurp? clojure.java.io doesn't provide this and I'm not seeing it with a quick google. |
| 13:10 | clojurebot | #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: x# in this context, compiling:(NO_SOURCE_PATH:0:0)> |
| 13:10 | bbloom | ,'x# |
| 13:10 | clojurebot | x# |
| 13:10 | bbloom | ,`x# |
| 13:10 | clojurebot | x__164__auto__ |
| 13:10 | bbloom | ,'[x# x#] |
| 13:10 | clojurebot | [x# x#] |
| 13:11 | bbloom | ,`[x# x#] |
| 13:11 | clojurebot | [x__213__auto__ x__213__auto__] |
| 13:11 | bbloom | there's like a dozen examples fo ryou |
| 13:11 | bbloom | just type some crap in to the repl and see what happens! |
| 13:11 | bbloom | your computer won't explode, i promise |
| 13:15 | fifosine | bbloom: Okay, so I've got the macro working the way I want. It looks like |
| 13:15 | fifosine | (defmacro wrap-doseq [body] `(doseq [x# '~body] (eval x#))) |
| 13:15 | fifosine | but isn't using eval discouraged? |
| 13:15 | fifosine | how do I get around this? |
| 13:15 | bbloom | fifosine: quote and eval are (more or less) opposite operations |
| 13:15 | llasram | fifosine: What are you actually trying to make the macro even do? |
| 13:15 | bbloom | they cancel each other out |
| 13:16 | bbloom | fifosine: so if you've got one too many evals, you might have one too many quotes |
| 13:16 | fifosine | llasram: given a list of unevaluated function calls, wrap it in a doseq (as opposed to a do) |
| 13:16 | bbloom | fifosine: but in this case, you're generating code that has a loop, rather than using a loop to generate code |
| 13:16 | fifosine | bbloom: Yes, that's intended |
| 13:16 | llasram | fifosine: "wrap it in a doseq" isn't well-defined |
| 13:17 | bbloom | fifosine: i think your intention is wrong then :-P |
| 13:17 | justin_smith | also, '(println :x) is a list of a symbol and a keyword, it is not an unevaluated function call |
| 13:17 | llasram | fifosine: Are you kind trying to re-implement `do` in terms of `doseq`? |
| 13:18 | fifosine | bbloom: actually, you're right, I don't need the doseq to be generated, I could just perform the doseq within the macro |
| 13:18 | bbloom | fifosine: and now it's time to experiment with ~@ outside of defmacro |
| 13:18 | bbloom | ,`~@(range 3) |
| 13:18 | clojurebot | #<IllegalStateException java.lang.IllegalStateException: splice not in list> |
| 13:18 | bbloom | ,`[~@(range 3)] |
| 13:18 | clojurebot | [0 1 2] |
| 13:18 | bbloom | ,`[~@(range 0)] |
| 13:18 | clojurebot | [] |
| 13:18 | Bronsa | `(~@()) :( |
| 13:18 | Bronsa | ,`(~@()) :( |
| 13:18 | clojurebot | nil |
| 13:19 | bbloom | Bronsa: hmmm |
| 13:19 | justin_smith | Bronsa: that last one is like bizarro ascii art |
| 13:19 | Bronsa | I should get clojurebot to automatically dec me each time I write clojure code without "," in front of it |
| 13:20 | Bronsa | maybe that'll make me remember |
| 13:20 | bbloom | Bronsa: if it could detect that, then it might as well just damn evaluate it :-P |
| 13:20 | Bronsa | bbloom: http://dev.clojure.org/jira/browse/CLJ-1444 |
| 13:20 | bbloom | Bronsa: is that not a giant breaking change? |
| 13:21 | justin_smith | Bronsa: add a hook to your client inserting , before all your messages to this channel |
| 13:21 | justin_smith | :P |
| 13:21 | Bronsa | , justin_smith: that might get annoying pretty fast |
| 13:21 | clojurebot | #<RuntimeException java.lang.RuntimeException: Invalid token: justin_smith:> |
| 13:21 | Bronsa | ^ |
| 13:21 | justin_smith | yeah :) |
| 13:22 | Bronsa | bbloom: maybe, but I think everybody would expect (~@whatever) to always return a list, not nil |
| 13:22 | Bronsa | I doubt there's code that depends on that returning nil |
| 13:22 | bbloom | Bronsa: by that logic, i doubt there's code that would desire it to return () |
| 13:22 | fifosine | bbloom: I have this now, but it still uses eval |
| 13:22 | fifosine | (defmacro wrap-doseq [body] (doseq [x body] (eval x))) |
| 13:23 | Janiczek | Hi, is there a way for Schema to throw an exception when I'm using a schema B instead of schema A, but they are the same under the hood? Example code: https://gist.github.com/Janiczek/e9c74130f18dd17c6d11 |
| 13:23 | bbloom | fifosine: how come you're still trying to make this work with defmacro? i'm not sure how much clearer i can be about this: get it working without defmacro, using only quoting in your repl |
| 13:24 | bbloom | fifosine: you're confused about both defmacro and quote, so you're definitely not going to understand them both at the same time |
| 13:24 | Bronsa | bbloom: find me one guy in this room that knows `(~@x) might return nil (except you and me now) :P |
| 13:24 | bbloom | Bronsa: all i'm saying is that i'm sure there's a library somewhere that will break |
| 13:24 | bbloom | :-P |
| 13:24 | bbloom | Bronsa: whether or not you care is another question |
| 13:24 | fifosine | bbloom: You're saying, get it working w/out defmacro and without eval, right? |
| 13:24 | bbloom | fifosine: i'm saying forget defmacro until you understand quoting |
| 13:26 | Bronsa | bbloom: "For Lists/Vectors/Sets/Maps, syntax-quote establishes a template of the corresponding data structure" |
| 13:26 | Bronsa | bbloom: the documentation is clear, if a library breaks, it deserves to. |
| 13:27 | Bronsa | brb dinner |
| 13:27 | bbloom | Bronsa: ok, so you don't care :-P |
| 13:27 | fifosine | bbloom: If I understand quoting, should I be able to remove the call to eval in the snippet? |
| 13:28 | fifosine | bbloom: e.g., I still have |
| 13:28 | fifosine | (doseq [x '((println 1) (println 2))] (eval x)) |
| 13:28 | bbloom | fifosine: if you understand quoting, you'll understand whether or not you need an eval too |
| 13:28 | justin_smith | ,(map #(.getScheme (java.net.URI. %)) ["telnet://foo/bar" "file:///twiddle" "http://example.com"]) ; arrdem maybe I misunderstand your question, but why not use #(.getScheme %) as a dispatch for a multimethod? |
| 13:28 | clojurebot | ("telnet" "file" "http") |
| 13:29 | fifosine | bbloom: Ah, okay, I see what you're saying. Well, it seems like if I ever need code to not be evaluated, I need to quote it so that it's known as a list of symbols. If I later need to take that same list of symbols and then evaluate it as I would expect, I have to use eval. |
| 13:30 | justin_smith | fifosine: you can also delay evaluation by constructing a function, and later calling it |
| 13:30 | bbloom | fifosine: except that you don't have to evaluate it yourself |
| 13:30 | fifosine | i.e. if I quote something and then want it evaluated, I need to use eval |
| 13:30 | bbloom | fifosine: a macro takes code in and returns code out |
| 13:30 | bbloom | fifosine: the compiler will ensure that the generated code gets evaluated |
| 13:31 | fifosine | hmmm |
| 13:31 | bbloom | fifosine: like i said, quote and eval cancel each other out |
| 13:32 | bbloom | fifosine: a macro is quoting something, applying a function to it, then evaluating the result of that function call |
| 13:33 | fifosine | bbloom: Given that, I don't think it's possible to write this w/out eval |
| 13:33 | arrdem | justin_smith: that's what I want to do... issue is that as implemented clojure.java.io doesn't provide such extensible dispatch. URIs are handled as (slurp (.toURL my-uri)) |
| 13:33 | bbloom | fifosine: you're wrong |
| 13:33 | arrdem | justin_smith: pondering how to package such an extension lib |
| 13:34 | bbloom | fifosine: if i give you the answer, you won't get to experience the joyous insight of understanding syntax quote |
| 13:34 | bbloom | fifosine: your goal is to write an expression that returns the right code you want to run, not to actually run the code |
| 13:34 | fifosine | ok, don't tell me then, I do want to figure it out I just feel slow |
| 13:35 | bbloom | fifosine: go away and play with your repl, you'll get it |
| 13:35 | fifosine | bbloom: If what I get from defmacro is a list of lists of symbols already quoted, i.e. '((println 1) (println 2)), and I want to iterate over this list, evaling each element, how can I not use eval |
| 13:36 | bbloom | fifosine: why are you still talking about defmacro? |
| 13:37 | fifosine | because before, when I assumed not using defmacro, if I wanted to quote things, later I *had* to use eval. as you said, they're "opposite" operations. and then you said "except that you don't have to evaluate it yourself", which I thought was referring to the power of macros |
| 13:37 | fifosine | so then I thought the solution isn't possible w/out them |
| 13:37 | fifosine | but I guess it is |
| 13:38 | bbloom | fifosine: you don't have to evaluate it yourself when you use defmacro |
| 13:38 | justin_smith | fifosine: he's saying, play with syntax-quote outside macros for a while, see what they really do, then use it inside a macro |
| 13:39 | bbloom | which is why i'm advising you to not think about defmacro for a bit, b/c it does some extra operations that make it harder to understand the primitives |
| 13:39 | bbloom | your goal is to generate the right code, not to run it |
| 13:39 | bbloom | if you want to make sure you generated the right code, you can call eval on that |
| 13:39 | bbloom | but my advice, is to do it like this: |
| 13:39 | fifosine | then, is there another way of writing this w/out eval and w/out defmacro |
| 13:39 | fifosine | (doseq [x '((println 1) (println 2))] (eval x)) |
| 13:39 | bbloom | ,'(println 5) |
| 13:39 | clojurebot | (println 5) |
| 13:39 | fifosine | is that what I'm missing? |
| 13:39 | bbloom | ,(eval *1) |
| 13:39 | clojurebot | #<Unbound Unbound: #'clojure.core/*1> |
| 13:39 | bbloom | oh, well that would work :-P |
| 13:40 | bbloom | use (eval *1) to test code you generate in your repl |
| 13:40 | fifosine | I gotcha |
| 13:40 | bbloom | at this point i'm going to stop talking b/c really there's only two ways for you get figure this out 1) somebody tells you or 2) you go experiment for a while and you'll understand it much more deeply |
| 13:41 | bbloom | go! have fun |
| 13:41 | fifosine | ugh ok |
| 13:41 | fifosine | I'm losing sight of the goal |
| 13:44 | Bronsa | bbloom: right, I don't care indeed, but my point is that I don't think anybody should care about libraries that depend on behaviour different than that documented |
| 13:44 | Bronsa | about not breaking* |
| 13:44 | Bronsa | they depend on a bug and bugs should get fixed |
| 13:45 | bbloom | Bronsa: i'm just playing devil's advocate here. personally i don't care one way or another, but if you're the only person who has ever noticed, then it's not worth risking any breaking change at all |
| 13:45 | bbloom | Bronsa: potentially, anyway |
| 13:46 | bbloom | Bronsa: it'd be one thing if no code could break and new code was possible, but somebody might depend on the falseness of that, and you say you don't care, but somebody might be scratching their heads for 3 friggin days after upgrading clojure |
| 13:46 | Bronsa | bbloom: that's what changelogs are for :P |
| 13:46 | bbloom | Bronsa: you gotta weigh cost & benefit |
| 13:46 | bbloom | cost is potential head scratching & broken lib w/ an absent maintainer |
| 13:46 | bbloom | and benefit is what exactly? |
| 13:47 | bbloom | it matches the "spec" which is a one liner on a page nobody reads? |
| 13:47 | bbloom | don't get me wrong, i think it probably should return empty list |
| 13:47 | Bronsa | bbloom: yeah, I understand what you're saying |
| 13:47 | bbloom | and i'd be totally fine if your patch got accepted |
| 13:47 | bbloom | but then again i'm not a clojure maintainer |
| 13:48 | Bronsa | it's just it makes me feel really bad when edge-cases don't work as they should :P |
| 13:48 | bbloom | switching from devil's advocate to being just a plain old joker: |
| 13:48 | bbloom | you should go write a programming language with NO EDGE CASES :-) |
| 13:51 | fifosine | bbloom: here's I've been able to write the snippet above w/out eval and w/out defmacro |
| 13:51 | fifosine | (doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x))) |
| 13:51 | fifosine | ,(doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x))) |
| 13:51 | clojurebot | 1\n2\n |
| 13:52 | bbloom | fifosine: lol well i gotta give you credit, that's creative |
| 13:52 | fifosine | ugh, not what you were thinking? |
| 13:52 | Bronsa | fifosine: resolve falls into the same category as eval |
| 13:52 | fifosine | aargggggg |
| 13:52 | Bronsa | somewhat |
| 13:52 | bbloom | fifosine: you're still running the code, rather than returning the code that you want to run... |
| 13:53 | bbloom | ,(let [x 5] `(* ~x ~x)) |
| 13:53 | clojurebot | (clojure.core/* 5 5) |
| 13:53 | bbloom | ,(let [x 5] (eval `(* ~x ~x))) |
| 13:53 | clojurebot | 25 |
| 13:53 | bbloom | fifosine: do you understand the difference between those two? |
| 13:54 | fifosine | yes, the first is returning a list of symbols, the second is evaluating that list |
| 13:54 | bbloom | ,(let [form '(prn 1)] (eval `(do ~form ~form))) ; do you understand why this prints two ones? |
| 13:54 | clojurebot | 1\n1\n |
| 13:54 | bbloom | can you write an expression that returns (do (clojure.core/println 1) (clojure.core/println 2)) ? |
| 13:54 | fifosine | yes, ~form turns into (prn 1), then (do (prn 1) (prn 1)) is eval'd |
| 13:55 | bbloom | (eval (doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x)))) ; this is what a macro is going to do to your code |
| 13:55 | bbloom | ,(eval (doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x)))) ; this is what a macro is going to do to your code |
| 13:55 | clojurebot | 1\n2\n |
| 13:55 | bbloom | that *looks* like it works, but it's not quite right |
| 13:56 | bbloom | ,(def foo (doseq [x '((println 1) (println 2))] (apply (resolve (first x)) (rest x)))) ; let's defer evaluation |
| 13:56 | clojurebot | 1\n2\n#'sandbox/foo |
| 13:56 | bbloom | ^^ whoops! it evaluated |
| 13:56 | bbloom | ,(eval foo) |
| 13:56 | clojurebot | nil |
| 13:56 | bbloom | fifosine: your goal is to produce code which will evaluate correctly, not to evaluate it yourself |
| 13:57 | bbloom | fifosine: experiment with ` and ~@ and replace your doseq with a for |
| 13:57 | fifosine | is for preferrable? |
| 13:58 | fifosine | ,(let [x '((println 1) (println 2))] `(do ~@x)) |
| 13:58 | clojurebot | (do (println 1) (println 2)) |
| 13:58 | bbloom | fifosine: it's different |
| 13:59 | bbloom | fifosine: the reason you're avoiding doseq or avoiding eval is not that there's something wrong with either of them... it's that they don't do what you need them to do.... |
| 13:59 | bbloom | but you should experiment with for and doseq and see how they differ |
| 13:59 | bbloom | look at their source code |
| 13:59 | bbloom | use eval to understand eval |
| 13:59 | bbloom | and to understand quote |
| 14:00 | fifosine | bbloom: Will I use for to generate code that uses doseq? Or do you suggest replacing doseq with for |
| 14:00 | Rhainur | so I'm a Ruby on Rails dev who's trying to learn Clojure, and I'm having a hard time adjusting to freedom :P Specifically Rails was very heavy on convention, and when I'm developing using Luminus I don't really know where to place my code :( |
| 14:00 | Rhainur | any guides that I can read with regards to this? |
| 14:01 | bbloom | fifosine: can you explain the difference between doseq and for? |
| 14:01 | Bronsa | https://github.com/clojure/tools.reader/commit/98d04ddce7152f69ac741ec783d0ce577075aef8 I feel kinda better now |
| 14:01 | fifosine | for will return a list |
| 14:01 | fifosine | doseq returns nil |
| 14:01 | bbloom | fifosine: and? |
| 14:01 | fifosine | more specifically, the list returned by for is the concatenation of the results of apply the body to each element in the specified list |
| 14:02 | bbloom | fifosine: doseq also supports concatenating nested loops |
| 14:02 | bbloom | ,(doseq [m "abc" n "xyz"] [m n]) |
| 14:02 | clojurebot | nil |
| 14:02 | bbloom | ,(doseq [m "abc" n "xyz"] (println [m n])) |
| 14:02 | clojurebot | [a x]\n[a y]\n[a z]\n[b x]\n[b y]\n[b z]\n[c x]\n[c y]\n[c z]\n |
| 14:03 | bbloom | (doc doseq) |
| 14:03 | clojurebot | "([seq-exprs & body]); Repeatedly executes body (presumably for side-effects) with bindings and filtering as provided by \"for\". Does not retain the head of the sequence. Returns nil." |
| 14:03 | fifosine | oh ok, like a cartesian product? I didn't know that |
| 14:03 | bbloom | note the parenthetical: |
| 14:03 | bbloom | "presumably for side-effects" |
| 14:03 | fifosine | to be clear, I'm assuming side-effecful functions |
| 14:03 | fifosine | part of the reason why i've been using println |
| 14:04 | bbloom | fifosine: if you are writing a macro, your goal is NOT TO RUN THE CODE |
| 14:04 | bbloom | your goal is to return the code that you want to run |
| 14:04 | Shoop | quick question is there any simpler way to write (for [a seq b seq c seq d seq.........] [a b c d.....]) |
| 14:04 | bbloom | fifosine: macros should not have side effects! although the code generated by the macro may have side effects |
| 14:04 | justin_smith | (doc interpose) ; Shoop |
| 14:04 | clojurebot | "([sep coll]); Returns a lazy seq of the elements of coll separated by sep" |
| 14:05 | bbloom | justin_smith: that's not what Shoop wants |
| 14:05 | fifosine | bbloom: The question I need to answer is, what code do I want to be generated w/out using eval |
| 14:05 | justin_smith | Shoop: oh wait, that's for, never mind |
| 14:05 | Bronsa | Shoop: do you care about the combination order? |
| 14:05 | Shoop | Bronsa: not really |
| 14:05 | fifosine | bbloom: and w/out using resolve, I guess |
| 14:06 | Bronsa | Shoop: then there's `cartesian-product` in math.combinatorics that does exactly that |
| 14:06 | bbloom | fifosine: sorry man, but i kinda give up.... |
| 14:06 | Bronsa | Shoop: https://github.com/clojure/math.combinatorics |
| 14:06 | Shoop | Bronsa: thanks :D |
| 14:07 | bbloom | ,`(do ~@(for [x '((println 1) (println 2))] x))) |
| 14:07 | clojurebot | (do (println 1) (println 2)) |
| 14:07 | fifosine | bbloom: I already have (defmacro wrap-do [body] `(do ~@body)) |
| 14:07 | fifosine | I thought that writing it in terms of doseq might be enlightening |
| 14:07 | bbloom | fifosine: i have no idea what you're talking about |
| 14:08 | alexyakushev | Hi, quick question. Why the following exception slips through catch: (try (map str 'foo) (catch Exception ex "failed")) |
| 14:08 | Bronsa | fifosine: I suggest you read (or re-read) an introductory clojure book or a documentation series before trying to do what you're doing. You clearly haven't understood yet how evaluation & macros work |
| 14:08 | fifosine | bbloom: What I mean to say is, maybe my aim was fruitless. I thought that writing a macro which took a list of function calls, and evaluated the list using doseq as opposed to using do (as above) would be interesting. |
| 14:08 | fifosine | but I guess it's not |
| 14:09 | alexyakushev | I mean, I know it's probably because of the laziness, but what the hell |
| 14:09 | Bronsa | alexyakushev: yes, it's because of map being lazy |
| 14:10 | fifosine | bbloom: sorry to have wasted your time, but thanks for sticking with me for as long as you did |
| 14:11 | Bronsa | alexyakushev: the only way to make that work is to force the evaluation of map inside the try, with a doall |
| 14:14 | alexyakushev | Bronsa: yeap, that's what I thought |
| 14:14 | alexyakushev | Seems awfully surprising and confusing to me |
| 14:16 | Bronsa | alexyakushev: there's no other way to do it and preserve the lazyness of map |
| 14:19 | alexyakushev | Bronsa: why the try-catch context cannot be enclosed the same way the closed variables are? |
| 14:22 | alexyakushev | It doesn't feel good to know that the only Clojure's error handling system will let you down as soon as you call a single sequence-operating function |
| 14:22 | Bronsa | alexyakushev: locals have lexical extent, try-catch blocks have dynamic extent, it's not the same thing |
| 14:23 | dbasch | alexyakushev: what do you mean by let you down? It fails when it’s supposed to |
| 14:23 | dbasch | alexyakushev: it’s the same thing as saying “why does the compiler let me compile code that will fail at runtime?” |
| 14:24 | Bronsa | alexyakushev: it doesn't let you down. if you're using map you should be aware of its lazyness and of the behaviour it implies |
| 14:25 | alexyakushev | dbasch: No, it's not the same. What is the point of an exception that I can't catch? It could just segfault with the same outcome |
| 14:25 | Bronsa | alexyakushev: it's the same for dynamic vars, really, the only difference is that vars being implemented by clojure and not in the jvm, can be "captured" manually |
| 14:26 | Bronsa | alexyakushev: you can catch that exception. you just need to realize the lazy sequence inside the try block instead of outside |
| 14:26 | dbasch | alexyakushev: you can catch it |
| 14:26 | Bronsa | ,(try (doall (map str 'foo)) (catch Exception _)) |
| 14:26 | clojurebot | Bronsa: Huh? |
| 14:26 | alexyakushev | Bronsa: point is, everyone's using map. So far the only implied behavior to care about for lazyness were side-effects |
| 14:26 | Bronsa | clojurebot: what. |
| 14:26 | clojurebot | Pardon? |
| 14:26 | alexyakushev | Bronsa: Clojail is trained to act dumb when it sees a "catch" |
| 14:27 | dbasch | ,(try (first (map str 'foo)) (catch Exception ex "failed")) |
| 14:27 | clojurebot | dbasch: Titim gan éirí ort. |
| 14:27 | alexyakushev | safety reasons I guess |
| 14:27 | Bronsa | alexyakushev: clojurebot doesn't use clojail |
| 14:27 | dbasch | &(try (first (map str 'foo)) (catch Exception ex "failed")) |
| 14:27 | lazybot | java.lang.SecurityException: You tripped the alarm! catch is bad! |
| 14:27 | alexyakushev | OK, then whatever else it uses |
| 14:27 | Bronsa | alexyakushev: exceptions are not side-effects? |
| 14:28 | alexyakushev | Bronsa: I don't see a reason why they should be |
| 14:29 | Bronsa | alexyakushev: it's a side-effect that acts on the state of the program |
| 14:30 | alexyakushev | Bronsa: in which way? |
| 14:30 | Bronsa | alexyakushev: anyway, lazyness is not only about side-effects, it's about delayed evaluation |
| 14:31 | alexyakushev | Overall, I wonder what was the point of doing lazy evaluation the default one if a lot of other concepts of the language don't work well with it |
| 14:31 | alexyakushev | "doall your lazy collections to trigger side-effects" |
| 14:31 | alexyakushev | "Don't use dynamic binding with lazy collections" |
| 14:31 | Bronsa | lazy evaluation is not the default evaluation strategy |
| 14:32 | alexyakushev | Now it's "doall your lazy collections to handle exceptions properly" |
| 14:32 | Bronsa | clojure is a strictly evaluated language |
| 14:32 | alexyakushev | I don't argue, except that almost all sequence processing library is lazy |
| 14:33 | alexyakushev | I'm trying to find a reason why should I care whether my collections is lazy or not when I want to catch an exception |
| 14:34 | Bronsa | alexyakushev: the evaluation of a lazy collection doesn't imply its realization |
| 14:34 | Bronsa | ,(def a (map str 'foo)) |
| 14:34 | clojurebot | #'sandbox/a |
| 14:34 | Bronsa | you can't catch the exception caused by evaluation that sequence, if you don't realize it |
| 14:35 | xeqi | ,a |
| 14:35 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol> |
| 14:35 | Bronsa | until you realize a lazy sequence, it's just a box with the recipe for building itself |
| 14:36 | alexyakushev | Nicola, you are saying everything correctly from the implementation standpoint |
| 14:36 | Bronsa | alexyakushev: if you want to make sure (map f y=[x ..]) succeds assuming that (f x) returns a correct value, you need to validate y |
| 14:37 | Bronsa | e.g. (assert (seq y)) |
| 14:37 | alexyakushev | But it doesn't answer the question why can't I have an error handling mechanism that lets me not care whether my collection is lazy or not |
| 14:38 | alexyakushev | Or not a collection at all |
| 14:38 | justin_smith | alexyakushev: do proper validation. the schema library can help there. or you may find yourself happier using a statically typed language. but clojure simply isn't one. |
| 14:40 | alexyakushev | justin_smith: well, actually I use Clojure exactly for the reason that I don't have to put static types everywhere. I don't want that code to fail during compilation (like it would in statically typed language), I don't want it to fail at all |
| 14:41 | xeqi | alexyakushev: what would try/catch do when half the sequence would evaluate successfully? |
| 14:42 | Bronsa | xeqi: he's expecting the try-catch block to be "captured" by the lazy-seq, and its evaluation be done using that try-catch context |
| 14:43 | Bronsa | which is not something that's really possible on the JVM |
| 14:44 | alexyakushev | Bronsa: That's what I "expected", that is right |
| 14:44 | alexyakushev | I'm not saying that's what I really want |
| 14:44 | Bronsa | you'd have to reify every try-catch block and somewhat attach it to its body |
| 14:44 | alexyakushev | I understand that implementing this requires special handling in the compiler, and besides you say it is not at all possible |
| 14:45 | alexyakushev | But then it means that the current error handling system cannot work well with other primary language concepts (like laziness) |
| 14:46 | Bronsa | alexyakushev: right, that's a tradeoff you're supposed to be making when using lazy sequences |
| 14:47 | Bronsa | features that have a dynamic extent like dynamic vars and exception handling don't know how to interact with lazyness |
| 14:47 | justin_smith | let's remember that with (map str 'foo) the argument isn't even valid - you can use schema validation to catch the error without needing to do anything fancy with try/catch here |
| 14:49 | alexyakushev | justin_smith: Thank you for trying to put me on the right path, but this is half-artificial example and in my case I actually need the try/catch |
| 14:50 | Bronsa | alexyakushev: (map f x) might fail for two reasons: either x is not seqable or (f y) fails with y an element of x |
| 14:51 | Bronsa | alexyakushev: to avoid the first occurrence, rewrite f as #(try (f %) (catch Exception _ ..)) |
| 14:51 | Bronsa | to avoid the second, validate x before calling map over it |
| 14:51 | Bronsa | that might involve realizing all, or some part of x, clojure can't do that automatically for you |
| 14:51 | bbloom | Bronsa: i've got a compiler question for you |
| 14:52 | bbloom | Bronsa: if i return a closure from a method, will that closure keep any pointers to the containing instance? |
| 14:52 | bbloom | Bronsa: that is (deftype T [foo] SomeProtocol (someMethod [this] (fn [x] foo))) ; will this be captured at all? |
| 14:53 | Bronsa | bbloom: yes if you're using a field of that instance |
| 14:53 | bbloom | Bronsa: argh. what if i copy it to a local? |
| 14:55 | Bronsa | bbloom: nvm, sorry, it only captures the value |
| 14:55 | bbloom | Bronsa: you sure? :-) |
| 14:56 | Bronsa | it will capture the instance if you use (.-foo this) rather than foo |
| 14:56 | bbloom | Bronsa: ok that makes sense |
| 14:56 | bbloom | thanks |
| 14:56 | Shoop | I am new to clojure coming from an imperative programming background. Can someone help me translate a simple python function into clojure? |
| 14:56 | Shoop | http://pastebin.com/ezD3bCgv |
| 14:57 | alexyakushev | Bronsa: btw speaking of doall, too bad it will help only if you control the sequence generation https://www.refheap.com/89629 |
| 14:57 | gfredericks | Shoop: depends on how direct you want; lines 13 and 16 aren't very idiomatic, since they're linear time |
| 14:58 | Bronsa | alexyakushev: yeah, doall isn't recursive |
| 14:58 | Bronsa | it only forces the sequence you give it, not the subsequences |
| 14:58 | Shoop | gfredericks: i was looking for something more functional |
| 14:58 | Shoop | gfredericks: i tried doing it with recurse but i was having trouble |
| 14:58 | Shoop | *recursion |
| 14:59 | gfredericks | Shoop: clojure style usually involves higher level operations on collections when possible |
| 14:59 | gfredericks | Shoop: in this case clojure.core/frequencies is an interesting way to get a lot of the logic you have |
| 14:59 | gfredericks | ,(def list1 [1 2 3]) |
| 14:59 | clojurebot | #'sandbox/list1 |
| 14:59 | gfredericks | ,(def list2 [3 3 4 5]) |
| 14:59 | clojurebot | #'sandbox/list2 |
| 14:59 | gfredericks | ,(frequencies list1) |
| 14:59 | clojurebot | {1 1, 2 1, 3 1} |
| 15:00 | gfredericks | ,(frequencies list2) |
| 15:00 | clojurebot | {3 2, 4 1, 5 1} |
| 15:00 | Shoop | oh and then you could zip them and work from there |
| 15:00 | gfredericks | sorta yeah |
| 15:00 | gfredericks | I would just iterate through the first one and use the second one at each point |
| 15:00 | Shoop | ok |
| 15:00 | Shoop | ill mess around with that |
| 15:00 | Shoop | thanks |
| 15:00 | gfredericks | np |
| 15:01 | gfredericks | also look at map, filter, reduce... |
| 15:01 | gfredericks | which work with maps as well |
| 15:01 | Bronsa | bbloom: I just checked the bytecode to make sure, I can confirm what I said |
| 15:01 | alexyakushev | Bronsa: Yup. So it appears that Clojure pushes laziness down your throat without having the proper infrastructure to deal with its nuances |
| 15:01 | Shoop | ok :D |
| 15:01 | bbloom | Bronsa: awesome, thank you |
| 15:01 | bbloom | Bronsa: working on some fiddly external resource management/cleanup nonsense |
| 15:02 | alexyakushev | Which probably means that you have to explicitly doall every place you call map/filter/remove if you know you don't need laziness there |
| 15:02 | Bronsa | alexyakushev: if you don't need lazyness, don't use it |
| 15:03 | Bronsa | alexyakushev: I use mapv instead of map when I don't need lazyness |
| 15:03 | Bronsa | now that transducers are a thing, I'll probably use those |
| 15:03 | gfredericks | clojurebot: transducers |are| a thing |
| 15:03 | clojurebot | Ok. |
| 15:04 | alexyakushev | Bronsa: now that's better. What about filter, can I easily replace it? |
| 15:04 | gfredericks | ,(doc filterv) |
| 15:04 | clojurebot | "([pred coll]); Returns a vector of the items in coll for which (pred item) returns true. pred must be free of side-effects." |
| 15:04 | alexyakushev | OK, great |
| 15:05 | alexyakushev | Two words that could save me an hour of ranting and wasting everyone's time:) |
| 15:05 | Bronsa | alexyakushev: you can use filterv |
| 15:05 | Bronsa | (inc gfredericks) |
| 15:05 | lazybot | ⇒ 86 |
| 15:05 | justin_smith | Shoop: https://www.refheap.com/89630 my imperfect version of example (returns the right results, code could be better) |
| 15:05 | Bronsa | alexyakushev: or, with transducers, use the filter transducer :) |
| 15:06 | Bronsa | alexyakushev: you never said you didn't need the lazyness |
| 15:06 | Bronsa | if you did, I'm sorry I missed that |
| 15:06 | alexyakushev | Bronsa: yeah, but I suspect it will take a while before 1.7 will become the oldest supported Clojure version |
| 15:06 | justin_smith | alexyakushev: I don't doubt that people use laziness in clojure without thinking about it, but it is not forced on you - my above function, coincidentially, has no lazy values in it |
| 15:07 | alexyakushev | Or will transducers be somehow backported into 1.5/1.6 (via a library of sorts)? |
| 15:07 | Bronsa | alexyakushev: I doubt they will |
| 15:08 | alexyakushev | Bronsa: I might have forgot to say that I don't need laziness in this particular example. But regardless, the map/filter are the functions that you read about in all books, and everyone uses them rather than mapv/filterv |
| 15:08 | Bronsa | ,(:added (meta #'mapv)) |
| 15:08 | clojurebot | "1.4" |
| 15:08 | Bronsa | alexyakushev: I'll be surprised if books covering clojure >=1.4.0 didn't mention them |
| 15:08 | alexyakushev | I meant transducers when I talked about versions |
| 15:09 | alexyakushev | They do, I knew about mapv |
| 15:09 | gfredericks | alexyakushev: I missed what your main issue with laziness is; something about error handling? |
| 15:09 | alexyakushev | But I thought of it more like "map for vectors" |
| 15:09 | alexyakushev | Rather than "non-lazy map" |
| 15:10 | justin_smith | gfredericks: the realizing of the lazy sequence can escape a try/catch, and thus not be caught as expected |
| 15:10 | Shoop | thanks justin_smith, looks good. im going to try a version using frequencies as well |
| 15:10 | gfredericks | yeah I guess that is kind of unfortunate |
| 15:10 | gfredericks | you can't write generic error handling code |
| 15:10 | justin_smith | Shoop: the definition of checkout there is a bit verbose - I opted for clarity over conciseness there |
| 15:11 | gfredericks | alexyakushev: I think it takes a bit of concentration wrt the boundaries of your functional vs imperative code |
| 15:11 | gfredericks | the error handling lives in the imperative part, and you stop using laziness somewhere around the boundary |
| 15:11 | alexyakushev | gfredericks: I'm used to that, just didn't think about error-handling as imperative before |
| 15:11 | Bronsa | btw c.c/iteration is awesome |
| 15:12 | gfredericks | alexyakushev: I probably wouldn't have either except that haskell makes you do it in the IO monad :D |
| 15:12 | Shoop | justin_smith: well thanks, its very readable :D |
| 15:13 | Bronsa | ,(def a (into [] (filter odd?) (map #(doto % println) (range 10)))) |
| 15:13 | clojurebot | 0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n#'sandbox/a |
| 15:13 | Bronsa | ,(def a (into [] (iteration (filter odd?) (map #(doto % println) (range 10))))) |
| 15:13 | clojurebot | 0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n#'sandbox/a |
| 15:13 | Bronsa | ,(def a (sequence (iteration (filter odd?) (map #(doto % println) (range 10))))) |
| 15:13 | clojurebot | 0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n#'sandbox/a |
| 15:14 | Bronsa | uhm |
| 15:14 | hiredman | ~clojurebot |
| 15:14 | clojurebot | clojurebot is in the Clojure IRC channel. Good work. |
| 15:14 | hiredman | ~clojurebot |
| 15:14 | clojurebot | clojurebot is pretty cool |
| 15:14 | hiredman | hmm |
| 15:14 | gfredericks | ~hiredman |
| 15:14 | clojurebot | hiredman is an evil genius. |
| 15:14 | Bronsa | clojurebot is not my repl? :) |
| 15:14 | hiredman | I could be here all day looking for the "is not a benchmarking platform" one |
| 15:15 | gfredericks | ~not a benchmarking platform |
| 15:15 | clojurebot | excusez-moi |
| 15:15 | hiredman | ~clojurebot |
| 15:15 | clojurebot | clojurebot is a multimap |
| 15:15 | hiredman | ~clojurebot |
| 15:15 | clojurebot | clojurebot queues for elephants |
| 15:15 | justin_smith | clojurebot: benchmark is clojurebot is not a benchmarking platform |
| 15:15 | clojurebot | Roger. |
| 15:15 | gfredericks | ~benchmark |
| 15:16 | clojurebot | criterium or gtfo |
| 15:16 | hiredman | justin_smith: you have to wonder, which is did clojurebot take as the assertion there |
| 15:16 | justin_smith | ouch |
| 15:16 | gfredericks | clojurebot: forget benchmark |is| clojurebot is not a benchmarking platform |
| 15:16 | clojurebot | I forgot that benchmark is clojurebot is not a benchmarking platform |
| 15:16 | alexyakushev | All right, thank you Bronsa, justin_smith, gfredericks. I will go and rewrite the code now |
| 15:16 | hiredman | did it? |
| 15:16 | alexyakushev | btw, there is no mapcatv, so meh:( |
| 15:17 | gfredericks | alexyakushev: start a library called v |
| 15:17 | Bronsa | alexyakushev: AFAIK there are only mapv filterv and removev |
| 15:17 | justin_smith | (into [] (mapcat ...)) |
| 15:17 | Bronsa | no removev. |
| 15:17 | gfredericks | In clojure, the only functions are mapv, filterv, and removev. And there is no removev. |
| 15:18 | justin_smith | gfredericks: worst esoteric lang ever |
| 15:18 | Bronsa | I was pretty sure there were 3 $somethingv functions |
| 15:18 | Bronsa | meh. |
| 15:18 | alexyakushev | gfredericks: v library — sounds like a plan |
| 15:18 | alexyakushev | AllThingsV |
| 15:18 | gfredericks | ,(->> (ns-publics 'clojure.core) keys (filterv #(re-find #"v$" (name %)))) |
| 15:18 | clojurebot | [filterv reduce-kv mapv] |
| 15:19 | justin_smith | ,(->> (ns-publics 'clojure.core) (map (comp name first)) (filter #(re-matches #".*v$" %))) |
| 15:19 | clojurebot | ("filterv" "reduce-kv" "mapv") |
| 15:19 | justin_smith | hah, I had the same thought |
| 15:20 | gfredericks | mine used filterv though which was more in line with the theme |
| 15:20 | justin_smith | heh, good point |
| 15:20 | justin_smith | yours was better expressed all around |
| 15:24 | Bronsa | uhm |
| 15:24 | gfredericks | ,(defn setv "Like set, but returns a vector" [coll] (vec (set coll))) |
| 15:24 | clojurebot | #'sandbox/setv |
| 15:25 | dnolen_ | gfredericks: you tolling? :) |
| 15:25 | dnolen_ | s/tolling/trolling |
| 15:25 | justin_smith | do not ask for whom gfredericks tolls, for he tolls for thee |
| 15:25 | gfredericks | dnolen_: no more than usual |
| 15:25 | gfredericks | ~gfredericks |
| 15:25 | clojurebot | gfredericks is a menace to bots everywhere |
| 15:26 | Bronsa | I wonder if (sequence (iteration (filter odd?) (range 10))) is supposed to realize the first element |
| 15:27 | alexyakushev | gfredericks: setv goes to the library for sure |
| 15:27 | alexyakushev | (inc gfredericks) |
| 15:27 | lazybot | ⇒ 87 |
| 15:27 | gfredericks | ,(defn incv "Like inc but returns a vector." [x] [(inc x)]) |
| 15:27 | clojurebot | #'sandbox/incv |
| 15:28 | Bronsa | lol |
| 15:29 | philandstuff | strv? |
| 15:29 | alexyakushev | lazy-seqv — like lazy-seq but not lazy? |
| 15:29 | gfredericks | this library is really shaping up |
| 15:29 | gfredericks | listv |
| 15:30 | justin_smith | vecv |
| 15:30 | gfredericks | nice |
| 15:30 | gfredericks | doseqv (always returns empty vector) |
| 15:31 | justin_smith | reduce-kvv |
| 15:31 | alexyakushev | (defn shutdown-agents "Like shutdown-agents but returns a vector." [] (shutdown-agents) (vector)) |
| 15:31 | philandstuff | ,(def emptyv (constantly [])) |
| 15:31 | clojurebot | #'sandbox/emptyv |
| 15:31 | Shoop | gfredericks: I think i figured out a way using list comprehensions - (apply + (for [a (frequencies list1), b (frequencies list2) :when (and (= (first a) (first b)) (>= (second a) (second b)))] (second b)))) |
| 15:32 | gfredericks | Shoop: after calling frequencies you should only have to do one iteration |
| 15:33 | justin_smith | Shoop: yeah, that's ignoring the wonderful associative property of a map, but walking it linearly |
| 15:33 | justin_smith | Shoop: a little silly |
| 15:33 | Shoop | gfredericks: but testing if the item is in list2 is another iteration |
| 15:34 | gfredericks | Shoop: it's a map, so you can do a direct lookup |
| 15:34 | hiredman | hey, I got JDBC-99, next person to file an issue gets 100 |
| 15:34 | Shoop | gfredericks: oh yeah |
| 15:34 | justin_smith | ,(reduce + (for [x (range 10) y (range 10)] 1)) ; Shoop |
| 15:34 | clojurebot | 100 |
| 15:34 | gfredericks | hiredman: oh snap! |
| 15:34 | justin_smith | Shoop: for on two collections does a lot my iterations than you might think :) |
| 15:35 | gfredericks | justin_smith: I think s/he knew that part, just didn't know it could be avoided |
| 15:35 | justin_smith | Shoop: frequencies returns a map - you can find out if a key is in a map without iterating |
| 15:35 | Shoop | justin_smith: its O(n^2) right? |
| 15:35 | Shoop | justin_smith: yeah i realized that |
| 15:35 | Shoop | he |
| 15:36 | justin_smith | ,(get (frequencies "hello world") \l) |
| 15:36 | clojurebot | 3 |
| 15:36 | gfredericks | gender discovery protocol complete |
| 15:36 | devn | wait... what |
| 15:36 | justin_smith | Shoop: I didn't need to walk the map to find that result - it supports directl lookup |
| 15:36 | bbloom | com.sun.jna.Pointer .... is friggin mutable! |
| 15:36 | Shoop | justin_smith: i see, well back to the drawing board |
| 15:37 | gfredericks | Shoop: want to see mine? |
| 15:37 | Shoop | justin_smith: its implemented as a hashtree right? |
| 15:37 | bbloom | it just wraps a long and has a frickin static method com.sun.jna.Pointer.nativeValue(Pointer p, long value) to set it |
| 15:37 | Shoop | gfredericks: give me a try, i want to use my brain |
| 15:37 | justin_smith | Shoop: a hashmap, which has a few backing datastructures depending on size |
| 15:38 | Shoop | Shoop: I thought it was a tree with a branching factor of 32 |
| 15:38 | justin_smith | ,(type (frequencies "hello world")) |
| 15:38 | clojurebot | clojure.lang.PersistentArrayMap |
| 15:38 | gfredericks | I have no idea what the branching factor on the hashmaps is |
| 15:39 | Shoop | gfredericks: docs say access is log base 32 n |
| 15:39 | Shoop | so |
| 15:39 | gfredericks | where does it say that? |
| 15:39 | Clarice | I remember hearing that in a talk some years ago |
| 15:39 | Clarice | It's based on the implementation of tries |
| 15:40 | gfredericks | not to be confused with vectors of course |
| 15:40 | justin_smith | Shoop: anyway, point is that the datastructure gives us fast lookup, so we should be suspicious if we are walking all the keys unless the point is to do something to every key |
| 15:40 | Clarice | Right, but as far as I can tell pretty much all the basic data types are persistent collections implemented as tries, so that should apply to all of them |
| 15:41 | gfredericks | well the 32 bit might not |
| 15:41 | Clarice | Has anyone tried Clojure on an Azul machine with great success? I think that'd be a good selling point for them: "Look! Clojure runs super fast with real time garbage collection!" |
| 15:42 | Shoop | justin_smith: ok let me try again |
| 15:47 | gfredericks | the number 32 does appear a few times in PersistentHashMap.java, so I'm just going to assume that's right |
| 15:51 | michaniskin | i remember seeing a clojure library for data schema validation, but not the prismatic/schema one. does anyone remember what it's called? |
| 15:53 | mynomoto | michaniskin: https://github.com/miner/herbert maybe? |
| 15:53 | gfredericks | also flatland/schematic |
| 15:54 | michaniskin | mynomoto: i think that's the one! thanks! |
| 15:59 | Shoop | ok its not perfect and i can get rid of a bunch of duplicated stuff with let but how is this? (reduce + (for [a (frequencies guess) :when (and (contains? (frequencies code) (first a)) (>= (second a) (get (frequencies code) (first a))))] (get (frequencies code) (first a)))) |
| 15:59 | Shoop | oops guess should be list1 and code list2 |
| 16:00 | Shoop | (reduce + (for [a (frequencies list1) :when (and (contains? (frequencies list2) (first a)) (>= (second a) (get (frequencies list2) (first a))))] (get (frequencies list2) (first a)))) |
| 16:06 | justin_smith | Shoop: yeah, a let would help a lot there |
| 16:06 | Shoop | but i think its down to O(n) now? |
| 16:07 | gfredericks | Shoop: I'm not sure that does the same thing? |
| 16:07 | Shoop | justin_smith: also sorry about the variable name mixup, this is part of a bigger project |
| 16:07 | gfredericks | your >= filter there seems to be not what you want |
| 16:08 | Shoop | gfredericks: how so? |
| 16:08 | gfredericks | you want (example [42] [42 42]) to return 1, no? |
| 16:08 | Shoop | yes |
| 16:09 | gfredericks | but your >= there becomes (>= 1 2) |
| 16:09 | gfredericks | ignoring the (first a) at the end which I don't understand at all |
| 16:09 | gfredericks | oh wait nm |
| 16:09 | Shoop | gfrederickks ah |
| 16:09 | Shoop | i see |
| 16:09 | gfredericks | I do understand it but my objection remains :) |
| 16:09 | Shoop | so it should be <=? |
| 16:09 | gfredericks | Shoop: I used min for this bit of logic instead of a >= chechk |
| 16:10 | Shoop | Can i see your version? |
| 16:10 | gfredericks | https://www.refheap.com/89635 |
| 16:12 | Shoop | oh i've never seen ->> before |
| 16:12 | Shoop | thats fancy :D |
| 16:14 | Shoop | gfredericks: btw if you are curious this is for the game http://en.wikipedia.org/wiki/Mastermind_(board_game) if you have ever played it |
| 16:14 | gfredericks | I guessed that by your variable names :) |
| 16:33 | TimMc | I wonder if I sitll have my TI-89 stuff. |
| 16:33 | TimMc | That calculator is... 18 years old now? |
| 16:36 | gfredericks | I think I transferred them off the calculator once but there's the question of how they're encoded and also where I put the files |
| 16:36 | justin_smith | TimMc: I still have a working tandy 102 - nigh indestructible, those are |
| 16:37 | gfredericks | I got super excited when I learned Java and discovered I could have more than one letter in my variable names |
| 16:37 | tac_ | TimMc: and still sold at $100+ to high school students everywhere in the US |
| 16:37 | Ven | tac_: and outside of the US, don't worry... |
| 16:37 | tac_ | despite having less computational power than an arduino |
| 16:43 | SagiCZ1 | are there any timers in clojure? |
| 16:46 | justin_smith | SagiCZ1: there is a Timer class in java you can use with clojure functions via interop |
| 16:47 | justin_smith | pretty simple to use, shown here http://stackoverflow.com/questions/16385049/timers-in-clojure |
| 16:49 | SagiCZ1 | justin_smith: i know that class.. ok thanks |
| 16:58 | ycouy | In core.match, is it possible to match on a variadic "middle" of a collection? So in some way ["foo" xs "qux"] would match ["foo" "bar" "baz" "qux"] and bind xs to ["bar" "baz"]. |
| 16:59 | dnolen_ | ycouy: not possible |
| 17:00 | ycouy | dnolen_: Do you know of any other language or pattern matching library that does this or something similar? |
| 17:01 | dnolen_ | ycouy: maybe seqex can do this? https://github.com/jclaggett/seqex |
| 17:02 | ycouy | dnolen_: Cool, will look into it. Thanks! |
| 17:15 | SagiCZ1 | ,(defn foo1 [{x :a y :b]}] (println x y)) |
| 17:15 | clojurebot | #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: ]> |
| 17:16 | SagiCZ1 | ,(defn foo1 [{x :a y :b}] (println x y)) |
| 17:16 | clojurebot | #'sandbox/foo1 |
| 17:16 | SagiCZ1 | (foo1 {:a 5 :b 6}) |
| 17:16 | SagiCZ1 | ,(foo1 {:a 5 :b 6}) |
| 17:16 | clojurebot | 5 6\n |
| 17:19 | SagiCZ1 | ,(defn foo1 [{x :a y :b :as a}] (println x y a)) |
| 17:19 | clojurebot | #'sandbox/foo1 |
| 17:19 | SagiCZ1 | ,(foo1 {:a 5 :b 6}) |
| 17:19 | clojurebot | 5 6 {:b 6, :a 5}\n |
| 18:02 | lavokad | hi, I don't find a place explaining why we can create a record using -> ? |
| 18:02 | llasram | lavokad: Example? |
| 18:04 | lavokad | (def algo (->MakeAlgo "lala" "huhu")) |
| 18:05 | llasram | lavokad: One thing `defrecord` does is define a var named `->RecordName`, which is a just a function which happens to start with the characters "->" |
| 18:05 | llasram | It has nothing to do with the `->` macro |
| 18:05 | llasram | It also defines `map->RecordName` |
| 18:05 | lavokad | ohh |
| 18:08 | lavokad | llasram: thanks |
| 18:10 | lavokad | llasram: where can I find this info? In docs nothing about this appears |
| 18:14 | lavokad | all right I found this in the source code :) |
| 18:15 | llasram | lavokad: It's mentioned in the last paragraph of the `defrecord` docstring |
| 18:16 | gfredericks | ,(-> defrecord meta :doc (clojure.string/split #"\n\n") last) |
| 18:16 | clojurebot | #<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/defrecord, compiling:(NO_SOURCE_PATH:0:0)> |
| 18:17 | gfredericks | ,(-> defrecord var meta :doc (clojure.string/split #"\n\n") last) |
| 18:17 | clojurebot | " Given (defrecord TypeName ...), two factory functions will be\n defined: ->TypeName, taking positional parameters for the fields,\n and map->TypeName, taking a map of keywords to field values." |
| 18:17 | llasram | gfredericks: Nice |
| 18:17 | llasram | (inc gfredericks) |
| 18:17 | lazybot | ⇒ 88 |
| 18:24 | lavokad | (doc defrecord) |
| 18:24 | clojurebot | "([name [& fields] & opts+specs]); (defrecord name [fields*] options* specs*) Currently there are no options. Each spec consists of a protocol or interface name followed by zero or more method bodies: protocol-or-interface-or-Object (methodName [args*] body)* Dynamically generates compiled bytecode for class with the given name, in a package with the same name as the current namespace, the given fields, and, optionall |
| 18:25 | gfredericks | I love that the first sentence is "Currently there are no options." |
| 18:26 | lavokad | why does the same doc info of defrecord appear on the web? |
| 18:27 | gfredericks | why not? |
| 18:28 | lavokad | i mean doesnt, sorry |
| 18:28 | gfredericks | $google "Currently there are no options" |
| 18:28 | lazybot | [ClojureDocs - clojure.core/reify] http://clojuredocs.org/clojure_core/1.2.0/clojure.core/reify |
| 18:28 | gfredericks | haha |
| 18:28 | justin_smith | "You're viewing version 1.2.0 of reify. The latest stable version of Clojure Core is 1.3.0." |
| 18:28 | justin_smith | lol |
| 18:29 | lavokad | http://clojuredocs.org/clojure_core/clojure.core/defrecord is not equal to (doc defrecord) output |
| 18:30 | justin_smith | lavokad: that's the 1.3 version of the docs |
| 18:30 | justin_smith | &*clojure-version* |
| 18:30 | lazybot | ⇒ {:major 1, :minor 4, :incremental 0, :qualifier nil} |
| 18:30 | justin_smith | ,*clojure-version* |
| 18:30 | clojurebot | {:interim true, :major 1, :minor 7, :incremental 0, :qualifier "master"} |
| 18:30 | TheMonarc | what are the maiun reasons one might use clojure over other langs? |
| 18:31 | lavokad | goshh |
| 18:31 | lavokad | sorry |
| 18:31 | lavokad | thanks |
| 18:31 | lavokad | :) |
| 18:31 | justin_smith | lavokad: it's sad that the clojuredocs site has so much google-juice, and is so out of date |
| 18:33 | llasram | TheMonarc: My reasons: it runs on the JVM and provides high developer productivity |
| 18:33 | gfredericks | TheMonarc: lets you write pure functions on generic data and then use them in real life |
| 18:35 | hyPiRion_ | Efficient immutable data structures, and powerful functions to manipulate them. |
| 18:36 | justin_smith | a stable and predictable runtime that will be identical to your local development environment without needing all sorts of fashionable tooling |
| 18:37 | TheMonarc | example of "fashionable tooling" from another stack/lang? |
| 18:38 | justin_smith | docker, puppet, chef |
| 18:38 | justin_smith | various ways to try to automate the duplication of environments in production, that we typically just have no need for |
| 18:38 | TheMonarc | aren't those things orthogonal to language/VM choice |
| 18:39 | justin_smith | TheMonarc: I deploy servers that run if you have a jvm of 1.6 or newer |
| 18:39 | TheMonarc | BTW, i'm not a java developer either so excuse me if my questions are ignorant |
| 18:39 | TheMonarc | what if you have project that requires java version X |
| 18:39 | TheMonarc | and then another project that requires java version Y |
| 18:39 | justin_smith | TheMonarc: literally any machine meeting that spec suffices - you don't need much automation to make that work |
| 18:39 | TheMonarc | wouldn't someting like docker help w/ that? |
| 18:39 | llasram | justin_smith: I take issue with your terminology :-) |
| 18:39 | justin_smith | TheMonarc: java version x or newer is a trivial dep |
| 18:40 | TheMonarc | but X and Y are different |
| 18:40 | TheMonarc | wouldn't docker help switch back and forth between an environment where X is met, and one where Y is met? |
| 18:41 | justin_smith | TheMonarc: you can use the newer one - it really works that way |
| 18:41 | TheMonarc | justin, are you saying that specifically with Clojure |
| 18:41 | amalloy | java very very very rarely breaks backwards compatibility |
| 18:41 | TheMonarc | or just for Java in general |
| 18:41 | llasram | TheMonarc: Yeah, I can't really reflect justin_smith here. In my experience it's about the same as deploying software in other languages |
| 18:41 | llasram | I do think that the Java/Maven packaging and dependency systems ends up being somewhat better than almost everything else |
| 18:42 | llasram | But AFAICT packaging is something no-one ever gets completely right :-( |
| 18:43 | justin_smith | llasram: we may be trying to do different things. I have never ended up needing a setup more complex than "jvm v. x or newer" *(plus a reverse proxy, which every language needs) |
| 18:43 | justin_smith | for a webapp that is |
| 18:44 | TheMonarc | any recommendations on a noob to get started with clojure? |
| 18:45 | TheMonarc | like what should i do once I do "Hello World" in clojure? |
| 18:45 | justin_smith | ~books |
| 18:45 | clojurebot | books is http://clojurebook.com/ http://joyofclojure.com/ |
| 18:46 | bounb | TheMonarc: i am a clojure novice working thru clojurebook.com and i recommend it |
| 18:46 | justin_smith | TheMonarc: I also like aphyr's clojure from the ground up series http://aphyr.com/posts/301-clojure-from-the-ground-up-welcome |
| 18:46 | bounb | it will answer your question "why clojure" at the start too |
| 18:46 | devn | out of curiosity, does anyone here use slime still? |
| 18:47 | justin_smith | iirc amalloy does |
| 18:47 | devn | is it usable anymore? |
| 18:47 | amalloy | devn: works fine |
| 18:47 | devn | because, and i seriously mean no offense here, i think i preferred it way more |
| 18:47 | llasram | justin_smith: Mine isn't that much more complicated, but I find having a version-controlled, executable, repeatable description of the full deployment utterly invaluable |
| 18:47 | devn | amalloy: do you by any chance have a gist of the relevant config laying around? |
| 18:47 | amalloy | devn: {:plugins [[lein-swank "1.4.5"]]} |
| 18:48 | devn | amalloy: yeah, was referring to emacs |
| 18:48 | justin_smith | devn: there were some really cool things about slime that I missed. The complaint I seem to remember was that the underlying slime was a fast moving and often breaking target, but I don't see any major improvement on that in cider. |
| 18:48 | amalloy | what relevant config? |
| 18:49 | amalloy | justin_smith: lein-swank uses a four-year-old snapshot of slime, works fine. definitely not fast-moving |
| 18:49 | devn | amalloy: i remember back in the day having to set a bunch of things up to get everything working |
| 18:50 | amalloy | well |
| 18:50 | devn | amalloy: what do you have in your emacs config related to slime/swank? and you just mentioned the other question: what packages do you have? do you install slime from marmalade? slime-repl? slime-clj? |
| 18:50 | amalloy | you probably have to do some, but not actually that much. i don't really know; i've just copied around the files i installed four years ago |
| 18:50 | devn | im just looking for the: "this is the absolute minimum required to jump back to lein-swank" story |
| 18:51 | devn | amalloy: lol yeah, that's basically what im asking for -- would you mind gisting what you're using? |
| 18:51 | amalloy | devn: clone git@github.com:amalloy/clojure-mode and add it to your load-path, and then (require 'clojure-mode). i think it gets a version of slime from lein-swank |
| 18:52 | devn | amalloy: oh, and the more recent version of clojure mode brings in nrepl or cider or something? |
| 18:52 | amalloy | maybe |
| 18:52 | justin_smith | devn: I think the newer clojure mode is agnostic to the repl integration |
| 18:52 | justin_smith | devn: for example I require both clojure-mode and nrepl |
| 18:52 | amalloy | (setq clojure-swank-command "lein with-profile +swank jack-in %s") is good too, so that you can have {:swank {:dependencies ...}} in your project.clj |
| 18:52 | devn | i have a brand new computer sitting in front of me. i was carrying around emacs config for years and i recently blew it all away |
| 18:53 | justin_smith | (I still have not made the cider plunge) |
| 18:53 | devn | otherwise i wouldn't bother you |
| 18:53 | TheMonarc | oh and tell me about repl |
| 18:53 | TheMonarc | in a nutshell |
| 18:53 | TheMonarc | i keep reading people mentioning REPL |
| 18:53 | TheMonarc | in terms of haskell, scala, and clojure |
| 18:53 | devn | TheMonarc: yessir! the repl dude! it's awesome! |
| 18:54 | amalloy | devn: you can see my .emacs and .emacs.d at github.com/amalloy/dotfiles, but i don't promise that they're clean and easy to read |
| 18:54 | TheMonarc | but what exactly is it |
| 18:54 | TheMonarc | and why do people rave about it so much |
| 18:54 | justin_smith | TheMonarc: clojure is designed such that everything you can do in clojure (with very few exceptions) can be done in the interactive interpreter (the repl) |
| 18:54 | devn | TheMonarc: REPL stands for Read Eval Print Loop. |
| 18:54 | amalloy | between that, my clojure-mode, and .lein/profiles.clj, that's all i *know* i have set up. there may be some old packages lying around, and if so sorry |
| 18:54 | devn | amalloy: thanks |
| 18:54 | TheMonarc | ok so kind of like the scheme interpreter we used in school |
| 18:54 | TheMonarc | Dr. Scheme |
| 18:54 | devn | amalloy: that's no problem. thanks much |
| 18:54 | justin_smith | TheMonarc: right, that is also a repl |
| 18:55 | devn | TheMonarc: yeah, so im going to attempt to convey what i believe to be the "right" way to develop clojure |
| 18:55 | devn | but some people don't do this |
| 18:55 | justin_smith | but clojure's repl is technically not an interpreter, it compiles code as it goes |
| 18:55 | TheMonarc | k, i'm all ears |
| 18:55 | devn | TheMonarc: let's say you're in your editor, and you're in a file: src/hello_world/core.clj |
| 18:56 | amalloy | justin_smith: IMO that's an implementation details: as far as a user can observe, it's an interpreter |
| 18:56 | devn | so inside of there you have (ns hello-world.core (:require [clojure.string :as str])) |
| 18:56 | devn | and you have (defn hello [name] (println (format "Hello, %s" name))) |
| 18:56 | devn | you "connect" or "jack in" to your project |
| 18:57 | devn | and then you can evaluate (and re-evaluate) chunks inside of that file |
| 18:57 | devn | so first you might want to evaluate the ns declaration at the top. so you do that, and it returns nil. cool. then you evaluate your hello function |
| 18:57 | devn | but it turns out you didn't quite like it, so you change some stuff inside of it, and evaluate it again from your editor |
| 18:58 | TheMonarc | ok that sounds pretty cool |
| 18:58 | devn | it's very playgroundish |
| 18:58 | TheMonarc | one more question for now |
| 18:58 | TheMonarc | any IDE's or editors recommended for use with Clojure? |
| 18:58 | devn | ive seen people doing clojure who dont really use the REPL to their advantage |
| 18:58 | devn | instead they run the whole program every time |
| 18:59 | justin_smith | my development is more directly repl-centric, where I experiment with code in the user ns in the repl until I have the basic structure, then adapt that into my individual namespace |
| 18:59 | devn | that's backwards in clojure IMO |
| 18:59 | bounb | devn: how does one 'connect' or 'jack in' |
| 18:59 | devn | bounb: what editor are you using? |
| 18:59 | bounb | vim |
| 18:59 | TheMonarc | devn, is there an article that describes how you use the REPL? |
| 18:59 | squidz | devn: clojure or clojurescript? |
| 18:59 | justin_smith | bounb: you can use fireplace for connecting vim to a repl |
| 18:59 | devn | TheMonarc: no, but i could show you if you want to do a google hangout |
| 18:59 | devn | squidz: clojure |
| 19:00 | TheMonarc | i'd like to get back to it and make sure i'm getting the most out of the REPL once i get through some hello world and other basic/intro stuff |
| 19:00 | bounb | justin_smith: nice, thx |
| 19:00 | TheMonarc | @devn, ah, i'm not at the point where i'm ready to do that yet |
| 19:00 | devn | clojurescript is harder |
| 19:00 | devn | but you can stil use the REPL |
| 19:00 | devn | bounb: https://github.com/tpope/vim-fireplace |
| 19:00 | bounb | tpope ✓ |
| 19:00 | amalloy | TheMonarc: whatever editor you're using probably has reasonable clojure support. but you might just do the primitive copy/paste from your editor to your repl for a while; it's not critical to get editor support set up until you're familiar with the language and a repl |
| 19:00 | devn | "There's a REPL in fireplace, but you probably wouldn't have noticed if I hadn't told you. Such is the way with fireplace.vim. By the way, this plugin is for Clojure. |
| 19:00 | devn | :) |
| 19:00 | justin_smith | TheMonarc: also, regarding your "what are good reasons to use clojure" survey question, now I am wondering what the bad reasons to use clojure are. |
| 19:00 | bounb | devn: thx |
| 19:01 | TheMonarc | because hipster |
| 19:01 | bounb | not at all |
| 19:01 | bounb | TheMonarc: what is your programming backgroun |
| 19:01 | bounb | d |
| 19:02 | TheMonarc | or do you mean what are the bad use cases for Clojure? |
| 19:02 | devn | lighttable has a really great setup by default |
| 19:02 | devn | you should try it out |
| 19:02 | TheMonarc | i code in C# |
| 19:02 | TheMonarc | i hate my current job |
| 19:02 | devn | TheMonarc: lol. it's going to be ok! |
| 19:02 | devn | you're here. that's all that matters. :) |
| 19:02 | TheMonarc | hahah |
| 19:02 | TheMonarc | yeah planning on branching out with various langs |
| 19:03 | TheMonarc | right now exploring scala and clojure |
| 19:03 | devn | clojure is a good train to get on. scala is... |
| 19:03 | devn | scala is... |
| 19:03 | TheMonarc | i figure i will touch on the JVM langs all together |
| 19:03 | devn | poorly designed. |
| 19:03 | bounb | it's not directly about clojure and the question "why clojure" is answered more succinctly in clojurebook.com but i think everyone (TheMonarc) should watch this great talk http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey |
| 19:03 | devn | amen bounb |
| 19:03 | bounb | just watched it earlier and was pretty blown away |
| 19:03 | TheMonarc | thanks for that recommendation |
| 19:03 | TheMonarc | adding it to my list |
| 19:03 | devn | that is THE talk. everyone needs to watch that talk. i think i watched it a dozen times when i first started getting into clojure |
| 19:04 | TheMonarc | spending this entire weekend watching programming vids and doing tutorials |
| 19:04 | devn | seriously TheMonarc -- sit down and watch it. it explains a lot of the Why? |
| 19:04 | bounb | <- starting to get into clojure ;) |
| 19:04 | bounb | yeah it's one of the best programming talks ive seen tbh, very... philosophically complete |
| 19:05 | devn | Rich's talks are all fantastic. The one post I ever wrote for the changelog: http://thechangelog.com/rich-hickeys-greatest-hits/ |
| 19:05 | devn | turned out to be the hottest post of the year and then i never wrote another |
| 19:05 | devn | im a terrible blogger. |
| 19:05 | TheMonarc | me too |
| 19:05 | bounb | haha nice yeah i saw this list earlier ill check out the rest! |
| 19:05 | TheMonarc | i have more blog entries in my drafts folder |
| 19:05 | TheMonarc | than i have actual publish posts |
| 19:06 | TheMonarc | do you guys use clojure at work? |
| 19:06 | devn | yes |
| 19:06 | TheMonarc | one of the reasons i'm gravitating towards clojure/scala |
| 19:07 | TheMonarc | and correct me if this impression si wrong |
| 19:07 | devn | almost 100% clojure, maybe 2% nodejs and ruby which will be rewritten soonish |
| 19:07 | TheMonarc | but ideally i'd get a job where those langs are being used in production apps |
| 19:07 | TheMonarc | and i feel like the caliber of developer working with those langs |
| 19:07 | TheMonarc | is going to be much higher than the C# dev's i interact with every day |
| 19:07 | TheMonarc | (there are some really good C# developers out there, but none of them are in the network of people i come across in my day job) |
| 19:07 | devn | TheMonarc: i know that i dont need to say it, but the following is just my opinion: dont waste your time with scala |
| 19:08 | devn | scala is a terrible language IMO |
| 19:08 | TheMonarc | haha |
| 19:08 | TheMonarc | well for now i'm at least going to expose myself to it |
| 19:08 | TheMonarc | i want to keep an open mind |
| 19:08 | devn | yeah, totaly fair |
| 19:08 | Wild_Cat | TheMonarc: it's kind of the same reasoning as that behind choosing to work in Python. In many cases, it's true |
| 19:08 | Wild_Cat | (although with Python it's becoming less so these days as it enters the mainstream) |
| 19:09 | devn | i dont know a ton about scala, but i know plenty to know that there's no way i'd ever want to seriously work with |
| 19:09 | TheMonarc | wait so what's so bad about scala? |
| 19:09 | devn | haha, oh gosh |
| 19:09 | Wild_Cat | because nobody just knows Clojure because it's what they learned at uni and/or their first job and couldn't be bothered to try something else |
| 19:09 | TheMonarc | even when i went onto #scala, i asked people if they used it at work and one guy went off on a rant about how much scala was an "illusion" |
| 19:09 | Wild_Cat | (whereas you just have to kick a trash can a couple times and J2EE/PHP developers fall out) |
| 19:10 | TheMonarc | which was ironic given that i was in the #scala channel |
| 19:10 | devn | TheMonarc: here's an example of the crazy shit they've done... i was talking with a JVM developer who told me that Scala's implementation of Value Classes causes 6^9 class files to be generated |
| 19:10 | devn | and that the reason why SBT (build tool) is so slow is because of I/O |
| 19:10 | TheMonarc | wow |
| 19:10 | Wild_Cat | o.O |
| 19:11 | bounb | lol... |
| 19:11 | devn | and worse |
| 19:11 | devn | their value class implementation still doesn't really solve the deeper problem on the JVM |
| 19:11 | devn | it doesn't really add them |
| 19:11 | devn | it's like a thin veneer of value classes |
| 19:12 | devn | but anyway, more evidence that scala is a bummer: gah, trying to find the video |
| 19:13 | devn | basically one of the co-founders of typesafe and a massive contributor to Scala. like 900+ closed issues. 500 issues filed. |
| 19:13 | Wild_Cat | the damning evidence against Scala is that I've heard *Haskell* developers complain that Scala's type system is scary. |
| 19:13 | devn | decided that scala is horribly broken |
| 19:13 | devn | and he left typesafe |
| 19:13 | bounb | u guys fans of haskell? |
| 19:14 | bounb | ive started learning it... a few times haha |
| 19:14 | devn | sure, im a fan. there's tons to learn in haskell land. |
| 19:14 | devn | i find the clojure crew a much more pragmatic bunch |
| 19:14 | TheMonarc | any of you tried F#? |
| 19:15 | devn | i also find the people in the clojure community to be a lot more helpful, friendly, nice overall, less prone to pissing contests |
| 19:15 | Wild_Cat | bounb: it's a fantastically elegant language, with tons of excellent ideas. No language I've ever touched has changed the way I think about programming in general as Haskell. |
| 19:15 | bounb | :) |
| 19:15 | Wild_Cat | nonetheless, I've never used it in a real project and probably never will. |
| 19:15 | bounb | i see yeah |
| 19:15 | TheMonarc | the guy that writes the Clojure Gazette worked in haskell for a couple of years |
| 19:15 | Wild_Cat | I find Clojure far more pragmatic, and on the "smart type system" side of the spectrum it's actually Rust I want to learn. |
| 19:15 | devn | yeah, same her |
| 19:16 | devn | here* |
| 19:16 | TheMonarc | he didn't seem that thrilled by using Haskell |
| 19:16 | Wild_Cat | (as for my day job, Python all day every day with some C++ here and there) |
| 19:16 | devn | devops? |
| 19:16 | bounb | python is where i'm comfortable but it's boring |
| 19:16 | Wild_Cat | devn: no, backend for game development. |
| 19:17 | devn | python is a decent language. i like python. the `python -c "import this"` Zen of Python matches pretty well with Clojure's general philosophy |
| 19:17 | TheMonarc | do you have any personal strategies for learning new langs |
| 19:17 | Wild_Cat | (previously casual Facebook games in the 500K DAU range, now AAA) |
| 19:17 | TheMonarc | like do you just work on it when you get a chance and depend on your personal drive to get you to do it |
| 19:17 | amalloy | TheMonarc: one i've heard recommended is to have a "pet project", which you implement in each new language you want to learn |
| 19:17 | devn | TheMonarc: yeah, id do some problems on project euler and 4clojure |
| 19:17 | TheMonarc | or do you force yourself to work a certain # of hours per day or week or whatever |
| 19:17 | Wild_Cat | TheMonarc: find something you want to do, and implement it in the language you want to learn rather than in the one you know. |
| 19:17 | amalloy | then you're familiar with the problem space enough that you can focus on what's new about the language |
| 19:18 | TheMonarc | amalloy, interesting, i've been thinking of doing exactly that |
| 19:18 | Wild_Cat | even better if you can do it at work, but don't go too exotic in that case. People will hate you when they need to maintain your app written in Coq. |
| 19:18 | TheMonarc | in my head i call it my "Rosetta Stone Project" |
| 19:18 | TheMonarc | that i would implement in each lang |
| 19:18 | devn | but also what Wild_Cat said -- after you do a couple of basic things, pick something that's more like a project |
| 19:18 | TheMonarc | wild_cat, lol, yeah |
| 19:18 | devn | like writing an IRC bot or building a static site generator or a blog or something |
| 19:18 | TheMonarc | i know better than to burden coworkers with exotic stuff |
| 19:19 | devn | TheMonarc: i dont want to tell you i know for a fact what you're going through, but i was in what sounds like a similar position about 7 years ago |
| 19:19 | Wild_Cat | for example, the current micro-project I'm working on at work is something I'm currently writing in Python with Gevent and Pyramid (and Redis, which makes me learn more Redis and Redis is awesome), but I'll probably try a Rust rewrite at some point. |
| 19:19 | devn | i finally just quit with no plans |
| 19:19 | amalloy | TheMonarc: when i was still newish to clojure, i was working in php; i found it useful to sketch out in clojure the new stuff i needed to write in php, because the repl speeds things up so much. it probably helped me learn both languages |
| 19:19 | Wild_Cat | (e.g. if performance becomes a true issue, which I doubt it will) |
| 19:20 | TheMonarc | so i'll just need to decide on a project |
| 19:20 | devn | amalloy: yeah, that's a good point. i was doing a lot of ruby around the time i picked up clojure. i found that building up a table of | clojure function | ruby method | was helpful |
| 19:20 | Wild_Cat | also, I find DBs are as important to learn as languages. |
| 19:21 | devn | i also found that it made my ruby code a lot better |
| 19:21 | Wild_Cat | learn Mongo, learn Redis, learn a SQL database. |
| 19:21 | TheMonarc | yup |
| 19:21 | TheMonarc | i have a big ass list of stuff to learn |
| 19:21 | devn | booooo mongo :D |
| 19:21 | TheMonarc | rabbitmq is high up there |
| 19:21 | devn | postgres, rabbitmq |
| 19:21 | amalloy | TheMonarc: you could write a scheme interpreter. it's small enough, and i think you said you learned scheme at school |
| 19:21 | TheMonarc | i want to introduce it at work, which is stupid because we already have it one one project at work |
| 19:21 | amalloy | but of course if that doesn't interest you, do something else |
| 19:21 | TheMonarc | but the douchebag architect hides it from everyone |
| 19:22 | TheMonarc | literally, won't let anyone use it, so it's just sitting there being used by a single process, which kind of defeats the point |
| 19:22 | devn | TheMonarc: one thing i found really interesting when i came to clojure was metadata, and there are some fun exploratory projects you can do there |
| 19:22 | gfredericks | clojurebot: rabbitmq is hidden from everyone by the douchebag architect |
| 19:22 | clojurebot | In Ordnung |
| 19:22 | devn | ,(map (comp meta second) (ns-publics 'clojure.core)) |
| 19:22 | clojurebot | ({:ns #<Namespace clojure.core>, :name primitives-classnames, :file "clojure/core_print.clj", :column 1, :line 315} {:added "1.0", :ns #<Namespace clojure.core>, :name +', :file "clojure/core.clj", :inline-arities #<core$_GT_1_QMARK_ clojure.core$_GT_1_QMARK_@180023a>, ...} {:ns #<Namespace clojure.core>, :name decimal?, :added "1.0", :file "clojure/core.clj", :static true, ...} {:ns #<Namespace c... |
| 19:22 | Wild_Cat | devn: I really don't get the Mongo hate. It works. |
| 19:23 | devn | Wild_Cat: for small problems, yes |
| 19:23 | Wild_Cat | heck, I could spew way more hate on MySQL than on Mongo, because I've had real bad issues with the former. |
| 19:23 | TheMonarc | i prototyped a project in mongo |
| 19:23 | p_l | Wild_Cat: Well... you're comparing similar quality there |
| 19:23 | TheMonarc | and it was pretty easy and nice to use |
| 19:23 | Wild_Cat | devn: my previous company's biggest game uses Mongo and it's a breeze. |
| 19:23 | TheMonarc | but any documentDB would have been just as good in my case |
| 19:24 | p_l | TheMonarc: that's about main pros of Mongo I've ever seen have substance... |
| 19:24 | TheMonarc | a lot of the complaints about mongo i've seen have been people's own fault of using a documentdb when they really needed something else |
| 19:24 | devn | my experience has been: for quick things where i dont want to configure stuff and just start using a store, mongo is nice. |
| 19:25 | devn | once you start getting to the point of having a mongo cluster |
| 19:25 | devn | all hell begins to break loose |
| 19:26 | TheMonarc | yeah i'd be wary of any scenario that needed a cluster |
| 19:26 | TheMonarc | sharded at least |
| 19:26 | TheMonarc | if it was just replicated i guess that'd be fine |
| 19:26 | p_l | it's the same code and behaviour... |
| 19:26 | TheMonarc | i'd ha ve to do research before committing to mongo for something that needed a cluster though |
| 19:26 | devn | well, it's not a problem for other document stores |
| 19:27 | devn | ive heard good things about couch |
| 19:27 | p_l | (and some people caught Mongo dropping writes at load, which lead to funny things) |
| 19:28 | TheMonarc | devn, you mentione dyou use clojure at work |
| 19:28 | TheMonarc | what kind of stuff? web app(s)? |
| 19:28 | devn | yeah |
| 19:29 | devn | services and apps |
| 19:29 | TheMonarc | cool |
| 19:29 | devn | lots of clojurescript too |
| 19:29 | TheMonarc | nice |
| 19:29 | TheMonarc | do you do SOA/microservices? |
| 19:29 | Wild_Cat | fun fact, said game actually uses a Mongo cluster |
| 19:30 | Wild_Cat | it works trivially because players are essentially isolated from each other, which means we do massive numbers of extremely simple DB operations. |
| 19:31 | devn | TheMonarc: some "microservices" sure. i suppose it'd also be fair to just call them "appropriately sized services" |
| 19:31 | TheMonarc | haha |
| 19:31 | TheMonarc | yeah i've been reading about it the past week, and there doesn't seem to be a real definition |
| 19:31 | devn | everything is a microservice when you compare them to the services of old |
| 19:31 | TheMonarc | other than that they are "small" |
| 19:31 | TheMonarc | i never got into SOA, so i don't know if this distinction is correct |
| 19:32 | TheMonarc | but it seems when people talk about microservices |
| 19:32 | TheMonarc | there is also tendency to have all these services be called directly from an edge/front end system |
| 19:32 | Wild_Cat | TheMonarc: I think what people mean by "microservices" is actually "not SOAP. Anything but SOAP. Oh god, never again SOAP." |
| 19:32 | devn | TheMonarc: there are a lot of opinions, but just like anything else -- there are tradeoffs. |
| 19:32 | TheMonarc | i keep wondering how are you not running into latency issues |
| 19:32 | TheMonarc | timeouts etc |
| 19:33 | TheMonarc | was that also an issue with SOA? |
| 19:33 | devn | microservices are great until you need to start coordinating sweeping changes across 10s of them |
| 19:33 | devn | but maybe you already thought that through ahead of time and so it's not a big deal |
| 19:33 | TheMonarc | @wild_cat LOL |
| 19:34 | devn | microservices make a lot of sense at first glance i think. they forcefully decouple code. they potentially allow you to scale out critical services cheaper because you can just get lots of small EC2 instances instead of needing monolithic server horsepower |
| 19:35 | devn | but once you have 100 EC2 instances for some service, you need to coordinate them |
| 19:35 | TheMonarc | 100 EC2 instances... |
| 19:35 | Wild_Cat | microservices make a lot of sense architecturally when you decide to write your app as something that needs to easily scale up by spinning up new VMs in a cloud somewhere. |
| 19:36 | TheMonarc | seems like a lot |
| 19:36 | devn | im not being down on them. i think it's a great idea. it's not really a new idea either. |
| 19:36 | Wild_Cat | ...and once you start needing them to coordinate somehow, you need to involve a message queue or something similar. |
| 19:36 | devn | TheMonarc: heh, that's not much |
| 19:36 | Wild_Cat | because any other approach leads to madness. |
| 19:36 | TheMonarc | wildcat |
| 19:37 | TheMonarc | give an example of when you need to "coordinate" |
| 19:37 | TheMonarc | the instances |
| 19:37 | TheMonarc | do you mean put a piece of async work into a queue |
| 19:37 | Wild_Cat | most of the time, yes |
| 19:37 | TheMonarc | for a separate service to process? |
| 19:37 | devn | "we're overloading another service. everyone who is a service like me, slow down!" |
| 19:38 | TheMonarc | ah ok |
| 19:38 | TheMonarc | so a circuit breaker across all instances of Service A |
| 19:38 | TheMonarc | so they don't overload service B |
| 19:38 | devn | it's a simple example sure |
| 19:39 | devn | here's the thing. let's say you have 50 microservices. and some of those services talk to other services, who talk to other services |
| 19:39 | TheMonarc | i never had to implement something like that |
| 19:39 | devn | draw the graph |
| 19:39 | TheMonarc | but i imagined if i did, my naive approach would be to use a reddis cache or something to store state that Service A instances would use |
| 19:39 | devn | now tell me: do you think it will be more difficult to make changes? |
| 19:39 | TheMonarc | rather than a queue |
| 19:40 | TheMonarc | devn, yeah it seems like it'd be difficult to make changes |
| 19:40 | devn | if you change service A, and service B uses service A through Service C, and Service C uses Service B, and Service D uses B, and so on... |
| 19:40 | devn | you need to have that story figured out early on |
| 19:40 | TheMonarc | my thought on that |
| 19:40 | TheMonarc | was you could version the services |
| 19:40 | TheMonarc | so at the bottom of the graph (the nodes that everything else depends on), you deploy two versions side by side |
| 19:41 | TheMonarc | keep doing that "up" the graph till new stuff is all deployed |
| 19:41 | TheMonarc | then retire the old versions |
| 19:41 | devn | great, but now what does it take for you to do a release? |
| 19:41 | TheMonarc | probably a lot of problems with that approach though |
| 19:41 | devn | takes you forever now to get a deploy out |
| 19:41 | TheMonarc | so how do you sole that |
| 19:42 | devn | carefully ;) |
| 19:42 | devn | there are lots of things you could do, right? |
| 19:43 | devn | you could make logical groups of services which will depend on nothing but a single interface to another group of services |
| 19:43 | devn | sort of like organs in the body |
| 19:44 | devn | you could do as you're saying and actually keep legacy services online and transition them out |
| 19:45 | TheMonarc | and you should only have to do the side-by-side-and-then-transition-out thing when a service has a breaking change right? |
| 19:45 | devn | you could send your version over the wire to other services to tell them: "Hey! I'm newer than you!" |
| 19:45 | devn | or "I'm older!" so you can get the response you expect |
| 19:46 | devn | TheMonarc: well this is the thing, and this is why simulation testing is important |
| 19:46 | devn | if you have a really complex graph of microservices |
| 19:46 | devn | you need to be able to replay production traffic and simulate traffic so you can find out who talks to who |
| 19:46 | devn | bcause it changes often |
| 19:48 | devn | and make sure that everyone knows how to live in the "my microservice just got a tiny version bump and now everyone has to deal with it" world |
| 19:48 | joobus | does anyone here use the nginx-clojure module? |
| 19:49 | devn | i haven't |
| 19:49 | Wild_Cat | devn: as someone who's currently living in the "we refuse to upgrade from a 4-year-old version of MySQL that you can crash with a very simple query" world, that world you describe is tempting. |
| 19:49 | devn | Wild_Cat: it comes with its own set of problems though, yknow? |
| 19:49 | devn | the grass is always greener. |
| 19:49 | Wild_Cat | indeed. |
| 19:50 | devn | RAPID DEPLOY! GO GO GO! ... Oh wait, we need to manage this now... |
| 19:50 | devn | vs 4 years of QA |
| 19:50 | joobus | i've been reading the install tutorial but it's written in broken english... |
| 19:50 | devn | joobus: nginx is a product of russia after all :) |
| 19:50 | Wild_Cat | yeah, it's a tradeoff of "crap, it's broken!" vs "crap, it's still not fixed!" |
| 19:50 | devn | Wild_Cat: i prefer the middle |
| 19:51 | Wild_Cat | hence 'tradeoff' ;) |
| 19:51 | devn | "it's still not fixed because we will all have to coordinate" and "crap it's broken, but we knew about it when <1% of traffic was being passed through the new production environment" |
| 19:52 | justin_smith | devn: is there a SO like site for that kind of architecture / system design stuff (and better yet, also intersecting with the programming and implementation side) |
| 19:52 | TheMonarc | yeah i wish i had to deal with this kind of problem at work |
| 19:52 | joobus | you guys have time to do qa?!?! my company does QA if we have time... |
| 19:52 | devn | justin_smith: i dont really know much about the SO ecosystem |
| 19:52 | amalloy | justin_smith: probably serverfault |
| 19:52 | devn | joobus: QA has the word "assurance" in it, which makes it kind of a funny term to begin with |
| 19:53 | devn | "intended to give confidence" |
| 19:53 | justin_smith | amalloy: I thought that was more for administrators than designers - but maybe that crosses over more than I thought |
| 19:53 | TheMonarc | yeah serverfault is for like "how do i configure IIS to enable gzip compression" type questions |
| 19:53 | devn | QA means a lot of different things to a lot of different people |
| 19:54 | amalloy | programmers and SO probably fit too; between the three of them you should be able to ask most any question about this kind of stuff. but i haven't really tried |
| 19:54 | devn | "it isn't on fire." vs "i noticed that when we give this 2x the load we normally have in production it falls over." |
| 19:54 | devn | anyone have any experience with CQRS? |
| 19:55 | joobus | my comp uses python, so we don't see the error until someone hits that path. |
| 19:55 | TheMonarc | none of the microservices blog posts/articles i've read have really gone into any detail about how they handle the versioning scenarios that devn mentions |
| 19:56 | devn | that's because it's kind of buzzwordy IMO |
| 19:56 | TheMonarc | is that because the options are all messy/bad and no one wants to acknowledge it? |
| 19:56 | devn | i've seen a couple of posts (would have to dig them up from history) |
| 19:56 | devn | about "well, we tried, and we sort of got it right... but..." |
| 19:57 | devn | well some of it is kind of just...idk, trendy. |
| 19:58 | TheMonarc | currently have this article about CQRS in my open browser tabs: http://www.udidahan.com/2009/12/09/clarified-cqrs/ |
| 19:58 | TheMonarc | but i haven't done CQRS |
| 20:03 | devn_ | go strmpnk___ |
| 20:03 | devn_ | whoops |
| 20:03 | joobus | who here uses clojure professionally? |
| 20:04 | justin_smith | I do |
| 20:05 | joobus | do you work for a startup? |
| 20:05 | joobus | just wondering how much penetration clojure is getting in the "real world" |
| 20:05 | devn | i use clojure at work |
| 20:06 | devn | joobus: ive been around this community since pre 1.0 days and it is growing big time |
| 20:06 | justin_smith | joobus: not a startup - I have a contract with a digital agency supporting some sites I developed for them. Previously was salaried doing clojure for web site backends. |
| 20:06 | devn | i mean, the fact that wal mart labs and staples labs were at clojure west should tell you something |
| 20:06 | joobus | I've been tinkering for about a month now |
| 20:07 | devn | joobus: http://www.indeed.com/jobtrends?q=ruby%2Cjava%2Cscala%2Cclojure&relative=1&relative=1 |
| 20:08 | TheMonarc | http://www.indeed.com/jobtrends?q=scala%2Cclojure&l= |
| 20:09 | devn | if you're just looking for a job with a different JVM language, Scala is a choice |
| 20:09 | devn | if you want to be a happy human being who enjoys their work, clojure |
| 20:09 | devn | ;) |
| 20:10 | TEttinger | joobus, clojure is very startup-friendly, since an experienced dev can get an app up and running with a good deal less code than, say, Java. but there's also the advantage of being able to interop with existing Java codebases which is great for established companies that use Java too. I'm speaking in generalities and of course every company will have different needs, but clojure's strengths are aimed at being a business-friendly lisp |
| 20:10 | TheMonarc | what do you do for web/service frameworks with clojre |
| 20:10 | devn | joobus: TheMonarc: https://github.com/Dobiasd/programming-language-subreddits-and-their-choice-of-words |
| 20:10 | TheMonarc | do people use clojure specific frameworks |
| 20:11 | joobus | I currently don't have a JVM language in my toolset, nor a functional lang. I began looking into clojure on the recommendation of a friend using clojure at a startup |
| 20:11 | devn | https://github.com/Dobiasd/programming-language-subreddits-and-their-choice-of-words/raw/master/img/happy.png |
| 20:11 | TheMonarc | or do you use Spring/Dropwizard etc |
| 20:11 | TheMonarc | with clojure? |
| 20:11 | devn | TheMonarc: most people don't use "frameworks" |
| 20:11 | devn | the idea in clojure is -- libraries > frameworks |
| 20:11 | devn | compose your libraries and you can have your own framework |
| 20:11 | TheMonarc | @devn, nice |
| 20:11 | devn | there are some pretty common pieces in that stack though |
| 20:12 | devn | compojure and ring are ubiquitous |
| 20:12 | justin_smith | that said, I did help develop a big old clojure framework, even comes with a built in cms where you can create new data models for the site, or add new data, in web forms |
| 20:12 | devn | yeah, there's room for both |
| 20:12 | devn | but /historically/, the community has had an opinion on libraries instead of frameworks |
| 20:13 | justin_smith | definitely |
| 20:13 | joobus | what is everyone's opinion of datomic/ do most here stick to the SQLs with clojure? |
| 20:13 | devn | and like justin_smith: that said, ain't nothin wrong with a framework now and again |
| 20:13 | devn | joobus: if you need datomic use it. if you dont know why you need it, figure that out first. |
| 20:14 | justin_smith | devn: and how does one know they need datomic? |
| 20:14 | devn | by understanding what it is :) |
| 20:14 | devn | comparing it to relational DBs, document stores, k/v stores, etc. |
| 20:15 | objectiveous | Is there a simple way to inspect deftypes in order to understand what modifiers and annotations have been applied? |
| 20:15 | bbloom | ,09 |
| 20:16 | clojurebot | #<NumberFormatException java.lang.NumberFormatException: Invalid number: 09> |
| 20:16 | bbloom | ,0644 |
| 20:16 | clojurebot | 420 |
| 20:16 | devn | ,08 |
| 20:16 | clojurebot | #<NumberFormatException java.lang.NumberFormatException: Invalid number: 08> |
| 20:16 | devn | ,07 |
| 20:16 | clojurebot | 7 |
| 20:16 | justin_smith | objectiveous: aren't annotations a javac thing? deftype does not use javac |
| 20:16 | bbloom | weeee leading zeros equal octal |
| 20:16 | devn | bbloom: haha, something i learned doing a project euler problem many moons ago |
| 20:16 | devn | did you just run into it? |
| 20:17 | bbloom | yeah, i was tuning a parameter, deleted a leading 1, and the results just seemed... wrong |
| 20:17 | devn | ,(Integer/parseInt "09") |
| 20:17 | clojurebot | 9 |
| 20:17 | devn | bbloom: heh yeah |
| 20:17 | TheMonarc | "Never break their consumers. We agreed a standard early on to have a version number in resource paths (e.g. /1.x/products/12345/), such that if there is a need for a breaking change, a new version can be deployed side-by-side and get adopted by upstream consumers. Even though we still keep this capability, we haven’t needed to use it for years." |
| 20:17 | justin_smith | objectiveous: that said, you can look at the interfaces some obejct implements |
| 20:17 | TheMonarc | from here: http://dev.mixrad.io/blog/2014/08/22/MixRadio-Architecture-Overview/ |
| 20:17 | justin_smith | ,(-> [] clojure.reflect/reflect :bases) |
| 20:17 | clojurebot | #<CompilerException java.lang.ClassNotFoundException: clojure.reflect, compiling:(NO_SOURCE_PATH:0:0)> |
| 20:18 | justin_smith | ,(require 'clojure.reflect) |
| 20:18 | clojurebot | nil |
| 20:18 | justin_smith | ,(-> [] clojure.reflect/reflect :bases) |
| 20:18 | clojurebot | #{clojure.lang.APersistentVector clojure.lang.IObj clojure.lang.IEditableCollection} |
| 20:18 | devn | clojure.reflect is so nice to have |
| 20:18 | justin_smith | indeed it is |
| 20:18 | objectiveous | justin_smith, I'm not sure to what degree they are supported but I did see an email on the list describing the feature. Let me check... |
| 20:19 | devn | ,(->> (clojure.reflect/reflect []) :members (map (comp str :name)) sort) |
| 20:19 | clojurebot | ("EMPTY" "EMPTY_NODE" "NOEDIT" "_meta" "access$000" ...) |
| 20:20 | justin_smith | objectiveous: annotations are not a thing that exists on the jvm - they are a concept in the javac compiler. Most Clojure code, and all deftypes, do not go through the javac compiler. |
| 20:20 | devn | objectiveous: like extenders? |
| 20:22 | objectiveous | justin_smith, this is what got headed down this train of thought. https://gist.github.com/richhickey/377213 |
| 20:22 | justin_smith | objectiveous: oh I may have to eat my words here |
| 20:22 | justin_smith | my bad, sorry for the misinformation |
| 20:23 | justin_smith | that gist shows how to get the annotations, which is exactly what you were asking |
| 20:23 | objectiveous | justin_smith, ;-) But please don't stop helping me! I'm seriously in over my head. lol |
| 20:23 | devn | https://gist.github.com/richhickey/b5aefa622180681e1c81 |
| 20:24 | objectiveous | justin_smith, basically I'm trying to work with a clojure library that wraps the orientdb client java library. |
| 20:25 | objectiveous | It does a load of javassit jazz and doesn't like my typedef as it's Final. |
| 20:25 | llasram | objectiveous: Do you have a link to documentation about what you're trying to do with annotations? |
| 20:26 | justin_smith | objectiveous: the class being final, or the fields on the object being final? I readily believe the latter, but that can be fixed with deftype |
| 20:26 | objectiveous | llasram, checking... |
| 20:26 | justin_smith | to the degree that making fields mutible is fixing anything |
| 20:26 | devn | heh, insane: https://github.com/ztellman/cambrian-collections/blob/master/generate/cambrian_collections/vector.clj |
| 20:26 | devn | generate that java class with clojure! |
| 20:27 | llasram | objectiveous: My experience is that many Java systems which use annotations at runtime via reflection need other things which you can't do with deftype, like have zero-argument constructors with annotations on the constructor |
| 20:27 | objectiveous | justin_smith, I've already marked the fields so I believe the problem is with Class itself. |
| 20:27 | devn | you could proxy, no? |
| 20:29 | devn | maybe im missing the point |
| 20:29 | devn | but there's also this: https://github.com/clojure/clojure/blob/master/test/clojure/test_clojure/genclass/examples.clj#L32 |
| 20:29 | objectiveous | llasram, I suspect you're right and wonder what the most clojuresque approach would be? |
| 20:30 | devn | bah nevermind, i see what you mean now |
| 20:31 | llasram | objectiveous: My experience is that Java is a pretty strong DSL for implementing Java classes |
| 20:31 | bbloom | llasram: heh. |
| 20:32 | llasram | objectiveous: You can implement a tiny veneer Java class with exactly the interface (in the abstract sense), which then uses the Clojure Java API to load and run Clojure code for the actual implementation |
| 20:33 | llasram | objectiveous: Here's a lightening talk rhickey gave describing the approach: https://skillsmatter.com/skillscasts/3864-impromptu-rich-hickey-lightning-talk |
| 20:34 | objectiveous | I think maybe I'm starting to see the light. I'm building up a rather large information model and orientdb allows me to interact with that model as Documents or Classes. I liked the idea of having types but maybe I should rethink this a little, if I want to live in clojure land. |
| 20:34 | objectiveous | llasram, cheers! |
| 20:34 | devn | hrm, llasram this looks like annotations on 0 argument constructors? https://github.com/pallet/clojure-maven |
| 20:35 | llasram | devn: Where? |
| 20:35 | devn | ugh, im tired or something. i think im leading you down the wrong path |
| 20:35 | llasram | objectiveous: Good luck! |
| 20:35 | devn | sorry dude |
| 20:36 | llasram | ~guards |
| 20:36 | clojurebot | SEIZE HIM! |
| 20:36 | devn | lol |
| 20:37 | objectiveous | Thanks, folks. It's great to know there's a group of friendlies around to help a brother out, as they say. |
| 20:50 | justin_smith | objectiveous: bonus, today I learned more about how annotations are actually implemented |
| 20:57 | lavokad | im geting file not exception when doing this |
| 20:57 | lavokad | (GET "/" [] (println (slurp "/resources/html/header.html")))) |
| 20:57 | lavokad | (GET "/" [] (println (slurp "/resources/html/header.html")))) |
| 20:57 | lavokad | (GET "/" [] (println (slurp "/resources/html/header.html")))) |
| 20:57 | lavokad | (GET "/" [] (println (slurp "/resources/html/header.html")))) |
| 20:57 | lavokad | (GET "/" [] (println (slurp "/resources/html/header.html")))) |
| 20:57 | lavokad | (GET "/" [] (println (slurp "/resources/html/header.html")))) |
| 20:57 | lavokad | (GET "/" [] (println (slurp "/resources/html/header.html")))) |
| 20:58 | justin_smith | lavokad: resources is on your path |
| 20:58 | justin_smith | and /resources probably does not exist |
| 20:59 | justin_smith | also, if you want your code to work from an uberjar, change it to (slurp (io/resource "html/header.html")) |
| 20:59 | lavokad | im geting file not exception when doing this |
| 20:59 | lavokad | clear |
| 20:59 | lavokad | wtf |
| 20:59 | lavokad | ? |
| 20:59 | justin_smith | lavokad: because /resources is not the same as resources |
| 20:59 | lavokad | damn it.. |
| 20:59 | justin_smith | (slurp "resources/html/header.html") |
| 20:59 | justin_smith | but like I said, better to switch to io/resource and take out the resources/ part of the path, while you are at it |
| 21:00 | lavokad | sorry something broke and didnt see what i was writing |
| 21:00 | lavokad | justin_smith: sorry, then in which dir am I when i do (GET "/" [] (println (slurp "/resources/html/header.html")))) |
| 21:00 | lavokad | ? |
| 21:01 | justin_smith | lavokad: you are likely in your project dir |
| 21:01 | justin_smith | but as I said multiple times, /resources/html/header.html is not the same as resources/html/header.html |
| 21:01 | justin_smith | you want the latter |
| 21:01 | justin_smith | the extra / means "look for this on the top level of my filesystem, ignoring my current directory" |
| 21:03 | lavokad | oh no |
| 21:03 | lavokad | i'm blind |
| 21:03 | lavokad | :D |
| 21:04 | lavokad | thank you! |
| 21:30 | xeqi | anyone have a library for watching a file for changes? |
| 21:31 | justin_smith | there are a few. You can also create a watcher object via interop with nio (jvm 7+) |
| 21:31 | justin_smith | https://github.com/ibdknox/watchtower this one looks straightforward |
| 21:32 | justin_smith | but it uses polling, nio can use much more efficient OS level notifications (push from the system when the file is changed) |
| 21:33 | justin_smith | this one uses the proper java 1.7+ watcher api https://github.com/derekchiang/Clojure-Watch |
| 21:36 | justin_smith | there is also nio.file, we have a unit test on that lib which shows a lower level interop. https://github.com/ToBeReplaced/nio.file/blob/master/test/org/tobereplaced/nio/file_test.clj#L111 |
| 21:36 | xeqi | yeah, I was glancing at Clojure-Watch but don't see a stop-watch |
| 21:36 | xeqi | but I can use it as a base |
| 21:37 | justin_smith | the nio.file one is based on a watch-service object you create, which you can turn off, more or less |
| 21:37 | justin_smith | also you can just cancel the thread that takes events from that watcher |
| 21:38 | justin_smith | (assuming you are doing the reasonable thing and putting watching in its own thread) |
| 22:10 | TheMonarc | anyone tried http://clojurekoans.com/ ? |
| 22:14 | joobus | trying it now :) |
| 22:15 | amalloy | TheMonarc: clojure koans is probably fine, but for a flavor of the same thing with less setup you could try 4clojure.com |
| 22:24 | joobus | koans seems ok, solved a few just now |
| 22:24 | joobus | then i got stuck |
| 22:34 | mynomoto | clojurescriptkoans.com are good too. I don't remember if there is anything clojurescript specific there. |
| 22:37 | joobus | does anyone here use vim-fireplace? |
| 22:41 | mynomoto | anyone? |
| 22:41 | clojurebot | anyone is anybody |
| 22:42 | jgdavey_ | joobus: I do |
| 22:44 | joobus | i guess you would recommend it then? |
| 22:44 | joobus | i'm kind of a clojure noob at the moment |
| 22:45 | jgdavey_ | If you're a vim user, definitely |
| 22:45 | joobus | i tried vim-fugitive (for git) but just use command line git instead |
| 22:45 | joobus | didn't know if it was worth it |
| 22:46 | jgdavey_ | I put together a screencast on using vim-fireplace a couple months back. It may be useful for the basics: https://vimeo.com/98052766 |
| 22:46 | mynomoto | joobus: http://clojure-doc.org/articles/tutorials/vim_fireplace.html is a good place to start. |
| 22:47 | joobus | thank you |
| 22:47 | joobus | jgdavey_: i think i've run across your name in other searches as well |
| 22:48 | joobus | were you at clojure west? |
| 22:48 | jgdavey_ | I wasn't, unfortunately. |
| 22:53 | joobus | has anyone used lein fruit and lein droid? I'm wondering if it is possible to share common code between the two to deploy the same app to both platforms. |
| 23:18 | danielcompton | I just got a Kinesis advantage, man it's brutal on my typing |
| 23:18 | danielcompton | showing up 10 years of shoddy muscle |
| 23:18 | danielcompton | memory from typing badly |
| 23:20 | joobus | danielc: i looked at those but went with the microsoft natural whatver for $20 |
| 23:20 | joobus | do you like the keyboard? |
| 23:21 | danielcompton | joobus: still undecided. I think it needs a while to really give it a good test. It feels 'natural' on my hands which is good I guess. |
| 23:22 | danielcompton | It uses thumbs way more so now i have sore thumbs instead of sore pinkies |
| 23:22 | joobus | what did you use before? |
| 23:23 | danielcompton | Apple wireless keyboard |
| 23:23 | danielcompton | I'm also keen to try technomancy 's |
| 23:23 | danielcompton | Atreus |
| 23:23 | joobus | i personally have a cast on my right hand at the moment so i use 1 hand and a "typing pencil" in my other. it sucks. |
| 23:23 | danielcompton | adyn ergodox, and a keyboard.io |
| 23:23 | joobus | i hate the apple keyboards |
| 23:24 | danielcompton | joobus: that would be dumb. Are there one handed keyboard layouts? |
| 23:24 | joobus | no, the cast hopefully comes off in a week |
| 23:25 | Jaood | joobus: the microsoft natural is great :) |
| 23:25 | joobus | Jaood: i agree, best bang for the buck |
| 23:25 | maravillas | the ms natural 4000 feels like mush |
| 23:26 | joobus | maravillas: are you a mechanical keyboard user? or what? |
| 23:26 | maravillas | keys, that is |
| 23:26 | Jaood | http://en.wikipedia.org/wiki/Microsoft_Natural_keyboard#mediaviewer/File:MS_Natural_Keyboard_Elite.png |
| 23:26 | Jaood | had that one but black |
| 23:26 | maravillas | i'm an ms natural 4000 user :) |
| 23:26 | maravillas | i haven't gotten around to replacing it |
| 23:27 | talios | danielcompton - keyboard.io looks nice |
| 23:27 | danielcompton | talios: not out yet though :( |
| 23:27 | maravillas | i also use an apple magic keyboard and don't mind it |
| 23:28 | Jaood | the 4000 is bigger because of the media buttons |
| 23:28 | talios | danielcompton - *sadface* |
| 23:28 | danielcompton | maravillas: I liked the apple keyboard until i started using emacs |
| 23:28 | joobus | i have bigger hands, the 4000 lets me stretch my hands out a little better. the apple keyboards are too cramped for me. |
| 23:28 | maravillas | it is a little awkward, but thankfully i've never had rsi issues with it, somehow |
| 23:30 | danielcompton | my favourite is still https://farm3.staticflickr.com/2787/4397554484_739ae62eee_b.jpg |
| 23:30 | danielcompton | from technomancy |
| 23:30 | joobus | danc, lol |
| 23:30 | joobus | did you use one of those? |
| 23:31 | talios | danielcompton - combine that with http://www.muldersworld.com/photo.asp?id=25864 and you're a winner |
| 23:31 | talios | or just a sad loser :) |
| 23:31 | danielcompton | computering anywhere. Just add an Oculus Rift |
| 23:39 | joobus | does anyone here use the nginx-clojure module with nginx? |
| 23:39 | justin_smith | joobus: it's silly |
| 23:39 | justin_smith | just use nginx as a reverse proxy |
| 23:39 | joobus | to a ring server? |
| 23:39 | justin_smith | right |
| 23:40 | justin_smith | http-kit is a good choice |
| 23:40 | justin_smith | it can be helpful to run varnish too |
| 23:41 | joobus | nginx-clojure claims to be the fastest https://github.com/ptaoussanis/clojure-web-server-benchmarks |
| 23:42 | joobus | so i was curious how well it works |
| 23:42 | joobus | but the install tutorial was written in broken english and i kinda got lost |
| 23:42 | amalloy | joobus: i would not advise using nginx-clojure |