2015-12-08
| 00:00 | justin_smith | ,(,,,,+,,,,,,,,2,,,,,,,,,,2,,,,,,,),,,,,,,,,,,,,,,,,,,,, |
| 00:00 | clojurebot | 4 |
| 00:00 | dongcarl | justin_smith: oh, so it was just for aesthetic purposes? |
| 00:00 | justin_smith | right, they don't do anything |
| 00:00 | dongcarl | justin_smith: thanks! |
| 00:00 | justin_smith | well, they don't do anything a space or newline wouldn't do (of course) |
| 00:22 | dongcarl | Hi guys, is there anywhere that can explain clojure's loop and recur structure to me? I'm a scheme user and I don't think I've seen this elsewhere... |
| 00:29 | dongcarl | help anyone? |
| 00:32 | spieden | dongcarl: have you seen this page? https://clojuredocs.org/clojure.core/loop |
| 00:34 | dongcarl | spieden: yes... I think I get it now... so recur just binds the same variables that loop already bound, but to the new values passed to it? |
| 00:51 | owlbird | how do you guys test your code? |
| 00:53 | mlb- | dongcarl: sounds right to me |
| 01:08 | spieden | dongcarl: yeah exactly. like a tail optimized recursive call |
| 01:09 | spieden | dongcarl: compiles down to similar bytecode to a java loop i think |
| 01:16 | dongcarl | spieden: because the JVM isn't optimized for tail-recursion? |
| 01:16 | sara | Hi, how to call methods from db.clj in core.cljs,i have core.cljs file with login ui and i want to call a method from db.clj when i click a button |
| 01:16 | sara | please help me if anyone know this.. |
| 01:54 | ridcully_ | sara: you need to `require` your db ns. e.g. in your (ns ... (:require [my-ns.db :as db])) and then (db/dosomething ...) |
| 01:57 | jonathanj | i have some code that calls a function `fetch-contents` which does an HTTP GET and returns some contents, now to test this i'd rather that function returned some predefined data and made no network requests, i think this is called dependency injection? is there a convenient way to achieve this with Clojure? |
| 01:58 | jonathanj | i could of course pass the function as a parameter, but then the implementations get a bit longer and uglier |
| 02:01 | jonathanj | ooh, `with-redefs` looks like the winner |
| 02:01 | tolstoy | jonathanj You could also define the client with defprotocol, then have a "mock" implementation locally. |
| 02:02 | tolstoy | (defprotocol WebClient (get-data [_ params])) |
| 02:02 | jonathanj | you still have to pass the implementation to the fn, which is more or less the same as just passing my stubbed version |
| 02:03 | jonathanj | so i'm not quite sure what the point would be for a simple piece of code like this |
| 02:03 | tolstoy | For your test, you'd just do: (defrecord FakeClient [] protocol/WebClient (get-data [_ params] {:fake "data"})). |
| 02:03 | jonathanj | tolstoy: yeah, but you have to pass an instance of that to the fn trying to use it, not so? |
| 02:03 | tolstoy | jonathanj Yeah, what I was mentioning is better if you've got a bit of complication. |
| 02:03 | jonathanj | agreed |
| 02:04 | tolstoy | No, I don't think so. |
| 02:04 | tolstoy | There are two defrecords, the "real" one, and the fake one. You're writing tests to the protocol. |
| 02:04 | tolstoy | So, (get-data (FakeService.) "x" "y") or whatever. |
| 02:05 | jonathanj | okay, except that the tests aren't calling get-data directly |
| 02:05 | jonathanj | it's a higher level function |
| 02:05 | tolstoy | Ah. |
| 02:05 | tolstoy | That's where something like Component helps out. |
| 02:05 | jonathanj | like: (defn foo [uri] (do-stuff (http/get uri))) |
| 02:05 | tolstoy | with-redefs definately works. |
| 02:05 | jonathanj | i'm using system, which is built on component |
| 02:06 | jonathanj | how does component help me? |
| 02:06 | tolstoy | For tests, you create a new System with the mock deps you want, then start that up rather than the real one. |
| 02:06 | jonathanj | the deps still have to get somewhere somehow |
| 02:07 | tolstoy | Using component (or system)? |
| 02:07 | jonathanj | how does my mock dep get from my system to the foo function above? |
| 02:08 | tolstoy | How does the real dep get there? Just use the same way? |
| 02:08 | jonathanj | it's required? |
| 02:08 | Trioxin | is there anything wrong with creating things like maps and vectors with def to work with them later? So far in my tutorial I haven't seen it done but tried it and it seems to word as in (get vec1 :b) |
| 02:09 | jonathanj | tr. |
| 02:09 | jonathanj | Trioxin: (def) defines a value global to the namespace you call it in, so you probably don't want to use it for anything that isn't supposed to be global, or for simple examples/repl work |
| 02:10 | tolstoy | jonathanj : I can't speak to your system cause I can't see it, but I have stuff like (system-map {:web-svc (mk-web-svc) :data-svc (component/using ... {:web :web-svc})) etc. |
| 02:11 | Trioxin | jonathanj, I had put it in a defn to be used within it. so how would I work with a map or vector later? I keep seeing examples of both creating and searching them in the same line but never assigning a name to them. |
| 02:11 | tolstoy | So, in tests, I just make one of those, and instead of (mk-web-svc) I use (mk-fake-web-svc). The data-svc then uses that one. Since they both implement the same interface, it works. |
| 02:11 | jonathanj | Trioxin: what do you mean by "later"? |
| 02:12 | jonathanj | tolstoy: so say you had a function "foo" defined more-or less like i did above, how does it get access to the system map? do you have to pass it to it? |
| 02:12 | Trioxin | jonathanj, create a map and then get a value out of it later in a function |
| 02:12 | jonathanj | Trioxin: within the same function? |
| 02:12 | Trioxin | sure |
| 02:12 | jonathanj | Trioxin: perhaps you're looking for `let`? |
| 02:12 | jonathanj | ,(doc let) |
| 02:12 | clojurebot | "([bindings & body]); binding => binding-form init-expr Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein." |
| 02:13 | jonathanj | that's not actually that useful |
| 02:13 | jonathanj | https://clojuredocs.org/clojure.core/let |
| 02:13 | tolstoy | jonathanj Yes, or I'm assuming that "foo" is invoked in the context of an existing component, so has access to that components config. But I guess an example is better. Alas, I don't have one visible. |
| 02:14 | dongcarl | does clojure do `let' sequentially or in parallel? |
| 02:14 | jonathanj | sequentially |
| 02:14 | ridcully_ | sequentially |
| 02:14 | dongcarl | jonathanj: so similar to let* in lisp? |
| 02:14 | jonathanj | dunno, the only lisp i know is Clojure |
| 02:14 | ridcully_ | ,(let [a 1 b (inc a)] b) |
| 02:14 | clojurebot | 2 |
| 02:15 | dongcarl | jonathanj: ridcully_: thanks |
| 02:15 | jonathanj | tolstoy: sorry if i'm being stupid here, but i don't understand how "foo" actually gets a reference to the component in order to peel things out of it |
| 02:17 | tolstoy | jonathanj: https://gist.github.com/zentrope/ff6fee94f39927d1046f |
| 02:18 | Trioxin | jonathanj, I just read let. I am seeing in this tutorial though using defn to create functions that work with sets of data as maps and vectors. This is the accepted way of working with such datasets? |
| 02:18 | tolstoy | jonathanj: In that example, I'd make a new map for "testing" and use, say (make-fake-mail-svc) instead of the real one. |
| 02:18 | tolstoy | jonathanj: Then, when I call a function (do-something-that-results-in-mail (:biz-svc system)), my fake version would be invoked. |
| 02:20 | ridcully_ | Trioxin: top level def's (consider ^:const) are fine |
| 02:30 | tolstoy | jonathanj I guess in my apps, maybe nothing ever happens except it's inside one of the components. Perhaps you're doing something different? Crossed assumption in there somewhere. ;) |
| 02:43 | Trioxin | intellij is annoying me. It never lets me backspace a ( or ) or add one when I'm trying to correct a mistake in my program |
| 02:43 | Trioxin | i have to cut and paste them |
| 02:46 | TEttinger | Trioxin: sounds like you have paredit on? |
| 02:46 | TEttinger | it's on by default in cursive |
| 02:46 | Trioxin | thx |
| 02:46 | TEttinger | it's either a setting or a button to enable/disable it |
| 02:59 | ridcully_ | Trioxin: it's called structural editing. it can be toggled with a small button on the lower/right corner or in the settings |
| 03:02 | slaterr | sdf |
| 03:03 | luma | Trioxin: also, it's actually quite helpful, since it doesn't let you create uneven parentheses |
| 03:03 | qsys | clojure and desktop applications: is seesaw still the best option? or are there any other/newer/still maintained projects? |
| 03:03 | TEttinger | seesaw doesn't need changes really does it? I mean swing isn't changing |
| 03:03 | Trioxin | oic it. just need to turn it off every now and then |
| 03:04 | TEttinger | seesaw is really nice IMO |
| 03:04 | qsys | allright, never did much in seesaw so far... so well, it's nice and stable |
| 03:05 | qsys | good enough for me than |
| 03:05 | qsys | *then |
| 03:05 | TEttinger | it helps to check the source of the examples -- docs are good not great |
| 03:06 | qsys | ok, thanks. |
| 03:07 | Trioxin | For GUI of my clojure programs I'll be using nw.js for desktop |
| 03:08 | qsys | nw.js, so clojurescript? |
| 03:09 | qsys | reasons to use nw.js instead of seesaw? |
| 03:10 | Trioxin | HTML5, node, clojurescript, and I should be able to embed jars that can talk in the dom |
| 03:11 | Trioxin | as in an applet or you could just communicate on the backend of the app via node since node code in nw.js interops with the dom code |
| 03:12 | Trioxin | so very easy to make a GUI |
| 03:12 | qsys | yes, I can imagine that |
| 03:13 | qsys | but easier than, e.g. seesaw? (which looks really simple as well) |
| 03:13 | Trioxin | easy as making a webpage. styling with some jquery dropins |
| 03:15 | qsys | hmmm, maybe I should try both |
| 03:17 | qsys | if jars can be embedded in nw.js - that may be a bit of double resources useage: nw.js running on a javascript engine and starting a jvm for some logic |
| 03:17 | Trioxin | you could even do both and embed your app at 100% the window if you wanted the extra scripting and node |
| 03:18 | Trioxin | you can strip nwjs down to be pretty small getting rid of what you don't need |
| 03:19 | qsys | and have just plain access to filesystem and such - I'm talking about a rather small application for desktops only (yes, I have someone asking for that!?) |
| 03:20 | Trioxin | jvm will run as separate process i believe and still you have the interop |
| 03:23 | qsys | well, maybe time to compare seesaw and nw.js :p |
| 03:24 | Trioxin | in my experience, using html5 for desktop GUI comes out looking very nice very fast and then much of that code is then portable to cordova/phonegap |
| 03:26 | qsys | sound nice, so here I go... seesaw vs nw.js |
| 03:26 | qsys | might be fun. |
| 03:26 | Trioxin | http://jqueryui.com/ |
| 03:41 | Trioxin | I'm looking for the last jquery theme I used that was really nice but for some reason I'm missing a file. must be on my external drive |
| 03:42 | qsys | :) don't worry, I'll find out. |
| 03:42 | qsys | theming is not my biggest concern right now :) |
| 03:43 | Trioxin | http://www.jquery2dotnet.com/2013/05/jquery-ui-themes-collection.html |
| 04:06 | alexyakushev | Hello everyone |
| 04:07 | alexyakushev | What is the correct way to fully clojure.edn/read a stream until EOF? |
| 04:08 | muhuk | alexyakushev: does it stop reading halfway through? |
| 04:09 | alexyakushev | No, I just have a file with individual EDN objects, and I want to read them all one-by-one until the file ends |
| 04:09 | alexyakushev | Like `slurp`, but use clojure.edn/read instead |
| 04:11 | alexyakushev | Scratch the one-by-one part, I'm being incomprehensible. I just want to read all of them, without catching EOF exception manually |
| 04:11 | muhuk | alexyakushev: so you don't want an exception to be thrown on EOF? |
| 04:13 | alexyakushev | I thought there might be some utility reading function like `slurp` that just stops reading at the end of file, and returns the result |
| 04:15 | noncom | alexyakushev: why don't you slurp and then read-string? |
| 04:15 | noncom | alexyakushev: actually it sounds like you'd better wrap the individual edn objects into a edn [] |
| 04:16 | alexyakushev | Because the file is very big, and I reading it as a string first effectively doubles the memory required to process it. Even if it will be GCed shortly after |
| 04:16 | noncom | or maybe something like (read-string (str "[" (slurp file) "]")) |
| 04:16 | noncom | ah i see |
| 04:17 | alexyakushev | noncom: No, wrapping it in a top-level sequence is exactly what I don't want to do. EDN is not some filthy JSON, its meant to be streamed :) |
| 04:17 | alexyakushev | *it's |
| 04:18 | noncom | alexyakushev: afaik there's no such functionality readily available |
| 04:18 | alexyakushev | I want to have both the ability to read it object by object when I need that, and to read it all without extra hassle |
| 04:19 | alexyakushev | noncom: Yeah, I suspected that, just asked to be sure |
| 04:20 | noncom | alexyakushev: a bit contradictory to the term "edn is meant to be streamed".. but really, there are such holes in functionality - one of them i met when it turned out that clojures ns system is coupled with filesystem, and it is not possible to easily fetch namepsaces from, say, a database or network |
| 04:21 | alexyakushev | Yes, there is that |
| 04:22 | alexyakushev | I just recollect that in one of his talks rhickey said that being able to stream EDN or Transit objects is one of their advantages over JSON where you must have one top-level object |
| 04:23 | muhuk | streaming is streaming, EDN or JSON doesn't make a difference. |
| 04:24 | muhuk | what does `read` return? Multiple values or a single seq? |
| 04:25 | alexyakushev | muhuk: They do, in fact. Is "foobar" a valid JSON? |
| 04:26 | alexyakushev | *do differ |
| 04:26 | muhuk | alexyakushev: how do you connect having a top-level object with streamability? |
| 04:27 | alexyakushev | muhuk: How do you put three JSON objects — "foo", "bar", "baz" — on a stream? |
| 04:28 | muhuk | alexyakushev: how does `read` delimit EDN values of `foo` and `bar` (without ticks)? |
| 04:29 | alexyakushev | ,(read-string "foo bar") |
| 04:29 | clojurebot | foo |
| 04:29 | muhuk | alexyakushev: there's your top-level object, it's just not EDN |
| 04:30 | alexyakushev | There - where? There is no top level object in that string. There are two objects. |
| 04:31 | muhuk | :) |
| 04:31 | owlbird | how to add a list of data like ({:math 80} {:math 70} and output {:math 150 :count 2} |
| 04:31 | muhuk | alexyakushev: you can write a function that reads a stream of valid JSON, separated with whitespace. It would be no different than the streaming EDN. |
| 04:32 | muhuk | owlbird: there is no core function, if you are asking that |
| 04:32 | alexyakushev | owlbird: I don't think there is a single function that does exactly that. But you can construct it from parts |
| 04:32 | alexyakushev | ,(merge-with + {:math 80} {:math 70}) |
| 04:32 | clojurebot | {:math 150} |
| 04:33 | alexyakushev | Then you can `assoc` the number of maps to it |
| 04:33 | owlbird | awesome! |
| 04:34 | alexyakushev | muhuk: OK, now you have a stream of JSON objects separated by whitespace. Is that stream valid by JSON spec? How do you read a single value from it? |
| 04:35 | muhuk | alexyakushev: is `foo bar` valid EDN? |
| 04:35 | alexyakushev | Yes |
| 04:35 | muhuk | read-string said no above |
| 04:35 | alexyakushev | read-string said yes, it correctly read the first value |
| 04:36 | muhuk | alexyakushev: observe: |
| 04:36 | muhuk | ,(read-string "##") |
| 04:36 | clojurebot | #error {\n :cause "EOF while reading character"\n :via\n [{:type java.lang.RuntimeException\n :message "EOF while reading character"\n :at [clojure.lang.Util runtimeException "Util.java" 221]}]\n :trace\n [[clojure.lang.Util runtimeException "Util.java" 221]\n [clojure.lang.LispReader$DispatchReader invoke "LispReader.java" 677]\n [clojure.lang.LispReader read "LispReader.java" 263]\n [cloj... |
| 04:36 | muhuk | ,(read-string "foo ##") |
| 04:36 | clojurebot | foo |
| 04:37 | muhuk | alexyakushev: by your logic `foo ##` is also valid EDN |
| 04:37 | alexyakushev | `##` is not a valid EDN object |
| 04:38 | alexyakushev | But the reader stops before it |
| 04:39 | muhuk | alexyakushev: did you think why? |
| 04:39 | muhuk | if `foo bar` is valid EDN, why does read-string just read the first bit? |
| 04:40 | alexyakushev | Because `foo` is a valid EDN object. `read` reads the first object from the string and returns it. |
| 04:40 | alexyakushev | s/string/stream/ but the idea is the same |
| 04:41 | muhuk | no it's not. `foo bar` not valid EDN, `[foo bar]` is, also `(foo bar)` etc. |
| 04:41 | muhuk | `foo bar` is two valid EDN parts, joined with a space |
| 04:43 | muhuk | in spec it says "There is no enclosing element at the top level. Thus edn is suitable for streaming and interactive applications." |
| 04:43 | muhuk | I guess it's time I eat my words. :( |
| 04:45 | alexyakushev | muhuk: No shame as long as the knowledge increases after the discussion |
| 04:45 | alexyakushev | And you were right that by separating json elements on a stream with whitespace it might be enough to imitate this behaviour |
| 04:46 | alexyakushev | But since JSON spec says nothing about that, it is entirely on the shoulders of the implementor to either support that or not |
| 04:46 | muhuk | yeah, that bit I would still defend. JSON is as streamable as any encoding. |
| 04:47 | muhuk | the spec says there's no enclosing element at the top level, but there is actually an enclosing list/seq, implicitly |
| 04:47 | alexyakushev | There's no such thing as "JSON stream" officially |
| 04:47 | alexyakushev | https://en.wikipedia.org/wiki/JSON_Streaming |
| 04:48 | muhuk | yeah I know |
| 04:48 | muhuk | but in practise people do stream JSON |
| 04:48 | alexyakushev | Sure |
| 04:48 | muhuk | and it works just fine |
| 04:48 | alexyakushev | But if I say to me "I will send you a JSON stream", how should I treat that? |
| 04:49 | muhuk | you're right. I would ask how you delimit. |
| 04:49 | muhuk | "\r\n" is what's used mostly (prints well) |
| 04:49 | alexyakushev | Indeed. So it's not really JSON at this point, but our custom format on top of JSON |
| 04:50 | muhuk | alexyakushev: aren't you at least a bit curious why read-string doesn't support this behavior? |
| 04:50 | muhuk | I mean reads just the first thing, ignoring the rest. |
| 04:50 | alexyakushev | I think that's the behavior most people expect, or have learned to expect |
| 04:51 | alexyakushev | read-string is no different from read, except that it turns a string into a stream |
| 04:51 | alexyakushev | And I wouldn't want `read` to consume the whole stream if I need just one element |
| 04:51 | muhuk | but since I now know `foo bar` is valid EDN, I would expect to get a '(foo bar) and not just 'foo |
| 04:52 | alexyakushev | Imagine you have a 50GB file of EDN objects, and you want just the top 10 of them |
| 04:52 | muhuk | my point is, definition of valid EDN seems to differ, when you're expecting a stream and when you are not. |
| 04:53 | muhuk | alexyakushev: also did you try setting :eof param in options to something like ::this-is-the-end? |
| 04:56 | alexyakushev | Damn it, that's where they moved it! I'm so dumb |
| 04:56 | alexyakushev | Thanks, now that was really helpful:) |
| 04:56 | muhuk | alexyakushev: yw |
| 04:57 | alexyakushev | And back to `read-string` question |
| 04:57 | alexyakushev | Like I've said, `read-string` is just a wrapper around `read` |
| 04:58 | alexyakushev | So it shouldn't really know if somewhere later in the string there is invalid EDN |
| 04:59 | alexyakushev | A stream can't know that, a string can, but we'll have to parse the whole string first to ensure that all EDN is valid, and then return only the first element. Which is weird |
| 05:07 | sara_ | how to use web-server to handle the requests from clojurescript |
| 05:08 | muhuk | alexyakushev: that's what I'm saying: it is weird and confusing |
| 05:08 | muhuk | alexyakushev: I'm not really arguing though, if spec says it is, it is |
| 05:09 | alexyakushev | muhuk: It might be confusing at first, but at least it is consistent. Which is much more valuable for me |
| 05:09 | muhuk | but if I was designing it, I would make "streaming EDN" as an extension to EDN |
| 05:09 | muhuk | I don't think it's consistent |
| 05:10 | muhuk | for the same input; you get a seq from `read`, but `read-string` reads the first thing |
| 05:10 | ridcully_ | sara_: are you asking the same questions on stack-overflow? then see the comments there |
| 05:11 | muhuk | and paste the link to SO so we don't have to fish the details out |
| 05:11 | ridcully_ | sorry, i was just guessing |
| 05:12 | alexyakushev | muhuk: What is an example where you get different things from read and read-string? |
| 05:14 | muhuk | alexyakushev: take "foo bar", make a reader out of it. Essentially they are the same input right? |
| 05:15 | alexyakushev | Absolutely |
| 05:15 | alexyakushev | ,(read (java.io.PushbackReader. (java.io.StringReader. "foo bar"))) |
| 05:15 | clojurebot | foo |
| 05:16 | alexyakushev | ,(read-string "foo bar") |
| 05:16 | clojurebot | foo |
| 05:16 | muhuk | damn you alexyakushev, you made a fool of me again :D |
| 05:17 | muhuk | I thought read was returning a lazy-seq of some sort |
| 05:17 | alexyakushev | Oh |
| 05:18 | alexyakushev | Well, now you know:) It's all for the best |
| 05:18 | alexyakushev | And thanks again for pointing me at the correct edn/read option! I gonna do so some actual work now |
| 05:18 | alexyakushev | Cheers |
| 05:18 | muhuk | alexyakushev: OK, it's not confusing or inconsistent etc. anymore. Just need to RTFM |
| 05:19 | muhuk | byw |
| 05:19 | muhuk | bye |
| 07:36 | clgv | I tried to test direct linking with clojure 1.8-RC3 but it didn't seem to work. I used the following profiles {:uberjar {:aot :all}, :1.8-DL {:dependencies [[org.clojure/clojure "1.8.0-RC3"]], :jvm-opts ^:replace ["-Dclojure.compiler.direct-linking=true"]}} and assumed that direct linking should be used in "lein with-profile 1.8-DL do clean, uberjar" then |
| 07:38 | clgv | but functions are still resolved via .getRawRoot on call sites |
| 07:41 | Bronsa | clgv: I just tried and it's definitely direct linking my vars |
| 07:41 | Bronsa | with that same setup |
| 07:42 | clgv | Bronsa: ok, that's weird then |
| 07:43 | clgv | Bronsa: does direct linking have fallback code generated and I confused that? |
| 07:45 | clgv | I looked up the invoke function of my.ns$my_fn.class with a java decompiler |
| 07:46 | Bronsa | clgv: DL generates an invokeStatic method |
| 07:46 | clgv | Bronsa: in the same class? |
| 07:46 | Bronsa | yes |
| 07:46 | clgv | ok that's definitely missing |
| 07:46 | Bronsa | clgv: what functions are you trying to compile? |
| 07:46 | Bronsa | if you try (defn foo [x] x) (defn bar [x] (foo x)) |
| 07:47 | clgv | that's the layout, yes |
| 07:47 | Bronsa | bar should be compiled into invokestatic Foo.invokeStatic |
| 07:47 | clgv | Bronsa: I'll enter this simple example in the same namespace and check again |
| 07:50 | clgv | Bronsa: might be a build tool problem - the code is in a non-aot dependency library |
| 07:50 | clgv | though it is compiled just fine |
| 08:01 | clgv | Bronsa: is there a known issue with leiningen 2.5.0 wrt dynamic linking or jvm options? |
| 08:01 | Bronsa | no idea |
| 08:05 | clgv | there's not a single invokeStatic in the whole target/classes folder :( |
| 08:14 | Bronsa | clgv: I'm using lein 2.5.3 and it works fine |
| 08:14 | Bronsa | I really don't see why lein would affect DL though |
| 08:15 | clgv | me neither, I should just set the JVM options and then it is supposed to work |
| 08:16 | Bronsa | are you sure you're using 1.8? |
| 08:17 | clgv | yes, according to lein with-profile 1.8-DL deps :tree |
| 08:25 | clgv | Bronsa: a simple dummy project without profiles worked |
| 08:27 | clgv | ok, the :jvm-opts in the profile seem to be the problem |
| 08:36 | noncom | did anyone use Pallet for shell scripting in Clojure? http://palletops.com/pallet/doc/reference/script/ |
| 08:39 | clgv | noncom: yes some small remote startup scripts |
| 08:39 | noncom | clgv: did you find it really useful? |
| 08:40 | noncom | i mean, it does not look like it allows using {}s easily.. |
| 08:40 | noncom | just does some very rough and primitive clj->bash translation? |
| 08:41 | clgv | I just needed bash scripts so it was good for that job |
| 08:41 | clgv | I am not sure what you mean with "allows using {}s easily." |
| 08:42 | noncom | clgv: well, if i would like to use the capabilities of {}s for data manipulation, that won't work since there are no analogous bash concepts |
| 08:43 | clgv | "{}s" = shortcut for clojure maps? |
| 08:45 | ARM9 | {} is an empty map |
| 08:45 | clgv | ARM9: sure, I was trying to find out what it meant for noncom in his description of bash tasks |
| 08:46 | noncom | clgv: oh, yes, sorry, i meant exactly maps, right |
| 08:46 | noncom | i just find that in clojurespeak, typing {}, [] or () or {:kw [] ..} is a good way to describe data structs |
| 08:47 | clgv | noncom: yeah, in bash you get just streams that you can pipe through different programs |
| 08:49 | clgv | "^doubles" is not resolved anymore in Clojure 1.8? |
| 08:49 | clgv | previously it could be used to tag arrays to avoid reflection |
| 08:53 | clgv | What is the correct way to type hint double arrays now? |
| 08:53 | clgv | ,(type (double-array 0)) |
| 08:53 | clojurebot | [D |
| 08:53 | clgv | that thing^^? |
| 08:54 | justin_smith | clgv: ^"[D" should work, but ^doubles should too |
| 08:56 | clgv | I have https://www.refheap.com/112483 which worked <= 1.6, and it had to be a string since there was a compiler error otherwise |
| 08:58 | justin_smith | clgv: I had no idea hints on let bindings would be on the symbol rather than the value |
| 09:00 | DEA7TH | Is there a function which would transform [1 1 3 1 3 1] into [[1 1] [1] [1]], treating each 3 as a separator like a string split? |
| 09:01 | clgv | ,(->> [1 1 3 1 3 1] (split-with #{3}) (remove #{3})) |
| 09:01 | clojurebot | (() (1 1 3 1 3 ...)) |
| 09:01 | clgv | ups |
| 09:02 | clgv | DEA7TH: ok so no. gotta write that yourself |
| 09:02 | justin_smith | clgv: `(let [a# ^doubles ~a] ...) appears to work with reflection warnings turned on I see no warning |
| 09:03 | clgv | justin_smith: there were error cases with that one |
| 09:03 | jeaye | DEA7TH: You can do that with a single reduce. |
| 09:03 | clgv | justin_smith: the metadata might get lost for macros (and inline fns?) |
| 09:03 | justin_smith | clgv: I got an error case with [^doubles a# ~a] but not with [a# ^doubles ~a] |
| 09:04 | clgv | justin_smith: which? |
| 09:04 | justin_smith | CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: clojure.core/doubles, compiling:(/tmp/form-init4469662376927938804.clj:1:1) |
| 09:04 | jeaye | DEA7TH: In each call to the reduce fn, conj onto the last vector; when you hit a 3, conj a new vector on |
| 09:04 | clgv | that it can not resolve clojure.core/doubles to a type? |
| 09:04 | DEA7TH | eh, I used str/split. it was actually a string, but I preferred to use partial rather than a lambda |
| 09:05 | clgv | justin_smith: yeah that's pretty strange that it works in functions but not in macros. but it is totally fine to type hint the binding name |
| 09:05 | DEA7TH | str/split's middle argument is the data, not sure why. |
| 09:07 | ridcully_ | ,(remove (partial = '(3)) (partition-by #{3} [1 1 3 1 3 1])) |
| 09:07 | justin_smith | clgv: my version works inline and inside macros |
| 09:07 | clojurebot | ((1 1) (1) (1)) |
| 09:08 | clgv | justin_smith: call it with a macro in argument position or an inline fn |
| 09:10 | clgv | justin_smith: the stupid thing is that I only get that error when AOT compiling |
| 09:10 | clgv | on repl it just compiles fine |
| 09:17 | DEA7TH | is there something like ctrl-o which works in the REPL? I have to retype 10 lines of code and I'd rather not do (uparrow 10 times + enter) 10 times |
| 09:18 | ridcully_ | DEA7TH: clojure-rlwrap: aliased to rlwrap -m -M .clj |
| 09:19 | ridcully_ | DEA7TH: CTRL-^ then open your $VISUAL |
| 09:24 | clgv | DEA7TH: better use some sane dev env with editor-repl-integration |
| 10:05 | Bronsa | clgv: (fn [a] (let [^doubles x a] (aset x 1 1.0))) works with no reflection warnings for me |
| 10:06 | clgv | Bronsa: sure, (defn ^doubles f [...] ...) caused an error when AOT compiling via leiningen, but not in REPL |
| 10:06 | Bronsa | clgv: that's wrong |
| 10:06 | Bronsa | metadata on var names is evaluated |
| 10:07 | Bronsa | doubles is resolved to the clojure.core/doubles function |
| 10:07 | clgv | Bronsa: but (defn f ^doubles [...] ...) does not work either |
| 10:07 | Bronsa | it should |
| 10:07 | Bronsa | I just tried, it works |
| 10:07 | clgv | Bronsa: I tried and got reflection warnings anyway. pre 1.8 the var was the place where the metadata was used to avoid reflection |
| 10:08 | Bronsa | (defn f ^doubles [] (double-array 10)) (aset (f) 0 1.0) |
| 10:08 | Bronsa | works w/ no refelction warnings |
| 10:08 | Bronsa | clgv: no, that never worked |
| 10:09 | Bronsa | clgv: it's always been the case that you can type hint on both the var name and the argvec |
| 10:09 | Bronsa | they have different semantics |
| 10:09 | Bronsa | type hints on arg name are evaluated, on the argvec are not |
| 10:09 | Bronsa | so (defn foo ^doubles [] ..) ~= (defn ^{:tag 'doubles} foo [] ..) |
| 10:09 | clgv | Bronsa: ok, maybe stale definition then... I tried all possibilities there.. |
| 10:10 | clgv | Bronsa: so is it now possible to only tag types on the arg vec? |
| 10:10 | Bronsa | no, you can do both, depending on the type hint |
| 10:10 | clgv | THat did only work for primitives up to clojure 1.6 |
| 10:11 | Bronsa | it always worked for every type hint, with some caveats |
| 10:11 | clgv | Bronsa: yeah, the caveats were what made me say it didnt work |
| 10:11 | clgv | Bronsa: so now I can establish the convention of only tagging the argvec in my projects? |
| 10:11 | Bronsa | yeah, those have been fixed in 1.8 |
| 10:11 | Bronsa | clgv: yes |
| 10:11 | clgv | great :) |
| 10:11 | Bronsa | I would suggest that |
| 10:13 | Bronsa | it has the additional benefit of throwing an exception when you use invalid type hints aswell (some are calling that a bug :( http://dev.clojure.org/jira/browse/CLJ-1863) |
| 10:14 | rhg135 | A npe... |
| 10:15 | clgv | Bronsa: well, let's switch that to a more informative exception ;) |
| 10:16 | clgv | so let's see whether there is an improvement through direct linking |
| 10:21 | Bronsa | rhg135: clgv: you try to convince clojure/core that type-hinting validation is reasonable and I'll be more than willing to fix that :) I've been starting that same discussion multiple times for over 3 years now and they just seem not to care |
| 10:22 | Bronsa | so a NPE at compile time to me is still an improvement over silently ignoring type hints & maybe throwing at callsite |
| 10:25 | rhg135 | The worrying part is that it could throw at runtime |
| 10:25 | clgv | Bronsa: read at least one of the discussions on the ML ;) |
| 10:26 | rhg135 | But then again if you need the type hint to not blow up, then you need more help |
| 10:34 | jonathanj | hrm, how can i turn an Enumeration<String> into a Clojure object that is readable using (println)? |
| 10:49 | rhg135 | seq |
| 10:49 | rhg135 | Maybe |
| 10:54 | jonathanj | (enumeration-seq) appears to have worked |
| 11:07 | jonathanj | class "org.bouncycastle.asn1.ASN1Object"'s signer information does not match signer information of other classes in the same package |
| 11:07 | jonathanj | how on earth do i resolve this type of error? |
| 11:21 | jonathanj | nevermind, figured it out with the help of `lein deps :tree` |
| 11:22 | jonathanj | is there something like (for) that would produce a map instead? |
| 11:22 | jonathanj | i could do (into {} (for ...)) but i was wondering if there was something more direct |
| 11:25 | j-pb | (into {} is the idiomatic way to create maps from pairs :) |
| 11:26 | j-pb | if you have a keysequence and a value sequence you can combine them into a map with zipmap |
| 11:26 | clgv | hmm no real difference between 1.8 and 1.8 with direct-linking on this benchmark |
| 11:27 | clgv | approx 5% improvement from 1.7 |
| 11:27 | rhg135 | Hey, that means non direct is pretty fast |
| 11:29 | clgv | ok, since I needed that code as fast as possible on 1.6 this likely means that I found all hotspots where inline functions were worth it ;) |
| 11:29 | rhg135 | Indeed |
| 11:30 | clgv | so this results is probably not that representative |
| 11:30 | rhg135 | Maybe it's meant for less hand optimized code |
| 11:30 | clgv | definitely |
| 11:30 | clgv | since the JVM can inline if it detects that as beneficial |
| 11:32 | rhg135 | The clojure compiler doesn't optimize much I think |
| 11:32 | rhg135 | But the jvm is good at it |
| 14:39 | Stalkr_ | Hi, I wish to explore some Clojure as I have heard a lot of good stuff about it. I am wondering though, I am just creating a very simple "Hello, World" server using Compojure, how come it eats over 100mb of RAM just for that? Is that just how it is with Clojure? |
| 14:44 | justin_smith | Stalkr_: yes, you can't run clojure code without loading the whole language and compiler into your runtime |
| 14:45 | justin_smith | Stalkr_: which is bad if you are worried about RAM usage, but in practice we tend to use it for things that start up once, stay running for months at a time, and we just live with the inflated memory usage. |
| 14:47 | Stalkr_ | justin_smith: I see, I'm only worried about having 512mb RAM on a cheap DigitalOcean host but I assume that means it takes more to reach 200mb or more RAM usage then |
| 14:53 | justin_smith | yeah, most of that usage is just from loading clojure itself - unlike most languages there is no way to run clojure without loading the full language (though there are experiments to do otherwise) |
| 14:54 | justin_smith | Stalkr_: if heap usage is a big concern, you could also check out clojurescript under node.js |
| 14:54 | Stalkr_ | justin_smith: I come from mainly JavaScript, so ClojureScript interests me too |
| 14:54 | Stalkr_ | but I suspect CS will be a pretty big change from JS too |
| 14:54 | justin_smith | Stalkr_: one bonus is all of js is accessible very easily from interop |
| 14:55 | justin_smith | which can be a crutch, but also eases things |
| 14:56 | Stalkr_ | justin_smith: I could run Express with ClojureScript through interop if I wanted right? I am not sure if Clojure or ClojureScript seems most appealing to me |
| 15:30 | juanjo_ | hi, can you help me with luminus? |
| 15:30 | juanjo_ | i have created a demo app with h2 |
| 15:30 | jonathanj | is anyone here familiar with <https://github.com/stuartsierra/component>? |
| 15:30 | juanjo_ | but id like to use postgresql in heroku |
| 15:31 | juanjo_ | how should I do it? |
| 15:31 | jonathanj | i have a question about composing components |
| 15:31 | codefinger | juanjo_: when you generate the luminus app use +postgres |
| 15:32 | juanjo_ | codefinger: that's the problem, the app is aready generated |
| 15:32 | juanjo_ | how can I add +postgres now? |
| 15:33 | codefinger | juanjo_: hmm, not sure. you could generate a new app and see what's different. but i don't think there is much. mainly the jdbc driver |
| 15:33 | codefinger | s/there is/there is not/ |
| 15:33 | juanjo_ | ok |
| 15:34 | codefinger | err no. was right first time :) |
| 15:35 | codefinger | juanjo_: i don't have an app in front of my but i think you'll need to add [postgresql "9.4-1201-jdbc4"] to project.clj |
| 15:37 | codefinger | juanjo_: and because yesql/conman use DATABASE_URL, it will just pick up the right driver for the postgres:// protocol |
| 15:39 | mavbozo | jonathanj, what is your question? |
| 15:40 | jonathanj | mavbozo: i think i've answered it, just testing some code |
| 15:41 | schmir | [org.postgresql/postgresql "9.4-1206-jdbc42"] |
| 15:46 | codefinger | schmir: +1 juanjo_ ^^ |
| 15:46 | juanjo_ | thanks |
| 15:46 | jonathanj | mavbozo: i'm actually using https://github.com/danielsz/system |
| 15:47 | jonathanj | anyway, i'm trying to use this component to define a ring handler: https://github.com/danielsz/system/blob/master/src/system/components/app.clj |
| 15:48 | jonathanj | but apparently whatever code i'm running doesn't match that |
| 15:49 | jonathanj | (component/using (new-app #'some-ns/my-ring-handler) produces clojure.lang.ArityException: Wrong number of args (1) passed to: app/new-app |
| 15:50 | jonathanj | oh, there has been a release since i last looked |
| 15:50 | jonathanj | thanks for the rubber duck session, mavbozo :| |
| 15:53 | mavbozo | jonathanj, :) |
| 15:58 | jonathanj | except now it's still not working, apparently some dependency is nil for reasons i'm unable to explain |
| 16:00 | ridcully_ | i thought the rubber duck was replaced with the plushy cthulu? |
| 16:02 | jonathanj | so (component/using (new-app #'some-ns/my-ring-handler) [:foo]) ends up invoking some-ns/my-ring-handler with nil as the only parameter, that makes no sense to me |
| 16:02 | jonathanj | in particular because another component is initialized before with the same component dependency and it's not nil there |
| 16:13 | mavbozo | jonathanj, i don't see any component/using usages in danielsz/system readme. |
| 16:15 | mavbozo | so, now you use stuartsierra's component directly? |
| 16:18 | jonathanj | mavbozo: i'm sure it mentions it, it might be kind of indirect |
| 16:18 | jonathanj | anyway, i discovered the issue, the new-app component expects the dependent component to be named "db" |
| 16:23 | jonathanj | which seems like a stupid requirement |
| 16:23 | justin_smith | Stalkr_: yes, you should be able to use Express with cljs |
| 16:24 | justin_smith | Stalkr_: sorry for the delay, just got back from lunch |
| 16:24 | justin_smith | Stalkr_: a walkthrough I found http://www.mase.io/code/clojure/node/2015/01/25/clojurescript-and-node-part-2-express/ |
| 16:26 | Stalkr_ | justin_smith: No problemo, I will probably give both a try over a few weeks, since I am interested in front-end too cljs with Om/Reagent or some React-wrapper like those seems very interesting. I'll give the article a look later :-) Does it make most sense to have Clojure on back-end + cljs on front-end or in that case keep it all cljs? |
| 16:29 | ridcully_ | jonathanj: in component the using part would name the things you want to autowire/inject |
| 16:30 | jonathanj | ridcully_: yeah, i mean that the "generic ring app" component in system has the thing named "db" |
| 16:32 | justin_smith | Stalkr_: I have not tried cljs on the backend but a friend has in production and says it works well |
| 16:32 | justin_smith | Stalkr_: but clojure on the backend is definitely the mainstream choice - it's the "official" version and all |
| 16:33 | MJB47 | cljs + node works well |
| 16:33 | MJB47 | but using normal clojure is easier imo |
| 16:34 | MJB47 | but depends what you wanna do |
| 16:34 | MJB47 | you obviously dont get threads with cljs |
| 16:34 | MJB47 | which you may or may not care about |
| 16:34 | Stalkr_ | justin_smith: I have tried to search for isomorphic (rendering JavaScript HTML server-side) but I could not find much, only a single article, but was thinking that it made more sense that with cljs to have isomorphic sites. Though I guess it should be possible with Java Nashorn |
| 16:34 | Stalkr_ | MJB47: is threads important when you have core.async? |
| 16:34 | MJB47 | core.async is just an abstraction |
| 16:34 | MJB47 | it doesnt replace threads |
| 16:35 | MJB47 | like you can do what core.async does with callbacks |
| 16:35 | MJB47 | https://www.youtube.com/watch?v=fICC26GGBpg |
| 16:35 | MJB47 | also i recommend this |
| 16:35 | Stalkr_ | I know, not saying it does but I mean it's the best we got for async programming with cljs right? |
| 16:35 | MJB47 | which goes into some depth about server side rendering |
| 16:35 | MJB47 | arguably yes it is |
| 16:36 | MJB47 | but if your project would like to have proper concurrency, i would not recommend node |
| 16:36 | justin_smith | Stalkr_: yeah, you might find something on pre-rendering reagent or om components via nashorn or node |
| 16:36 | Stalkr_ | Ahh cool, I'll give it a watch, I have seen some cool stuff with Clojure(Script), like Figwheel but I still feel like it's a very different world from JS |
| 16:37 | ridcully_ | jonathanj: i don't know system. i just added this, because component injects by the name _you_ give it in your record. so maybe the same with that other thingy |
| 16:37 | ridcully_ | jonathanj: if this just adds to the confusion... sorry ;P |
| 16:37 | Stalkr_ | MJB47: I am not sure when I would require that, but in any case, I could have one Node server for rendering, another pure Clojure for heavy tasks that requires proper concurrency right? |
| 16:37 | MJB47 | you could yes |
| 16:38 | Stalkr_ | Of course that is more expensive for the machine than a single Clojure + front-end cljs |
| 16:38 | MJB47 | but you have to think about the complexity that would involve |
| 16:38 | MJB47 | ultimately that might be the set up that suits you best |
| 16:38 | MJB47 | or it might not |
| 16:38 | MJB47 | who knows |
| 16:38 | gfredericks | tcrawley: ping |
| 16:39 | Stalkr_ | Yeah I don't have any particular reasons for using Clojure yet so that's hard to say, that will definitely be something I will have to think about some day when doing a real project |
| 16:39 | tcrawley | gfredericks: what up, dog? |
| 16:39 | gfredericks | tcrawley: are you familiar with the general idea of how component works? |
| 16:39 | Stalkr_ | but for now I will explore Clojure(Script) some more, see how it fits with me |
| 16:40 | tcrawley | I feel like that's a trick question, but I'll respond with a tentative yes |
| 16:40 | gfredericks | tcrawley: okay so I'm using immutant and component at the same time |
| 16:41 | gfredericks | which so far has been fine but now I want an http server too |
| 16:41 | gfredericks | and don't know enough about how immutant works to be able to tell if that is even possible |
| 16:41 | gfredericks | the big question I think is whether I can start/stop the web server myself, or if it has to be registered w/ the deploy somehow such that I don't have control over it |
| 16:42 | gfredericks | (this works fine with jetty instead of immutant, since you can just call start-jetty and get a server object that you can later stop) |
| 16:43 | tcrawley | gfredericks: see if https://github.com/danielsz/system/commit/1bdc182022bdbd79129d4f75bf770613b60a6499 is helpful |
| 16:44 | gfredericks | tcrawley: I bet so; okay thanks man thanks |
| 16:44 | tcrawley | you can pass the return value of immutant.web/run to immutant.web/stop, which is what ^ does |
| 16:44 | tcrawley | my pleasure! |
| 16:46 | gfredericks | tcrawley: wait wait what if I'm using immutant 1.1.4? |
| 16:46 | tcrawley | oh dear |
| 16:47 | gfredericks | I'm so sorry |
| 16:47 | tcrawley | in that case, you're kindof in a pickle |
| 16:47 | gfredericks | tcrawley: okay maybe my real question is about upgrading then -- do I have to upgrade other apps deployed to the same server in synchrony? |
| 16:48 | tcrawley | wait, you should be able to do something similar in 1.1.4 though, let me look |
| 16:48 | gfredericks | immutant.web/start doesn't say what it returns |
| 16:48 | tcrawley | if you want to upgrade, then you have to upgrade the container itself to WildFly, or move the apps out to run as uberjars |
| 16:49 | tcrawley | you can't run an Immutant 2.x app inside the Immutant 1.x container |
| 16:49 | gfredericks | roger |
| 16:50 | tcrawley | you can do (immutant.web/start "/" handler) (immutant.web/stop "/") |
| 16:50 | tcrawley | or (immutant.web/start handler) (immutant.web/stop), and "/" will be assumed in both casees |
| 16:51 | gfredericks | tcrawley: okay I will try that thanks Señor crawley |
| 16:51 | tcrawley | my pleasure! I'm always here for you |
| 16:51 | gfredericks | you are! |
| 16:52 | gfredericks | ~tcrawley is always here for me |
| 16:52 | clojurebot | 'Sea, mhuise. |
| 16:53 | jcrossley3 | gfredericks: one other thing, if it matters: there is an undocumented option, :auto-start, that can be set to false in order to create a server without actually starting it, after which you can (.start s) or (.stop s) it. that may play nicer with component, depending on what you're doing |
| 16:55 | gfredericks | jcrossley3: thanks; I think the main thing that feels weird about it is that it's global rather than OOP; but it amounts to the same thing I think so it's not a big deal |
| 16:55 | gfredericks | if you call immutant.web/start twice with the same args will the second one throw? |
| 16:55 | jcrossley3 | gfredericks: er... :auto-start is for the (server ...) function, not (run ...). that was added for pedestal, iirc |
| 16:57 | jcrossley3 | gfredericks: there is no start, only run or server. i don't think run throws if you restart. |
| 16:57 | gfredericks | jcrossley3: there's a start because I'm using a 17-year-old version of immutant |
| 16:58 | jcrossley3 | gfredericks: you probably need to stop doing that |
| 16:58 | gfredericks | jcrossley3: it's hard since there's like seven other apps too |
| 16:59 | jcrossley3 | gfredericks: SIMPLICITY IS HARD! |
| 17:00 | gfredericks | that was the punchline of rich's famous talk "Simplicity Is Hard" |
| 17:00 | jcrossley3 | gfredericks: fwiw, i would be surprised if start tossed if called twice |
| 17:01 | gfredericks | jcrossley3: roger roger ack ack |
| 17:01 | Morgawr | This is probably a silly question but what's the most elegant way to obtain the index of an element searched in a vector that fits a given condition? |
| 17:02 | Morgawr | like I have a vector of maps with an :id property and I want to get the index of a specific map with a given :id within that vector |
| 17:02 | gfredericks | (first (keep-indexed (fn [idx el] (when (pred el) idx)) coll)) |
| 17:02 | Morgawr | gfredericks: thanks, didn't know about keep-indexed :) cheers |
| 17:16 | tcrawley | gfredericks: calling start twice with the same context path should replace the former handler |
| 17:16 | gfredericks | tcrawley: the component gods are mildly sad about this |
| 17:16 | amalloy | Morgawr: also consider storing a map instead of a list, since you are looking stuff up by id often |
| 17:18 | Morgawr | amalloy: that's a good point, I'll keep that in mind. I need to check if I look it up more often than I need it ordered or not :) But yeh, I'll consider it |
| 17:18 | MJB47 | you could always use a sorted map |
| 17:58 | WorldsEndless | What's the clojure equivalent of "import namespace.*"? |
| 17:59 | tolstoy | Is it use? (use '[some.lib.core])? |
| 17:59 | amalloy | uhhh, it kinda depends whether you mean import or namespace or what. like, you import things, but not namespaces |
| 18:00 | WorldsEndless | So, java has import java.util.*; |
| 18:00 | WorldsEndless | That one happens to have a nice clojure wrapper, but for those that don't... |
| 18:01 | amalloy | there is no way to import all classes from a package |
| 18:01 | WorldsEndless | I suppose that's for the best |
| 18:01 | amalloy | yes, whenever you do it in java someone tells you not to |
| 18:01 | WorldsEndless | Just makes translating this java code a little trickier... |
| 18:02 | WorldsEndless | dang someone |
| 18:02 | WorldsEndless | can :import use :as the same way :require does? |
| 18:03 | amalloy | sadly not |
| 18:03 | amalloy | that is a feature that would be cool, unlike import foo.* |
| 18:03 | WorldsEndless | shucks |
| 18:09 | tolstoy | WorldsEndless: When porting java, I don't use imports at all. Let the compiler tell me what it can't find. Most of the imports aren't needed. |
| 18:23 | WorldsEndless | look what I found: |
| 18:23 | WorldsEndless | (:import [cc.mallet.util.*]) |
| 18:24 | WorldsEndless | So apparently you can do the bad stuff |
| 18:25 | amalloy | that just like...doesn't do anything |
| 18:25 | amalloy | that import is literally a no-op |
| 18:25 | WorldsEndless | Hmm... well, it's in the text book |
| 18:25 | amalloy | RIP textbook |
| 18:25 | amalloy | unless something new went into 1.8 i guess. i'm not super up to date |
| 18:28 | puredanger | Nope |
| 18:29 | amalloy | thanks puredanger, i just confirmed it myself by looking at the source too |
| 18:29 | amalloy | WorldsEndless: confirmed. who wrote this cargo-culting textbook? |
| 18:29 | WorldsEndless | Let's see... "Mastering Clojure Data Analysis" by Eric Rochester |
| 18:30 | WorldsEndless | cargo-culting? |
| 18:31 | amalloy | mmm. i haven't heard of eric rochester, and the book seems to be about data analysis, not about clojure. so like, he's obviously wrong, but that's not totally unexpected given the focus of the book, nor really a huge condemnation of the book either. if it were a book about clojure it'd be a bigger issue |
| 18:31 | amalloy | https://en.wikipedia.org/wiki/Cargo_cult#Metaphorical_uses_of_the_term |
| 18:32 | WorldsEndless | That's a great idiom. I'm gonna use it, so I look smart like you guys. |
| 18:33 | WorldsEndless | :| |
| 18:34 | WorldsEndless | Seriously, though, that's a great term. |
| 18:35 | justin_smith | somewhere there are polynesian devs that are like "yeah, my grandpa was in a cargo cult, and now I cargo cult in my code, what about it?" |
| 18:39 | Pupeno | What’s the best way to have one or more example programs that exercise my library in my library’s project? Should they be full leiningen projects on their own? |
| 18:40 | WorldsEndless | Pupeno: I'd try to make them as tests |
| 18:40 | Pupeno | WorldsEndless: I don't want tests, this is on top of tests. |
| 18:41 | WorldsEndless | In that case, making seperate lein projects is what I often see on Github, with a readme in the primary project that links to them |
| 18:53 | Takeiji | ls |
| 19:19 | didibus | I've asked this before, but what's the Clojure syntax for destructuring inside nested maps when using :keys ? |
| 19:20 | didibus | ,{:first "John" :last "Doe" :parents {:mother "Alicia" :father "George"}} |
| 19:20 | clojurebot | {:first "John", :last "Doe", :parents {:mother "Alicia", :father "George"}} |
| 19:20 | didibus | ,(let [{:keys [parents]}] |
| 19:20 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 19:21 | didibus | , (let [{:keys [parents]} {:first "John", :last "Doe", :parents {:mother "Alicia", :father "George"}}] parents) |
| 19:21 | clojurebot | {:mother "Alicia", :father "George"} |
| 19:21 | didibus | Now say I wanted mother and father too? |
| 19:32 | justin_smith | , (let [{:keys [parents] {:keys [mother father]} :parents} {:first "John", :last "Doe", :parents {:mother "Alicia", :father "George"}}] [parents mother father]) |
| 19:32 | clojurebot | [{:mother "Alicia", :father "George"} "Alicia" "George"] |
| 19:33 | justin_smith | also, it might be clearer not to do keys when you have nesting |
| 19:34 | justin_smith | , (let [{{:keys [mother father] :as parents} :parents} {:first "John", :last "Doe", :parents {:mother "Alicia", :father "George"}}] [parents mother father]) |
| 19:34 | clojurebot | [{:mother "Alicia", :father "George"} "Alicia" "George"] |
| 19:34 | justin_smith | , (let [{{mother :mother father :father :as parents} :parents} {:first "John", :last "Doe", :parents {:mother "Alicia", :father "George"}}] [parents mother father]) ; there's also doing away with :keys altogether |
| 19:34 | clojurebot | [{:mother "Alicia", :father "George"} "Alicia" "George"] |
| 19:35 | justin_smith | I think that version is a little easier to puzzle out (though :keys is convienient) |
| 19:54 | kenrestivo | what are some sane/reasonable ways to pass settings from a clojure app to a clojurescript app? |
| 19:55 | kenrestivo | i.e. i have src/foo.clj , i also have src-cljs/foo.cljs. it's not so much state that i want to share, as global settings. i can't use the network to pass the state because it involves setting up the network |
| 19:56 | kenrestivo | and project.clj is not the place for it, since i don't want these in git. i'm using schema and component to load settings from an edn file |
| 19:56 | amalloy | fwiw i think the :keys version is more readable than manual map destructuring |
| 19:57 | amalloy | justin_smith: ^ i have to read the manual map destructuring carefully because it being manual implies it's doing something more sophisticated than :keys |
| 19:58 | didibus | Wow, nice, so many different ways. |
| 20:00 | kenrestivo | yeah, :keys is fantastic. i'm addicted to it. |
| 20:01 | kenrestivo | makes it very clear when reading code, what things are passed in as parameters and where they come from |
| 20:02 | kenrestivo | and speaking of passing parameters... |
| 20:02 | kenrestivo | the current nasty hack i'm using is a moustache template with "var settings = {{{settings}}}" in the clj ring handler, and then reading that on the cljs side. |
| 20:03 | kenrestivo | (defonce state (atom {:settings (js->clj js/settings)}) etc. i hate this. |
| 20:19 | LuminousMonkey | Hey #clojure, sorry, I've got a question and my google-fu is failing. When it comes to lein deps, and specifying versions, is there a best practice? For example, I write a library that can be used with Clojure 1.6 or 1.7, etc. In the project deps do I specify a range, or just the latest version? |
| 20:22 | rhg135 | I'd just go for the latest. If people want to use old versions, they can read the readme |
| 20:26 | LuminousMonkey | I thought so, I've never noticed any problems, but I have had lein deps :tree give exculsion suggestions. I thought it might just a suggested way to stop my libraries causing that, even though I have noticed problems. Ta. |
| 20:26 | LuminousMonkey | *haven't |
| 20:31 | amalloy | ranges cause more problems than you can possibly imagine, despite seeming like good ideas on the surface |
| 20:36 | LuminousMonkey | So, basically just the highest version for all your deps at the time? |
| 20:36 | TEttinger | highest version you've tested with |
| 20:37 | LuminousMonkey | Cool. |
| 20:37 | LuminousMonkey | Ta. |
| 20:56 | didibus | Is there a function that sorts a nested map structure recursively in alphabetical order? |
| 20:57 | xeqi | is there a function that turns a channel into a lazyseq? |
| 21:01 | kenrestivo | a transducer might |
| 21:01 | TimMc | didibus: Not a single function, no, but there are tree walk fns + sorted-map-by |
| 21:04 | didibus | Ok, I'll look into the walk functions |
| 21:21 | TimMc | didibus: clojure.walk/postwalk seems to be the thing to use |
| 21:39 | dongcarl | Hi guys, can anyone explain to me what #(or %2 %1) does in (merge-with #(or %2 %1) state new-data)? |
| 21:39 | justin_smith | it's the same as (merge state new-data) |
| 21:40 | justin_smith | ,'#(or %2 %1) |
| 21:40 | clojurebot | (fn* [p1__26# p2__25#] (or p2__25# p1__26#)) |
| 21:40 | justin_smith | wait, not the same because the new-data could have false or nil |
| 21:40 | justin_smith | right, |
| 21:41 | dongcarl | so... #(or %2 %1) is like syntactic sugar for a lambda? |
| 21:42 | justin_smith | ,'#() |
| 21:42 | clojurebot | (fn* [] ()) |
| 21:42 | justin_smith | in general #(...) is syntactic sugar for a lambda, yeah |
| 21:42 | dongcarl | justin_smith: thanks! |
| 21:43 | justin_smith | one gotcha with #() is that it doesn't nest - because it would be impossible to specify the args |
| 21:43 | TEttinger | or will short-circuit evaluate in that case and, if the second argument given to the lambda is true, will return that without ever evaluating the first arg (I think) |
| 21:43 | TEttinger | pretty sure that's the reason for %2 and then %1 after it |
| 21:44 | TEttinger | ,(merge-with #(or %2 %1) {:a 1 :c 3} {:a 10 :b 20}) |
| 21:44 | justin_smith | TEttinger: the second item is already fully realized before the or sees it |
| 21:44 | clojurebot | {:a 10, :c 3, :b 20} |
| 21:45 | TEttinger | ah, so it's just to prefer the second arg then |
| 21:45 | justin_smith | right, which is the normal merge behavior |
| 21:45 | justin_smith | except special case for nil or false |
| 21:45 | justin_smith | ,(merge-with #(or %2 %1) {:a 0 :b 1} {:a nil :b 2}) |
| 21:45 | clojurebot | {:a 0, :b 2} |
| 21:45 | TEttinger | (I mean why %2 is before %1, which is normally a little odd) |
| 21:45 | dongcarl | justin_smith: what happens in those cases? how is it different? |
| 21:45 | justin_smith | ,(merge {:a 0 :b 1} {:a nil :b 2}) |
| 21:46 | clojurebot | {:a nil, :b 2} |
| 21:46 | dongcarl | justin_smith: ah! |
| 21:46 | justin_smith | in the merge case, the nil is newer, so it replaces the original |
| 21:46 | TEttinger | interesting |
| 21:46 | TEttinger | where's you see this code, dongcarl? |
| 21:46 | TEttinger | *where did |
| 21:47 | TEttinger | I'm a bit curious |
| 21:47 | dongcarl | TEttinger: one sec |
| 21:48 | dongcarl | TEttinger: https://github.com/shaunlebron/parinfer/blob/master/lib/src/parinfer/reader.cljc#L129 |
| 21:48 | TEttinger | ah ok thanks |
| 21:48 | dongcarl | I'm trying to port this to emacs-lisp for an emacs plugin |
| 21:49 | justin_smith | oh, cool |
| 21:50 | justin_smith | it would make writing lisps just like writing python or haskell I guess |
| 23:42 | kenrestivo | does this new 1.8 socket repl break nrepl? |
| 23:43 | justin_smith | it's meant to replace it |
| 23:43 | kenrestivo | :( |
| 23:43 | justin_smith | I would be surprised if it broke nrepl - it's going to be a better alternative though |
| 23:44 | justin_smith | kenrestivo: when I compare clojure startup times, nrepl, lein, and clojure itself are about equal in the time each takes to load - even just an improvement on that front would be great |
| 23:46 | kenrestivo | i'm sure it'll be better, i just have to budget time for dealing with all my tooling breaking |
| 23:47 | justin_smith | I'm actually not using anything that relies on nrepl at the moment - I use lein repl but only because that's easier than starting up clojure.main |
| 23:48 | dongcarl | HI guys can you help me understand what's going on here: https://github.com/shaunlebron/parinfer/blob/master/lib/src/parinfer/reader.cljc#L59 |
| 23:50 | justin_smith | it takes something like {:ch \)} then returns something different based on whether it's opening, closing, or neither |
| 23:50 | puredanger | kenrestivo: no, the socket repl does not break nrepl |
| 23:50 | justin_smith | or {:ch \a} - that's easier to read |
| 23:50 | puredanger | justin_smith: and no it is not intended to replace it |
| 23:50 | justin_smith | puredanger: oh! |
| 23:50 | puredanger | they are alternatives |
| 23:50 | justin_smith | puredanger: wishful thinking on my part |
| 23:51 | dongcarl | justin_smith: so I know that it takes in a state map which has a key :ch, would that work as well? |
| 23:51 | justin_smith | dongcarl: the other keys don't matter, it just looks at the :ch key |
| 23:51 | justin_smith | and that should have a char |
| 23:51 | TEttinger | \a is the syntax for char literal lowercase a |
| 23:51 | puredanger | justin_smith: the socket repl is really a socket server + a repl that runs over it. you could also run something that did nrepl framing over the socket server afaik if you wanted to |
| 23:51 | TEttinger | what would be 'a' in C or Java |
| 23:52 | justin_smith | ,(int \a) |
| 23:52 | dongcarl | justin_smith: if it's opening, it calls " |
| 23:52 | clojurebot | 97 |
| 23:52 | dongcarl | (defmethod push-char* :open ...)"? |
| 23:52 | justin_smith | it would be 97 in emacs |
| 23:52 | puredanger | the provided socket repl is stream-oriented, whereas nrepl is more message-oriented, as far as I understand it |
| 23:53 | justin_smith | dongcarl: defmulti defines the dispatch, the defmethods define what it does for different dispatch values |
| 23:57 | dongcarl | justin_smith: okay. So let me get this straight. It grabs ch from the :ch key in the input, checks if it's opening, if it is, it'd call (defmethod push-char* :open ...), then check if it's closing, if it is, it'd call (defmethod push-char* :close ...), otherwise, it calls a (defmethod push-char* ch ...), and if there are no defmethods with ch, then it calls (defmethod push-char* :default ...)? |
| 23:57 | justin_smith | dongcarl: no, it can only call one of the dispatch values |
| 23:58 | justin_smith | it either calls the method for :open, :close, or the char itself - though it's clearly poorly named, because looking at the methods defined, it is dispatching on string not char |
| 23:58 | dongcarl | justin_smith: okay so it's what I said but if one of the defmethods are called, the other ones aren't called? like an ifelse? |
| 23:59 | owlbird | how to write a fun just return its arguments? I tried eval like this (if (nil? style) #(eval %) #(:node %)), which seems very slow. |
| 23:59 | justin_smith | dongcarl: right, first the dispatch in the defmulti is called, and based on that, one of the dispatch values is called |