2014-07-03
| 02:05 | [Neurotic] | Hi, I've used extend-type, but no matter what I do, I can't seem to get it t compile. It keeps giving me 'unable to resolve symbol'. I'm not sure what I'm doing wrong here? https://www.refheap.com/87821 |
| 02:06 | [Neurotic] | I've done something stupid, but I can't see what it is |
| 02:35 | ddellacosta | [Neurotic]: what is get-value? |
| 02:36 | [Neurotic] | ddellacosta: what do you mean? it's defined on line 21 |
| 02:36 | ddellacosta | [Neurotic]: oh, I see, sorry |
| 02:36 | [Neurotic] | Ah cool. Wasn't sure if I was crazy :) |
| 02:36 | ddellacosta | [Neurotic]: try requiring storm.trident.testing in the same ns declaration |
| 02:37 | ddellacosta | [Neurotic]: damnit, sorry, you are. I must be sleepy today |
| 02:37 | [Neurotic] | nope, no win :( |
| 02:37 | [Neurotic] | unfortunately :/ |
| 02:37 | ddellacosta | [Neurotic]: well, wait, where is the type declared? |
| 02:38 | [Neurotic] | it's a Java type. |
| 02:38 | ddellacosta | oh |
| 02:38 | [Neurotic] | it's imported on line 15 |
| 02:38 | ddellacosta | [Neurotic]: right, thought it was a type though |
| 02:40 | ddellacosta | [Neurotic]: have you tried importing the get-value fn from marceline.storm.trident where the Protocol is defined? |
| 02:40 | ddellacosta | [Neurotic]: I think that's actually what you want to be doing vs. :refer :all from marceline.storm.testing |
| 02:41 | Viesti_ | hum |
| 02:41 | Viesti | doh, I had a tail! |
| 02:42 | [Neurotic] | [marceline.storm.testing :refer [get-value]] << like so? says it doesn't exist |
| 02:42 | ddellacosta | [Neurotic]: also, it may be the case that you have to define multiple-arity get-value separately: https://groups.google.com/d/msg/clojure/XeY7MGrcxLQ/6fMfdoWzjWMJ |
| 02:43 | [Neurotic] | ddellacosta: ooh, lemme try that |
| 02:43 | Viesti | why do <,>,=,<=,>= return true in the single argument case? |
| 02:43 | ddellacosta | [Neurotic]: also, not [marceline.storm.testing :refer [get-value]] but rather [marceline.storm.trident :refer [get-value]] |
| 02:44 | Viesti | we had a discussion on another channel where a guy had a bug in his code where he passed only one argument to = |
| 02:44 | Viesti | I understand and quite like of the generality in say < |
| 02:44 | Viesti | but maybe the one arg case is a bit confusing |
| 02:45 | Viesti | this haskell guy was of the opinion that such generality should live elsewhere, but thought about having a good argument on why to keep it in those functions. The generality is at least close in the source code :) |
| 02:48 | ddellacosta | Viesti: I think you'd probably get a good answer on the mailing list, but I don't have much other than a guess, which is to maintain consistency with other Clojure functions. But that's just a guess. |
| 02:50 | ddellacosta | [Neurotic]: did it work? |
| 02:50 | [Neurotic] | ddellacosta: nope, but I think I have another idea... need to try it |
| 02:51 | ddellacosta | [Neurotic]: multiple declarations per arity + that require didn't work? Hmm |
| 02:52 | [Neurotic] | I don't *think* so, I've kinda scrapped it, and trying it again, see if I did something stupid |
| 02:53 | ddellacosta | [Neurotic]: well, I don't have any great ideas past that; I hope you figure it out! Good luck |
| 02:54 | ddellacosta | [Neurotic]: oh, one more stupid freaking thing actually--I've had trouble when I had the import at the top of the ns statement vs. bottom, believe it or not |
| 02:54 | [Neurotic] | ddellacosta: looks like the refer worked for a friend of mine... I may try out his code |
| 02:55 | ddellacosta | [Neurotic]: okay, hope that works for you |
| 02:57 | [Neurotic] | ddellacosta: yep, working looks like. Actually needed a [marceline.storm.trident :refer [get-value]] |
| 02:57 | [Neurotic] | which brought in the get-value function from the protocol, so it knew what was going on |
| 02:57 | ddellacosta | [Neurotic]: ah okay, great |
| 02:58 | ddellacosta | [Neurotic]: thought it may be related |
| 03:10 | Viesti | ddellacosta: common lips has same single arity case for =,< etc. |
| 03:11 | Viesti | of course should have looked there :) |
| 03:12 | [Neurotic] | ddellacosta: yep, all passing now :) Thanks for your help! |
| 03:12 | ddellacosta | Viesti: what's the reason there? |
| 03:12 | ddellacosta | [Neurotic]: great! Glad you got it working. |
| 03:40 | Viesti | ddellacosta: didn't find out yet |
| 04:06 | petrust | How to combine secretary with Om? Should one manipulate the app state atom and then conditionally render in the main Om fn? |
| 04:06 | petrust | Or is there a different om call that I can call from my defroute fns? |
| 04:08 | borkdude | petrust I have an example of this |
| 04:09 | petrust | thx, borkdude :) |
| 04:09 | borkdude | petrust this might give you an idea: |
| 04:09 | borkdude | https://www.refheap.com/87825 |
| 04:10 | borkdude | petrust call define-routes from will-mount |
| 04:10 | borkdude | it needs the access to the data argument provided to the Om component |
| 04:10 | borkdude | that's why I used this construction |
| 04:11 | borkdude | petrust some more code: https://www.refheap.com/87826 |
| 04:12 | borkdude | hope this answers your question a bit |
| 04:12 | petrust | thanks, borkdude! |
| 04:38 | petrust | I’m having a weird issue with dependencies, specifically related to dependencies. |
| 04:38 | petrust | *related to secretary |
| 04:38 | petrust | I’ve added [secretary "1.2.1-SNAPSHOT"] to project.clj deps |
| 04:38 | petrust | I ran> lein clein |
| 04:38 | petrust | and lein cljsbuild clean |
| 04:38 | petrust | if I run lein deps, I get no output, so presumably all deps are satisfied |
| 04:38 | petrust | but if I now try to run lein cljsbuild auto, I get the following error: |
| 04:39 | petrust | Caused by: java.io.FileNotFoundException: Could not locate secretary/core__init.class or secretary/core.clj on classpath: |
| 04:42 | noidi | lein classpath | grep secretary |
| 04:42 | noidi | is the JAR on the classpath? |
| 04:43 | petrust | yes |
| 04:43 | petrust | it’s there |
| 04:44 | petrust | - /Users/petrus/.m2/repository/secretary/secretary/1.2.1-SNAPSHOT/secretary-1.2.1-SNAPSHOT.jar: |
| 04:46 | noidi | unfortunately I don't know enough about cljsbuild to help you :/ |
| 04:46 | petrust | downgraded dep to 1.2.0, same error. |
| 04:48 | ddellacosta | petrust: did you include secretary in any source files, or did you merely add it to the project.clj dependencies? |
| 04:48 | petrust | addid it to project.clj and :require it in my main.cljs |
| 04:48 | petrust | i.e. :require … [secretary.core :as s :include-macros true :refer [defroute]]) |
| 04:48 | ddellacosta | petrust: what happens if you get rid of :include-macros true, does it compile okay? |
| 04:49 | ddellacosta | petrust: and defroute, since that is a macro |
| 04:49 | ddellacosta | petrust: that is, only this: [secretary.core :as s] |
| 04:49 | petrust | seems to be working… |
| 04:51 | ddellacosta | petrust: huh, okay. What about if you then add the macro stuff back in via (:require-macros [secretary.core :refer [defroute]]) at the top of your ns form? |
| 04:52 | petrust | added back, compiling…works! |
| 04:52 | petrust | hmm |
| 04:52 | ddellacosta | petrust: weird. I'm not sure what is going on since I just created a brand new project and compiled it just fine w/secretary exactly as you described in your first example. |
| 04:53 | ddellacosta | I'll try cleaning as you did, see if that makes any difference |
| 04:54 | ddellacosta | nope, works fine...curious |
| 04:55 | ddellacosta | petrust: I'm wondering if there's some other wackiness happening in your project.clj, but I'm really not sure what would be causing this. However, if you can get it to work with :require-macros I suppose you're set... |
| 04:56 | joelkuiper | Does anyone have any experience with using core.async with the HTTP-kit server? Basically I have some (long running) process ops that return a channel (with the computer value on it when done). I'd like to use the HTTP-kit long-polling trick for sending the responses |
| 04:57 | joelkuiper | but I'm usure how to proceed; this is what I have right now https://gist.github.com/joelkuiper/d6c03488432f3146d72b |
| 04:59 | petrust | ddellacosta: ran lein cljsbuild clean, then lein cljsbuild auto again (with :include-macros), and it seems to work now. |
| 04:59 | petrust | must be some weird state or env var somewhere |
| 05:00 | ddellacosta | petrust: huh, okay, that's good. Sometimes an extra clean will do the trick, no idea why sadly... |
| 05:01 | petrust | tried a whole bunch of cleans - can’t replicate the error :/ |
| 05:07 | borkdude | petrust I had the same kind of error yesterday when I tried to write a macro in clojurescript |
| 05:07 | borkdude | cleaning, restarting, retrying.. at some point it worked |
| 05:14 | joelkuiper | https://stackoverflow.com/questions/24549565/using-http-kit-long-polling-with-core-async-channels |
| 06:12 | Janiczek | Is there any kind of polymorphism operating on two arguments? I'm creating a game and want to do things like (use-on :egg :pan), (use-on :bucket :cow) - but don't know how to NOT have a huge bloated definition of use-on. I'd like to be able to extend it from elsewhere |
| 06:13 | Janiczek | Would multimethods and (use-on [object subject]) instead of (use-on object subject) work? |
| 06:13 | Glenjamin | multimethods can dispatch on all arguments |
| 06:15 | Janiczek | Glenjamin: care to elaborate? |
| 06:15 | Glenjamin | yep, just typing a repl example :) |
| 06:16 | Janiczek | Glenjamin: great, thx :) |
| 06:16 | Glenjamin | ,(do (defmulti f vector) (defmethod f [:a :b] :a-and-b) (defmethod f [:c :d] :c-and-d)) |
| 06:16 | clojurebot | #<CompilerException java.lang.IllegalArgumentException: Parameter declaration :a-and-b should be a vector, compiling:(NO_SOURCE_PATH:0:0)> |
| 06:16 | Glenjamin | oh right |
| 06:17 | Glenjamin | ,(do (defmulti f vector) (defmethod f [:a :b] [&_] :a-and-b) (defmethod f [:c :d] [&_] :c-and-d)) |
| 06:17 | clojurebot | #<MultiFn clojure.lang.MultiFn@28500a> |
| 06:17 | Glenjamin | ,(f :a :b) |
| 06:17 | clojurebot | #<ArityException clojure.lang.ArityException: Wrong number of args (2) passed to: sandbox/eval56/fn--57> |
| 06:17 | Glenjamin | hrm, i guess i need to be more explicit |
| 06:17 | Glenjamin | ,(do (defmulti f (fn [a b] [a b]) (defmethod f [:a :b] [&_] :a-and-b) (defmethod f [:c :d] [&_] :c-and-d)) |
| 06:17 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 06:17 | Glenjamin | ,(do (defmulti f (fn [a b] [a b])) (defmethod f [:a :b] [&_] :a-and-b) (defmethod f [:c :d] [&_] :c-and-d)) |
| 06:17 | clojurebot | #<MultiFn clojure.lang.MultiFn@28500a> |
| 06:18 | Glenjamin | ,(f :a :b) |
| 06:18 | clojurebot | #<ArityException clojure.lang.ArityException: Wrong number of args (2) passed to: sandbox/eval138/fn--139> |
| 06:19 | Janiczek | ,(do (defmulti f identity) (defmethod f [:a :b] :a-and-b) (defmethod f [:c :d] :c-and-d) (f [:c :d])) |
| 06:19 | clojurebot | #<CompilerException java.lang.IllegalArgumentException: Parameter declaration :a-and-b should be a vector, compiling:(NO_SOURCE_PATH:0:0)> |
| 06:20 | Glenjamin | i could have sworn this worked :s |
| 06:21 | Glenjamin | oh right, it doesn't like my variadic thing |
| 06:21 | Glenjamin | (do (defmulti f (fn [a b] [a b])) (defmethod f [:a :b] [a b] :a-and-b) (defmethod f [:c :d] [a b] :c-and-d)) |
| 06:21 | Glenjamin | ,(do (defmulti f (fn [a b] [a b])) (defmethod f [:a :b] [a b] :a-and-b) (defmethod f [:c :d] [a b] :c-and-d)) |
| 06:21 | clojurebot | #<MultiFn clojure.lang.MultiFn@28500a> |
| 06:21 | Glenjamin | (f :a :b) |
| 06:21 | Glenjamin | ,(f :a :b) |
| 06:21 | clojurebot | :a-and-b |
| 06:21 | Glenjamin | ,(f :c :d) |
| 06:21 | clojurebot | :c-and-d |
| 06:21 | Glenjamin | ,(f :c :a) |
| 06:21 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: No method in multimethod 'f' for dispatch value: [:c :a]> |
| 06:21 | Janiczek | nice :) |
| 06:21 | Janiczek | thanks a lot! |
| 07:02 | silasdavis | I think I've found a bug in: https://github.com/clojure/data.priority-map |
| 07:03 | silasdavis | (-> (priority-map-by (fn [[_ x1] [_ x2]] (compare x1 x2))) (assoc :a [:foo 2]) (assoc :b [:bar 2]) (assoc :c [:baz 1])) |
| 07:03 | silasdavis | returns {:c [:baz 1], :b [:foo 2], :a [:foo 2]} |
| 07:03 | silasdavis | that is, when you use a custom comparator it looks like if two values are equal under comparison they are considered to be the same |
| 07:04 | silasdavis | rather than just being sorted as equal |
| 07:05 | silasdavis | I was using a priority map for [path-to-node distance] and I was getting path-to-node overwritten in all key-value pairs with the same distance |
| 07:05 | silasdavis | where can I report this? |
| 07:06 | silasdavis | issues are disabled on that repo |
| 07:06 | Bronsa | silasdavis: https://github.com/clojure/data.priority-map/blob/master/CONTRIBUTING.md |
| 07:08 | silasdavis | ah thanks |
| 07:09 | Bronsa | silasdavis: I'm reading the readme, have you read http://sprunge.us/VXXT this? |
| 07:09 | silasdavis | ah |
| 07:09 | silasdavis | well done |
| 07:10 | silasdavis | and thanks |
| 07:10 | Bronsa | np |
| 07:10 | silasdavis | that's excactly what I'm doing wrong |
| 07:53 | perplexa | hai. is there a way to get the namespace of a function from within the function? |
| 07:54 | perplexa | like (ns mynamespace ...) (defn x[] (resolve mynamespace here)) |
| 07:54 | TEttinger | ,*ns* |
| 07:54 | clojurebot | #<Namespace sandbox> |
| 07:54 | perplexa | that doesn't work |
| 07:55 | perplexa | *ns* is the current namespace, not the absolute namespace of a function ;/ |
| 07:55 | Bronsa | you have to close over the *ns* |
| 07:55 | Bronsa | (let [ns *ns*] (defn x [] ns)) |
| 07:55 | perplexa | i was using *ns* before and it ended up interning functions to the wrong namespace ;p |
| 08:57 | Janiczek | hmm uberjar seems not to pack swing with my seesaw project ... is it normal? (when I run it with `java -jar the.jar`, it's OK and sees Swing, but when I bundle it with Ant AppBundler to an .app, it throws NoClassDefFound for java.awt.Window$Type) |
| 08:57 | Janiczek | (no expert on Java ecosystem) |
| 09:34 | Janiczek | ah, it's probably me (in shell) running java 1.7+ and the system (in the bundled .app) running 1.6 or something. java.awt.Window$Type is from 1.7+ up |
| 09:47 | fowlslegs | ,(.rotateRight (long 8) (int 1)) |
| 09:47 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: No matching method found: rotateRight for class java.lang.Long> |
| 09:47 | fowlslegs | http://docs.oracle.com/javase/8/docs/api/java/lang/Long.html#rotateRight-long-int- |
| 10:00 | Bronsa | fowlslegs: it's a static method |
| 10:00 | Bronsa | ,(Long/rotateRight 8 1) |
| 10:00 | clojurebot | 4 |
| 10:12 | gfredericks | those sorts of things get made static so they can use primitives amirite? |
| 10:13 | Bronsa | gfredericks: probably, yeah |
| 10:30 | cbp | arrdem: should the `add examples' page default to 1.4? |
| 10:31 | cbp | I think it would be more practical to default to the latest no? |
| 10:49 | zeebrah | dae know where this moved (out of contrib) http://richhickey.github.io/clojure-contrib/miglayout-api.html ? |
| 10:51 | fowlslegs | ,(map #(.bitCount (biginteger (- % 30))) (range 30)) |
| 10:51 | clojurebot | (4 3 4 3 3 ...) |
| 10:51 | fowlslegs | ,(apply list (map #(.bitCount (biginteger (- % 30))) (range 30))) |
| 10:51 | clojurebot | (4 3 4 3 3 ...) |
| 10:51 | puredanger | zeebrah: afaik it did not go anywhere |
| 10:51 | puredanger | http://dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go |
| 10:51 | cbp | zeebrah: maybe you can use this https://github.com/scgilardi/artem |
| 10:52 | fowlslegs | ,(.bitCount (biginteger 7)) |
| 10:52 | clojurebot | 3 |
| 10:52 | fowlslegs | ,(.bitCount (biginteger -7)) |
| 10:52 | clojurebot | 2 |
| 10:52 | zeebrah | puredanger: yeah i saw that page just before |
| 10:52 | fowlslegs | Can someone explain what's going on with the java.lang.BigInteger class here? |
| 10:52 | zeebrah | cbp: is that maintained? it seems not |
| 10:53 | cbp | more recently maintained than clojure.contrib.ma |
| 10:53 | fowlslegs | I understand what it means to be in two's complement notation, but it does not specify how many bits it uses as a base. |
| 10:53 | cbp | clojure.contrib.miglayout :-p |
| 10:54 | fowlslegs | This page http://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html doesn't, that is. |
| 10:54 | zeebrah | cbp: it's not the actual miglayout library though, just a coupla useful macros/functions |
| 11:00 | fowlslegs | Ahh, it must represent it in two's complement notation in byte multiples. I can finally write my hamming distance function for comparing two BigInts. |
| 12:02 | PigDude | when you are sharing core.async code between cljs and clj, does your namespace declaration look like this? https://www.refheap.com/87837 |
| 12:02 | PigDude | it seems really ugly |
| 12:03 | PigDude | #+cljs/#+clj everywhere, and the hassle of maintaining two sets of requirements |
| 12:03 | PigDude | *the same set in two places |
| 12:17 | Willis1 | Hi, I'm investigating the use of The Grinder's support for Clojure: |
| 12:17 | Willis1 | http://grinder.sourceforge.net/g3/clojure.html |
| 12:18 | Willis1 | But from what I can tell, there's no way to use lein to pull in additional dependencies |
| 12:18 | Willis1 | because the Grinder invokes the clojure scripts directly |
| 12:18 | Willis1 | Has anybody made any effort to use lein and grinder together? |
| 12:46 | synkte | What is the best way to test a function that creates a new row entry into a sql database? |
| 12:46 | synkte | Is there a lib that could help with that? |
| 12:48 | mdeboard | synkte: http://clojure.github.io/java.jdbc/#clojure.java.jdbc/insert! |
| 12:49 | synkte | mdeboard: So use the ":transaction?" param? |
| 12:50 | mdeboard | synkte: Depends on your particular application |
| 12:50 | mdeboard | but if you're asking, the answer is yes |
| 12:51 | mdeboard | synkte: Well, the default is true, so no :P |
| 12:52 | synkte | mdeboard: So, what would be the best way to test a function that does an insert to a sql database? |
| 12:56 | mdeboard | synkte: Insert, then do a select for that value, then delete it if it iexists |
| 12:56 | mdeboard | synkte: Do you mean like a unit test i.e. application testing or to only insert if there isn't already a record? |
| 12:57 | synkte | mdeboard: unit test |
| 12:57 | mdeboard | synkte: Yeah then the way I said there |
| 12:57 | synkte | mdeboard: Thank you :) |
| 12:58 | mdeboard | no prob |
| 12:58 | mdeboard | I bet amalloy_ has some kind of context manager (`(with-row)`)or something that takes care of that cleanup for you |
| 13:01 | synkte | mdeboard: That would be awesome |
| 13:03 | mdeboard | until then though yeah you'd just have to clean it up yourseff |
| 13:04 | mdeboard | synkte: There is this http://clojure.github.io/java.jdbc/#clojure.java.jdbc/with-db-transaction that you could then roll back once done but you'd have to do some additional setup to ensure constraints were not deferred |
| 13:06 | mdeboard | 13:01 <mdeboard> until then though yeah you'd just have to clean it up yourseff |
| 13:06 | mdeboard | 13:02 <mdeboard> synkte: There is this http://clojure.github.io/java.jdbc/#clojure.java.jdbc/with-db-transaction that you could then roll back once done but you'd have to do some additional setup to ensure constraints were not deferred |
| 13:06 | mdeboard | otherwise you're not actually testing the insert |
| 13:06 | mdeboard | just something kinda like it |
| 13:11 | dbasch | mdeboard: if I had a unit test for a db I would create a dummy table, insert, and then delete the table |
| 13:11 | Janiczek | are immutable bags (multisets) available in clojurescript, or do I have to somehow include mori-bag? (I'm in browser env, not node) |
| 13:15 | dbasch | Janiczek: clojure.core doesn't have multisets but there are some libraries around, it shouldn't be hard to adapt one of those for cljs |
| 13:15 | Janiczek | yeah, I've found https://github.com/achim/multiset which seams reasonably easy to port |
| 13:16 | Janiczek | only protocols and clojure.algo (which I'm not so sure about but maybe it can be bypassed) |
| 13:17 | dbasch | Janiczek: as an alternative, you could have a map of keys to counts |
| 13:17 | dbasch | it would be a bit clunkier but at least you wouldn't need an external lib |
| 13:18 | dbasch | of course it might be very inefficient if most of your items appear once |
| 13:18 | dave-7 | hey, when using om/root to render a site, you pass it a component, an atom and a map. Should the component be re-rendered if I swap! the atom at some point? The basic tutorial seems to indicate so, but I'm not having any luck. Does the atom count as "attached" to a root if you call (om/root some-comp some-atom {:target dom-node})? |
| 13:47 | Klaufir | How can I process output from tagsoup ? I have something like this: |
| 13:47 | Klaufir | [:html {} [:head {} [:title {} "asd"]] [:body {} [:div {:class "dc"} "text"]]] |
| 13:48 | danielszmulewicz | I've been using 'length instead of 'count on sequences, and I could swear it was working all the same. Now I get a runtime error. What gives? |
| 13:48 | amalloy | mdeboard: nope, i don't. it also seems a little wonky: don't you want to use the db's transaction mechanism if you're inserting stuff you never want to appear there? |
| 13:48 | tolitius | is there a way to require/use from within a function: e.g. in a local scope? https://www.refheap.com/87842 |
| 13:49 | amalloy | danielszmulewicz: length has never in a million years worked |
| 13:49 | danielszmulewicz | amalloy: I'm hallucinating then. |
| 13:49 | amalloy | tolitius: no |
| 13:49 | dbasch | Klaufir: what do you mean by process? What do you want to get out of that? |
| 13:49 | ToxicFrog | danielszmulewicz: .length might have worked, if you were using it on Java objects? |
| 13:49 | mdeboard | amalloy: You do, like I said though it requires a little more insight into how constraints are handled inside a transaction, i.e. initially immediate/deferred, not deferred, etc. |
| 13:50 | amalloy | ToxicFrog: only on arrays or strings. collections have .size |
| 13:50 | mdeboard | that just seemed like a bridge too far to cover w/ that guy's question |
| 13:50 | danielszmulewicz | ToxicFrog: No. Just 'length on clojure sequences. I'm utterly confused. |
| 13:50 | amalloy | danielszmulewicz: maybe you were using clojure 1.9? the rest of us are still on 1.6, but who knows what future versions will bring |
| 13:51 | Klaufir | dbasch: I am looking for the language features to process nestes structures like this. Say I want to get the content for :html/:head/:title |
| 13:51 | dbasch | Klaufir: look into things like get-in, or clojure.walk |
| 13:51 | danielszmulewicz | amalloy: Hehe, that must be it. I'm with a future version of Clojure. |
| 13:51 | danielszmulewicz | (inc amalloy) |
| 13:51 | lazybot | ⇒ 136 |
| 13:51 | Klaufir | dbasch: thanks |
| 13:52 | tolitius | amalloy: thx. I have to aot a file, but only need some ns at runtime (e.g. in -main), otherwise they have macros that expand into a "never ending ..", so it would not aot compile unless it is in main. is there a known way to load/see/make visible from within a function instead? |
| 13:54 | amalloy | whaaaaa? you've written a macro that doesn't compile, so you want it at runtime? i think you must be confused about something; do you have more specific code that doesn't work? |
| 13:54 | amalloy | more likely, i think, is that you have some def at the top level of a namespace that performs side effects, such as connecting to a database; the solution is to not have side effects at compile-time, but instead to def a delay or a function that is called at runtime |
| 13:58 | tolitius | amalloy: yes, you are right, but it is not a def, it is a macro, that, when expands (which happens during compilation), starts a scheduler, hence will work on demand, but not if aot'ed. I am looking for a way to isolate this macro expansion in -main. (yes, I know that macro should be rewritten, but that is a bit more difficult at the moment [different project, different existing dependencies, etc.]) |
| 14:00 | hiredman | tolitius: if the macro performs side effects at macro expansion time there is no way to isolate that, code is macro expanded before it is compiled and then run |
| 14:00 | hiredman | aot compilation saves the byte code after compiling so you can run it later, but the macro expand has already happened |
| 14:03 | tolitius | hiredman: I understand that, what I am looking for is a way to only ever "require"/"use"/"load" the namespace where this macro lives on demand. e.g. compile the file that in main has "… and 'import' this namespace as you're running (e.g. runtime)" |
| 14:04 | tolitius | hiredman: avoiding compiling the namespace with this macro ahead of time |
| 14:05 | TimMc | tolitius: It sounds like your desire to do this with a macro is distorting your entire program. |
| 14:05 | danielszmulewicz | amalloy: Mystery solved. I was using incanter which advertises a :use namespace usage. This should be outlawed. |
| 14:06 | technomancy | ~guards |
| 14:06 | clojurebot | SEIZE HIM! |
| 14:06 | amalloy | tolitius: i don't know what this macro is, but it sounds like a scourge on this planet |
| 14:07 | tolitius | TimMc: it is more of a curiosity now, since I see why it would be useful to do, and now I just want to get to the bottom of whether it is possible (I agree that macro needs to be changed) |
| 14:08 | tolitius | TimMc: (to have a better control of what gets aot'ed) |
| 14:09 | tolitius | TimMc: similar to http://dev.clojure.org/jira/browse/CLJ-322 |
| 14:12 | Demosthenes_ | (doc +) |
| 14:12 | clojurebot | "([] [x] [x y] [x y & more]); Returns the sum of nums. (+) returns 0. Does not auto-promote longs, will throw on overflow. See also: +'" |
| 14:13 | Demosthenes_ | (doc apply) |
| 14:13 | clojurebot | "([f args] [f x args] [f x y args] [f x y z args] [f a b c d ...]); Applies fn f to the argument list formed by prepending intervening arguments to args." |
| 14:19 | stuartsierra | All, CLJ-322, old friend. It's been a while. We were so young back then. Where did all the time go? |
| 14:46 | danielszmulewicz | I assumed that any library that has 'core in it (like core.matrix) ships with Clojure. Wrong again. |
| 14:47 | amalloy | danielszmulewicz: most don't |
| 14:47 | amalloy | core.* is more like "libraries that might one day be part of clojure" |
| 14:47 | amalloy | "...and which also live at github.com/clojure/*" |
| 14:48 | danielszmulewicz | amalloy: They're halfway there :-) |
| 14:48 | danielszmulewicz | (+ amalloy) |
| 14:48 | TimMc | Huh, the phrase "ships with Clojure" is ambiguous -- at first I read it as "includes Clojure as a dependency", not "is included in the Clojure jar". |
| 14:48 | danielszmulewicz | (inc amalloy) |
| 14:48 | lazybot | ⇒ 137 |
| 14:48 | TimMc | $karma TimMc |
| 14:48 | lazybot | TimMc has karma 60. |
| 14:48 | TimMc | Man, I've got some catching up to do. |
| 14:49 | danielszmulewicz | TimMc: Don't seat it. amalloy is a bot and everybody knows that. |
| 14:49 | danielszmulewicz | *sweat* |
| 14:50 | arrdem | no mere human could contribute so much to the channel :P |
| 14:50 | Klaufir | Whats the point of 'compare-and-set!' ? |
| 14:51 | amalloy | (inc TimMc) ; to get you started |
| 14:51 | lazybot | ⇒ 61 |
| 14:51 | {blake} | Aw, a pity inc! |
| 14:51 | Janiczek | : |
| 14:51 | Janiczek | :D |
| 14:51 | amalloy | Klaufir: mostly to implement swap! with. i think i saw one case where it made sense to use compare-and-set! over swap!, but mostly you can ignore it |
| 14:51 | TimMc | (dec TimMc) ;; I don't need your pity! |
| 14:51 | lazybot | You can't adjust your own karma. |
| 14:51 | TimMc | ha |
| 14:51 | amalloy | TimMc: largesse, not pity |
| 14:51 | Klaufir | amalloy: i see, thanks |
| 14:52 | Bronsa | amalloy: swap! is not implemented in terms of compare-and-swap! though |
| 14:52 | Bronsa | compare-and-set!* |
| 14:52 | amalloy | well, it could have been |
| 14:52 | amalloy | instead, it's implemented in java with an equivalent thingy, compareAndSet |
| 14:53 | Bronsa | amalloy: I don't think swap can be implemetned in terms of compare-and-set |
| 14:53 | amalloy | really? |
| 14:53 | TimMc | Other way around, right? |
| 14:53 | hiredman | there are CAS based algorithms where you want better control over the retries |
| 14:53 | puredanger | pretty much everything can be implemented in terms of CAS |
| 14:54 | hiredman | Bronsa: what makes you say that? |
| 14:54 | amalloy | (defn swap!' [a f] (let [old @a, new (f old)] (if (compare-and-set! a old new) new, (recur a f)))) |
| 14:54 | TimMc | Or... thyey can be implemented in terms of each other. |
| 14:54 | hiredman | no |
| 14:54 | Bronsa | amalloy: hiredman uhm I'm definitely wrong |
| 14:54 | hiredman | swap! retries until the CAS succeeds |
| 14:55 | amalloy | TimMc: cas is more primitive. you can't really use swap to implementi t |
| 14:55 | hiredman | comare-and-swap! tries once and returns a boolean |
| 14:55 | TimMc | I mean at the CLJ layer, if you had one of swap! or compare-and-set! you could write the other without interop. |
| 14:56 | amalloy | i don't think that's true |
| 14:56 | hiredman | if you look at the literature for high performance queues, you often want to do a cas, and if the cas fails do some exponential back off, or switch to some some other strategy, which swap! doesn't let you do |
| 14:57 | TimMc | amalloy: It might require a second atom. :-P |
| 14:57 | amalloy | yes, then you could do it, but that's cheating |
| 14:57 | TimMc | Well... |
| 14:58 | amalloy | actually it's not entirely clear to me how you could do it with a second atom either. coordinating it is non-obvious, and atoms are terrible at coordination |
| 14:59 | amalloy | if you want a solution that works under concurrency |
| 15:02 | TimMc | amalloy: It's stupid, but I think it works: https://www.refheap.com/87845 |
| 15:03 | amalloy | yeah, i was just in the middle of writing that myself. i was thinking it doesn't work because of retries, but of course you're resetting it each time you try |
| 15:03 | amalloy | so it's theoretically okay. but on the other hand it's not guaranteed to ever return, which is a problem that compare-and-set! is not supposed to have |
| 15:04 | TimMc | Yeah, that's the tricky bit. :-P |
| 15:06 | TimMc | Ha, interesting -- you can edit a refheap paste to be private, but not back again. |
| 15:06 | TimMc | which is to say it is now at https://www.refheap.com/b08ad02d8bd667abcf364ac65 |
| 15:07 | tbaldrid_ | amalloy: to the original question, I've used compare-and-set! when I want to return the old value, not the new one. |
| 15:07 | tbaldrid_ | amalloy: acutally, every time I've wanted a return value from swap! it's always been the old one, and then I have to write swap-old! |
| 15:07 | TimMc | tbaldrid_: Might I suggest https://github.com/timmc/handy/blob/master/src/org/timmc/handy.clj#L129 |
| 15:08 | amalloy | tbaldridge: really, every time? i find the old one useful about as often as the new one |
| 15:08 | TimMc | (split-atom! a identity f) |
| 15:09 | puredanger | feel free to vote on http://dev.clojure.org/jira/browse/CLJ-1454 re swap-old! |
| 15:09 | tbaldridge | puredanger: I think I did ;-) |
| 15:09 | puredanger | I know *you* did :) |
| 15:09 | tbaldridge | rofl |
| 15:09 | amalloy | eg, to reimplement memoize: (defn memoize [f] (let [a (atom {}] (fn [& args] (-> a (swap! update-in [args] (fn [old] (or old (delay (apply f args))))) (deref))))) |
| 15:10 | amalloy | tbaldridge: your comment may be the only time anyone has ever used nfirst |
| 15:12 | TimMc | I mostly use my fn for (split-atom! a first next) |
| 15:12 | seangrove | clojurescript: "extend is not currently implemented" |
| 15:12 | seangrove | >.< |
| 15:14 | tbaldridge | seangrove: seems like that would be a bit "fun" to implement in a AOT compiled language like ClojureScript |
| 15:15 | tbaldridge | seeing as it just takes a hashmap of function names to functions. |
| 15:34 | seangrove | Uhg, clojure.walk doesn't support records. |
| 15:35 | stuartsierra | seangrove: In 1.6 it does |
| 15:36 | seangrove | stuartsierra: Hrm, any idea how that translates to cljs? |
| 15:36 | stuartsierra | seangrove: no idea |
| 15:36 | stuartsierra | Does cljs even have clojure.walk? |
| 15:36 | seangrove | https://github.com/clojure/clojurescript/blob/master/src/cljs/clojure/walk.cljs |
| 15:36 | tbaldridge | seangrove: if you're using the latest CLJS that means port it yourself and send a patch to dnolen_ ;-) |
| 15:37 | seangrove | I suppose I could take a look at it |
| 15:37 | stuartsierra | It's easy |
| 15:37 | stuartsierra | https://github.com/clojure/clojure/commit/2224dbad5534ff23d3653b07d9dc0a60ba076dd7 |
| 15:38 | seangrove | stuartsierra tbaldridge: Yeah, haven't contributed anything to cljs recently, would be good to bring cljs' clojure.walk up to date |
| 15:45 | dnolen_ | seangrove: seems pretty straightforward to me, we have the IRecord marker protocol |
| 15:45 | seangrove | dnolen_: Yeah, hacking on it locally |
| 15:45 | seangrove | dnolen_: Should I use (satisfies? IRecord form) rather than (instance? IRecord form) ? |
| 15:46 | bbloom | seangrove: yes |
| 15:48 | dnolen_ | seangrove: you should not consider instance? a thing :) |
| 15:48 | dnolen_ | it's there internally for perf reasons |
| 15:48 | stuartsierra | dnolen_: Are you referring specifically to `instance?` in ClojureScript? |
| 15:48 | bbloom | it's also anti-modular to depend on concrete types in general |
| 15:49 | dnolen_ | stuartsierra: yes |
| 15:49 | dnolen_ | oh oops sorry |
| 15:49 | dnolen_ | not enough coffee today |
| 15:49 | dnolen_ | instance? is fine |
| 15:50 | dnolen_ | was thinking about implements? |
| 15:50 | dnolen_ | seangrove: instance? IRecord won't work :) |
| 15:52 | seangrove | dnolen_: Ok, satisfies? with stuartsierra's change looks like it works. Will check it out a bit more and submit a patch if so |
| 15:54 | dbasch | btw |
| 15:54 | dbasch | ,(satisfies? 1 1) |
| 15:54 | clojurebot | #<NullPointerException java.lang.NullPointerException> |
| 15:54 | dbasch | ^ could be better |
| 15:54 | stuartsierra | dbasch: patches welcome |
| 15:55 | dbasch | stuartsierra: will look into it |
| 15:58 | stuartsierra | dbasch: Ah yes, looks like http://dev.clojure.org/jira/browse/CLJ-1107 again. |
| 15:58 | dbasch | ,(instance? nil nil) ;; stuartsierra is there a reason this behavior is desirable? |
| 15:58 | clojurebot | #<NullPointerException java.lang.NullPointerException> |
| 15:58 | dbasch | ah, ok |
| 16:00 | puredanger | dbasch: no, but it's a "breaking" change |
| 16:01 | puredanger | (although the broken things are already broken, imo) |
| 16:01 | dbasch | puredanger: oh well |
| 16:02 | stuartsierra | (instance? nil nil) throwing NPE does make sense: that's a bytecode op on the JVM. |
| 16:03 | stuartsierra | null has no type, therefore it is an error to ask for the type of null. |
| 16:04 | dbasch | stuartsierra: it does make sense, but does it make more sense than returning false-y? |
| 16:05 | stuartsierra | maybe |
| 16:05 | sveri | Hi, I am trying to use sente and I can establish a ws connection from client to server, however, when I look at the connected uids atom I only see this: {:ws #{nil}, :ajax #{}, :any #{nil}} and it looks like the connection is ok, but the uid is "nil" which is weird I guess, this is my server and client side code: http://pastebin.com/aahbRDQx |
| 16:05 | dbasch | the reason I brought it up is because it's why (statisfies? 1 1) throws the NPE according to the (old) sources I'm looking at |
| 16:07 | dbasch | ah, it's not that |
| 16:08 | dbasch | I think it's this line https://github.com/clojure/clojure/blob/ef2e762e21a817305314ed10bc33505bed6874a5/src/clj/clojure/core_deftype.clj#L497 |
| 16:23 | tbaldridge | dbasch: yeah, the first argument is supposed to be a protocol. You're handing it a integer, thus by the laws of Clojure anything can happen |
| 16:24 | dbasch | tbaldridge: do you think it would be worth checking to return a more meaningful error instead of an NPE? |
| 16:24 | arrdem | {:pre [(protocol? ...)]} |
| 16:24 | tbaldridge | dbasch: welcome to clojure..... |
| 16:25 | dbasch | (inc arrdem) |
| 16:25 | lazybot | ⇒ 32 |
| 16:25 | tbaldridge | dbasch: that requires a check at the invocation of every call to satisfies. Good luck getting that patch approved. |
| 16:26 | stuartsierra | I think it's doable as a fall-through case without adding an additional check at the beginning. |
| 16:28 | amalloy | stuartsierra: maybe just catch the exception that is actually produced and wrap it in something nicer? iirc a try/catch costs basically nothing if no exception happens, right? |
| 16:29 | stuartsierra | amalloy: probably not needed |
| 16:30 | arrdem | amalloy: couldn't that obscure other errors? |
| 16:30 | amalloy | arrdem: in satisfies? what other error could there be? |
| 16:31 | amalloy | true, false, what-the-hell-is-this-i-wanted-a-protocol are the only three reasonable outcomes |
| 16:31 | arrdem | heh |
| 16:31 | arrdem | yeah looking at this I don't see another way to make it explode right off |
| 16:31 | dbasch | I just hate NPEs |
| 16:32 | arrdem | tbaldridge: I did ultimately manage to rebind ns... had to write my own alter-var-root based with-macro-redefs because with-redefs kills the macro metadata and breaks everything |
| 16:32 | amalloy | googled around a bit, and it looks like try/catch is free if nothing is thrown, except that it adds bytecode, and can prevent some optimizations that assume linear control flow |
| 16:32 | {blake} | Is there are more succinct way of saying "if (nil? %1) (list %2) (cons %2 %1))"? |
| 16:33 | tbaldridge | arrdem: lol yeah, I forgot there's a macro flag on vars |
| 16:33 | amalloy | {blake}: #(cons %2 %1) |
| 16:33 | amalloy | the if is pointless |
| 16:33 | arrdem | tbaldridge: the fun bit is that using with-redefs on a macro flagged var permanently kills the macro flag, which makes code reloading totally horked :D |
| 16:34 | tbaldridge | arrdem: I bet you could do some reflection black magic.... |
| 16:34 | {blake} | amalloy, Thanks. Thought I tried that but I must've gotten it wrong. |
| 16:34 | {blake} | (inc amalloy) |
| 16:34 | lazybot | ⇒ 138 |
| 16:34 | tbaldridge | arrdem: http://stackoverflow.com/questions/1555658/is-it-possible-in-java-to-access-private-fields-via-reflection |
| 16:34 | {blake} | Sorry, TimMc |
| 16:35 | arrdem | tbaldridge: sure, but why bother. this works a treat. https://www.refheap.com/87848 |
| 16:35 | dbasch | OTOH if someone is using protocols (which is not a beginner feature) perhaps an NPE is not that horrible |
| 16:40 | TimMc | amalloy: I recently learned that using a finally clause causes code to be duplicated for each catch clause. It's interesting that they chose that instead of using more complicated gotos. |
| 16:41 | TimMc | I'm now imagining some absolutely horrifying situation where a cosmic ray alters the in-memory code for one copy but not another and is even more impossible to debug. :-P |
| 16:41 | puredanger | there have been a couple strategies used for try/catch/finally bytecode over the years |
| 16:41 | puredanger | I think it was jdk 6 where it last changed significantly |
| 16:42 | tbaldridge | I know try is mostly free in Java, but is it in clojure? Try bodies are anonymous functions last I checked |
| 16:43 | Jaood | is there a way to clear/clean the user ns in the repl without restarting it? |
| 16:44 | amalloy | i don't think that's true, tbaldridge |
| 16:44 | puredanger | tbaldridge: handwave handwave JIT JIT handwave |
| 16:44 | amalloy | the body of a try is parsed as a BodyExpr, which emits as just a bunch of statements |
| 16:44 | Bronsa | https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L2161-L2162 |
| 16:45 | dbasch | Jaood: you mean something like this? http://stackoverflow.com/questions/3636364/can-i-clean-the-repl |
| 16:45 | amalloy | dangit! snuck that in there, apparently. good eyes, Bronsa |
| 16:46 | tbaldridge | puredanger: it'd be a interesting thing to try sometime, my repl experiments say no, but yes, jit stuff |
| 16:47 | amalloy | can someone explain to me what the various contexts in the compiler mean? i've never really been able to work that one out. like i've seen EXPRESSION and EVAL before, but don't remember seeing RETURN; and anyway i don't know what the others really mean |
| 16:47 | Bronsa | amalloy: return means the expression is in return position |
| 16:47 | Bronsa | as opposed to statement |
| 16:47 | Bronsa | (do 1 2 3) |
| 16:48 | Bronsa | 1 2 statement, 3 return |
| 16:48 | Jaood | dbasch: yeah, thanks |
| 16:48 | Bronsa | amalloy: expression is non return, non statement |
| 16:48 | Bronsa | amalloy: meaning the expression value is used but it's not in return position. if it's a statement the return value can be discarded |
| 16:49 | Bronsa | amalloy: eval is this weird context that's somewhat like expression but used when the code is loaded via eval (usually in the repl) |
| 16:50 | amalloy | Bronsa: when is an expression's value used but not in return position? |
| 16:50 | Bronsa | amalloy: in a binding for example |
| 16:50 | Bronsa | (let [a 1] 2) |
| 16:50 | Bronsa | 1 is an expr |
| 16:50 | Bronsa | 2 is return |
| 16:52 | amalloy | because it's...returning from the let expr? but that's not necessarily returning from the whole function, right? like, in (let [x (let [a 1] 2)] 3), 1 and 2 are both used but not returned |
| 16:52 | amalloy | but 2 is still in RETURN position because it's being returned from the letexpr, whereas there's no expr that 1 is returned from |
| 16:52 | amalloy | (aside from the ConstExpr that emits it?) |
| 16:54 | Bronsa | amalloy: so, wherever you can put a recur, that's a return, if the expression is in do and is not the last expression in that do (do [this]* x), it's a statement, otherwise it's either expression or eval |
| 16:55 | Bronsa | in your example 2 has a return ctx, yes |
| 16:56 | Bronsa | amalloy: no actually it's an expr. it has to be in a return position of a fn or a loop to be a return |
| 16:57 | amalloy | i see. so return is like "this would be in tail position if this were the top-level expr of a loop". so the 2 could be in return context, except that it's being parsed as part of a try that's in eval context? |
| 16:57 | amalloy | er, part of a let-binding |
| 16:57 | bracki | How do I turn a java.io.Outputstream into a ring {:body stream} response? |
| 16:58 | Bronsa | amalloy: that should be correct, yes |
| 16:59 | technomancy | bracki: you can copy it to a ByteArray and then make a ByteArrayInputStream |
| 16:59 | Bronsa | amalloy: the last expression in a "block" (let/letfn/..) takes the context of the "block" |
| 17:00 | Bronsa | so if the let is in return position (tail-call of a fn/loop/method body) then the expression in tail position in the let body will have return ctx |
| 17:02 | Bronsa | amalloy: I suck at explaining it but it's really easy to understand if you play a bit with it, analyze some expressions with t.a.j and look at their (-> ast :env :context) and it'll be clear |
| 17:03 | amalloy | yeah, i think i get it, Bronsa |
| 17:04 | amalloy | technomancy: gross |
| 17:04 | amalloy | use a pipe; there's one helpfully included in compojure |
| 17:05 | amalloy | or maybe ring. i'm never quite sure |
| 17:05 | technomancy | sure, provided you have control over that |
| 17:05 | bracki | technomancy: Like here http://data-sorcery.org/2009/11/29/incanter-webapp/? |
| 17:06 | atyz | Hey all... what would happen if you spawned a lot of futures (blocking calls lasting ~1 second each) then enver defererenced them |
| 17:06 | atyz | *never |
| 17:06 | amalloy | technomancy: huh? control over what? |
| 17:06 | turbofail | atyz: a future runs whether you dereference it or not |
| 17:07 | bracki | There's this https://groups.google.com/forum/#!topic/clojure/BZxYCQQJtV8 and this https://github.com/ring-clojure/ring/blob/bc4ddda43e68cc2117f73306d936555ac870239b/ring-core/src/ring/util/io.clj#L11 |
| 17:07 | turbofail | atyz: there's a limited thread pool for running them |
| 17:07 | bracki | I don't understand the signature of piped-input-stram |
| 17:07 | amalloy | bracki: https://github.com/ring-clojure/ring/blob/bc4ddda43e68cc2117f73306d936555ac870239b/ring-core/src/ring/util/io.clj#L11 |
| 17:07 | puredanger | turbofail: it's not limited |
| 17:08 | amalloy | you can't really convert an output stream to an input stream, bracki. it doesn't make sense, because neither of those actually stores data |
| 17:08 | atyz | turbofail: I think futures are pulling from an unbound pool |
| 17:08 | amalloy | if you have an output stream, and you want writes to it to be sent out over ring, that's what piped-input-stream is for |
| 17:09 | atyz | Basically after a while my cpu usage hits 100% and never comes down. I think this could be due to me abusing futures, is this at all possible? |
| 17:09 | bracki | But how? |
| 17:09 | dbasch | bracki: what is your output stream? where does it come from? |
| 17:09 | amalloy | but you still have to actually do those writes, so the idea is (let [response (piped-input-stream (fn [out] (.write out "hello!")))] {:status 200 :body response}) |
| 17:10 | bracki | I want to use http://people.apache.org/~thejas/thrift-0.9/javadoc/org/apache/thrift/transport/TIOStreamTransport.html |
| 17:10 | bracki | So I'm not in control of the writing to the outputstream... |
| 17:10 | turbofail | oh hm. wonder why i thought it was bounded |
| 17:10 | puredanger | atyz: do a thread dump - who's doing the work? |
| 17:11 | puredanger | turbofail: the agent send pool is bounded |
| 17:11 | bracki | So I guess what technomancy said applies. Hard to wrap that thing in a function... |
| 17:12 | puredanger | turbofail: the send-off and future pool (same pool) is a cached thread pool |
| 17:12 | atyz | puredanger: I did a thread dump (https://www.refheap.com/87785) but it looks similar to a new fresh healthy machine and the thread counts weren't all that different |
| 17:12 | turbofail | puredanger: ah, the send-pool must have been what i was thinking of |
| 17:13 | puredanger | atyz: none of your threads are doing anything. I don't believe your cpu usage is coming from this process :) |
| 17:13 | atyz | puredanger: that is really sad news. could you think of anything else that could cause this? |
| 17:13 | dbasch | bracki: it's pretty easy to wrap that in a function, but what do you mean you're not in control of the writing to the output stream? |
| 17:13 | puredanger | why do you think it's this process? |
| 17:14 | atyz | even once the machine is pulled from the LB it continues to stay at 100% utilization |
| 17:14 | dbasch | bracki: I mean, you're writing thrift to an outputstream that you gave that class |
| 17:14 | atyz | puredanger: my thinking is that there were a bunch of theads getting backed up (they are blocking calls) and for some reason not being killed off |
| 17:14 | TimMc | atyz: Good question -- you *have* confirmed that it's the JVM that's eating the CPU? |
| 17:15 | puredanger | atyz: there are a few threads reading/waiting on sockets - it's possible one of those is reading vast quantities of stuff in a tight loop, but I'd still guess that's IO bound, not CPU bound |
| 17:15 | puredanger | atyz: blocking threads won't show up as cpu utilization |
| 17:15 | atyz | TimMc: I have confirmed that it is the JVM eating the cpu |
| 17:15 | TimMc | OK. :-) |
| 17:16 | bracki | dbasch: I'm not doing the write but some Java class using this https://github.com/apache/thrift/blob/38b453be5a015b7aaefcd91b4e261e53e0e211c2/lib/java/src/org/apache/thrift/transport/TIOStreamTransport.java#L140 |
| 17:16 | dbasch | bracki: ok, but where is it writing to? |
| 17:16 | bracki | Basically I have no control over when (.write stream) is being called |
| 17:16 | bracki | in .write |
| 17:17 | atyz | puredanger: if that were the case I would expect the cpu utilization to come down after some time? |
| 17:17 | puredanger | atyz: you could connect with jvisualvm or something like that - it can show you what threads are doing |
| 17:17 | atyz | Generally the amount of data would be a couple kb at most |
| 17:17 | dbasch | bracki: I got that, but what is the output stream? |
| 17:17 | atyz | (thats even a stretch) |
| 17:18 | amalloy | atyz: i'm with puredanger, your jvm isn't doing anything at all. the only way it could be burning through cpu would be like garbage collection |
| 17:18 | bracki | dbasch: Something I'm passing in here https://github.com/apache/thrift/blob/56a648d0ffc370123c4f1047b72d0d80080a1d9b/lib/java/src/org/apache/thrift/TBaseProcessor.java#L26 |
| 17:19 | atyz | amalloy: if it were garbage collection, how would I confirm that? |
| 17:19 | puredanger | atyz: generally I find if my system is violating my assumptions then one of my assumptions is probably wrong :) |
| 17:19 | atyz | And why would it max my cpu indefinitely |
| 17:19 | atyz | puredanger: I'm sure that I'm wrong in many ways here. Just confused and grasping at straws |
| 17:19 | puredanger | atyz: you would see the GC threads in the thread dump. jvisualvm / jconsole can also show you gc activity |
| 17:20 | amalloy | puredanger: really? i don't recall seeing a gc thread in that list before, like ever |
| 17:21 | puredanger | amalloy: maybe I'm having flashbacks to an earlier time :) |
| 17:21 | dbasch | bracki: I guess my question is: you're writing to some place. What is that place? The network? A file? A Byte array? |
| 17:21 | amalloy | puredanger: i could be wrong. i use yourkit much more than jstack, and while its thread dumps look just like these it's possible it's filtering out some threads i guess |
| 17:22 | atyz | OK so just to dispell my theory completely, having many calls spawned by futures would not exhibit the behavior i'm seeing here? |
| 17:22 | bracki | dbasch: I guess a bytearray |
| 17:22 | puredanger | atyz: I don't see anything in this stack that makes me think it's related to futures. |
| 17:23 | puredanger | atyz: I don't even see anything using cpu |
| 17:23 | atyz | puredanger: is it possible thats because I didn't run it for more than a second or two? |
| 17:23 | danielsz` | I want to split a sequence of variable length in three parts, with the last part having the possible remainder. Think columns in a table. What would be the idiomatic way to achieve this? |
| 17:23 | amalloy | three equal parts, with leftovers appearing in the third? |
| 17:24 | danielsz` | amalloy: yes |
| 17:24 | dbasch | bracki: then do exactly what technomancy said: (.toByteArray os) and then create a ByteArrayInputStream from that |
| 17:25 | amalloy | https://github.com/flatland/useful/blob/develop/src/flatland/useful/seq.clj#L54 does roughly that, except it looks like the excess goes into the first few rather than the last one |
| 17:25 | puredanger | atyz: I don't think I understand what you're doing enough to answer that. |
| 17:27 | dbasch | danielsz`: you can use partition-all and then concatenate the last two things |
| 17:27 | danielsz` | amalloy: Here's my overkill solution: I partition my sequence, put it in matrix, and take the columns. I figured there must be a simpler way (with built-in fns). But it's not that straightforward as I had thought. At least I can't figure it out, |
| 17:28 | danielsz` | alas. |
| 17:28 | dbasch | danielsz`: e.g. if you have 20 columns you'll end up with 6-6-6-2 |
| 17:28 | atyz | puredanger: thats fair, I'll take a look into the garbage collection |
| 17:28 | dbasch | danielsz`: concatenate the last two and you'll have 6-6-8 |
| 17:28 | puredanger | just turn on -verbose:gc |
| 17:29 | atyz | Can you think of anything in particular I shoudl look out for? |
| 17:29 | danielsz` | dbasch: interesting... |
| 17:29 | hiredman | the threads are all blocked in that dump, and if you take another dump they will likelly show as blocked again, so the question is, are they actually blocked, or are they flipping back and forth between blocked (waiting on some thing from a queue) and running, the high cpu usage would seem to indicate the switching back and forth, what kind of logging do you have? |
| 17:30 | atyz | hiredman: mostly just request/response logging |
| 17:30 | atyz | Nothing actually looking at the jvm or its processes |
| 17:31 | hiredman | are all the threads doing stuff with datomic? |
| 17:31 | puredanger | datomic itself has a lot of logging you can turn on, no idea if that would help here |
| 17:32 | atyz | hiredman: I don't think they would be |
| 17:32 | atyz | I'm sshing into a heatlthy machine to see what the thread dump looks like |
| 17:32 | amalloy | that's a cute way to do it, dbasch |
| 17:33 | hiredman | if datomic reads data in some kind of single threaded fashion, so all your threads are communicating with the datomic io thread via queues you might see something like this, but that is a stretch |
| 17:35 | atyz | https://www.refheap.com/87850 |
| 17:36 | atyz | hiredman: on an inactive machine, they are blocked as well |
| 17:37 | puredanger | atyz: when you say you just run it for a second or two, do you mean you start the jvm, see 100% cpu, then kill it? if so, what happens if you let it run? |
| 17:38 | atyz | puredanger: Sorry, i meant to say I killed the thread-dump prematurely |
| 17:38 | puredanger | well don't do that :) |
| 17:38 | arohner | what is the preferred logging lib to use w/ tools.logging? |
| 17:38 | puredanger | arohner: prob log4j or slf4j over log4j |
| 17:38 | arohner | thanks |
| 17:39 | atyz | Before I killed the threaddump. I started teh machine, it was put into the LB. It was used for 2 hours, I pulled it out of the LB (when it was at 100% utilization) and it stayed at 100% utilization for the next 6 hours. At which point it I killed it |
| 17:39 | atyz | I currently don't have any machines at 100% utilization because we just did a deploy and there is very little usage |
| 17:40 | puredanger | so you need a full thread dump when it's at 100% utilization. otherwise, you can't know what's actually using cpu at that time |
| 17:41 | atyz | But on monday I am very certain that there will be a few at 100% |
| 17:43 | atyz | puredanger: is there something I should be looking at in the thread-dump that woudl indicate that its the thread that would be using my cpu? |
| 17:43 | puredanger | atyz: it will be RUNNING or RUNNABLE (can't remember which) |
| 17:44 | atyz | So if the thread-dump doesn't say either ofthose - the cpu usage is not from any of those threads |
| 17:44 | atyz | And it would be the GC, possibly? |
| 17:46 | puredanger | well, it's not the BLOCKED threads. you had a few in IN_NATIVE which could theoretically be doing something but are usually IO waiting. could be GC. using gc logging should make that obvious or just connect with one of the jvm tools and see where the pools are. |
| 17:48 | atyz | Ok, I'll give it a look when I have another machine thats stuck at 100% utilization. thank you puredanger amalloy and hiredman |
| 17:49 | puredanger | happy hunting! :) |
| 17:50 | atyz | haha, I wouldn't say happy. I hate it when computers make me feel dumb :P |
| 17:50 | TimMc | atyz: Is it throughly enough wedged that you can't attach a liverepl? |
| 17:50 | cbp | / |
| 17:51 | atyz | TimMc: I haven't tried that. they are deployed as jars |
| 17:52 | atyz | And don't have access to the box in that way. |
| 17:52 | atyz | That said, despite being at 100% it still seems fairly responsive |
| 17:53 | rasmusto_ | is there something special I have to do to get leiningen to extract/use native dependencies? |
| 17:54 | technomancy | rasmusto_: if the native deps have been packaged for use with lein, there's nothing to do |
| 17:55 | rasmusto_ | technomancy: not sure if they have. Trying to use lwjgl-platform-2.8.4-natives-windows.jar |
| 17:55 | technomancy | unlikely then |
| 17:55 | technomancy | unfortunately the docs for that are pretty much crap |
| 17:55 | technomancy | https://github.com/technomancy/leiningen/issues/1385 |
| 17:56 | TimMc | atyz: liverepl attaches to a running JVM whether it has Clojure in it or not. (Unfortunately, it leaks a classloader each time, so you don't want to do it a lot.) |
| 17:57 | technomancy | protip: don't think of it as crap documentation, think of it as a pull request opportunity |
| 17:58 | rasmusto_ | technomancy: if I add an explicit dep for [org.lwjgl.lwjgl/lwjgl-platform "2.8.4" :classifier "natives-windows"] it'll pull the jar down, I guess I can see about extracting it somehow |
| 17:59 | aperiodic | last time I made an artifact to be consumed as a native dependency I remember writing a bash script that did manual jar surgery |
| 17:59 | rasmusto_ | powershell, here I come |
| 17:59 | technomancy | rasmusto_: if the files that need extracting are under a consistent prefix, :native-prefix "natives/" in the dep vector might do it? |
| 18:01 | rasmusto_ | technomancy: the dlls are just in the root of the *-platform.jar |
| 18:01 | technomancy | rasmusto_: maybe just :native-prefix "" then? |
| 18:02 | rasmusto_ | kk, will try |
| 18:02 | rasmusto_ | technomancy: !! the exception changed. I think that worked |
| 18:02 | danielsz` | If there is a consensus that wholesale imports with :use in the namespace declaration is *evil*, how come the most respected libraries instruct users to do exaclty that? I've seen it three times in a row today. Incanter, core.matrix and ring or ring related. Where is our leadership? |
| 18:03 | atyz | TimMc: https://github.com/djpowell/liverepl <--- That? |
| 18:03 | technomancy | danielsz`: I'm fairly suspicious of incanter in general |
| 18:04 | technomancy | have run into a number of poor API decisions there, primarily around using macros for no reason |
| 18:04 | amalloy | incanter is like a suuuuuuuper old project |
| 18:05 | technomancy | danielsz`: also there's a big difference between calling the use function directly and putting a :use clause in your ns form |
| 18:05 | amalloy | the author almost has to have been new to clojure when he started, since clojure was new. so probably he's made some poor decisions, in addition to following things that were community standards at the time but have since changed |
| 18:07 | TimMc | atyz: That's the one. We usually kill any host we use it on shortly afterwards as a best practice because of the classloader leakage, but it's hella useful for diagnosis or even hotpatching. |
| 18:07 | TimMc | Unfortunately it doesn't have line editing, IIRC. |
| 18:07 | danielsz` | amalloy: core.matrix is halfway in the standard library! They should know better. |
| 18:07 | technomancy | danielsz`: being a contrib project is entirely a political thing; it doesn't say anything about the code itself |
| 18:08 | atyz | TimMc: The machine is basically dead anyway so I'll give it a try! Thank you :) |
| 18:08 | atyz | I'm going to go home now, enjoy your night! |
| 18:08 | technomancy | danielsz`: if anything it means the docs are less likely to be accurate, because they can't take pull requests |
| 18:08 | TimMc | same here, you too |
| 18:08 | technomancy | for quick fixes like this |
| 18:09 | danielsz` | technomancy: What is a use case of a direct use of the use function (except in the README to make a point)? |
| 18:09 | technomancy | danielsz`: repl exploration |
| 18:10 | danielsz` | technomancy: oh yes, of course. |
| 18:10 | technomancy | it's faster to type =) |
| 18:10 | danielsz` | James Reeves definitely knows better. I'll tell him when I get the chance. |
| 18:13 | ishanc | Is it possible to gen-class clojure code and use it from java code when both the java and clojure code reside in the same maven project |
| 18:13 | ishanc | I am using the clojure-maven-plugin and calling java from clojure works fine, but not the other way around |
| 18:18 | bracki | What does this mean? https://github.com/xsc/thrift-clj/blob/master/src/thrift_clj/client.clj#L29 |
| 18:18 | bracki | What is the signature? |
| 18:19 | cbp | bracki: what signature? {:keys [protocol]} ? |
| 18:19 | bracki | i'm talking abot the & :keys stuff |
| 18:19 | cbp | it means you can call that function like (connect! client-class transport :protocol whatever) |
| 18:19 | rasmusto_ | ,(let [{:keys [a b c]} {:a 1 :b 2 :c nil}] [a b c]) |
| 18:19 | clojurebot | [1 2 nil] |
| 18:19 | cbp | bracki: its map destructuring |
| 18:20 | cbp | bracki: the & means it groups every arg after it and then the {:keys } stuff means it destructures it as a map |
| 18:21 | bracki | and the [protocol] part? |
| 18:22 | gfredericks | ,(let [[a b & {:keys [c d]}] [1 2 :e :e :d :d :c :c]] [a b c d]) |
| 18:22 | clojurebot | [1 2 :c :d] |
| 18:22 | gfredericks | bracki: that means the only key it recognizes is :protocol |
| 18:23 | danielsz` | (inc amalloy) |
| 18:23 | lazybot | ⇒ 139 |
| 18:23 | danielsz` | That's for the slice function. |
| 18:23 | gfredericks | bracki: i.e., you could call this function like (connect! my-client-class my-transport :protocol my-protocol) |
| 18:23 | gfredericks | or (connect! my-client-class my-transport) |
| 18:24 | bracki | tried that but doesn't work... |
| 18:24 | cbp | bracki: it means it's assigning the key :protocol (hence the :keys part) to the name 'protocol' |
| 18:24 | radix | I wonder why they didn't just have two different signatures, with with a protocol argument and one without |
| 18:24 | cbp | the value of the key i mean |
| 18:24 | radix | s/with with/one with/ |
| 18:24 | gfredericks | bracki: in what way did it not work? |
| 18:25 | gfredericks | radix: easier to add more options later? |
| 18:25 | radix | yeah, maybe that. |
| 18:25 | cbp | radix: i guess they thought it would be more explicit to force the user to use the keyword |
| 18:25 | cbp | :-P |
| 18:25 | rplaca | radix: also folks find that keywords are better at documenting how variable args are used, if they really are optional |
| 18:26 | rplaca | which is basically what cbp said :) |
| 18:27 | whodidthis | maybe would be easier to have a map for the opts |
| 18:27 | bracki | gfredericks: it always falls throught to https://github.com/xsc/thrift-clj/blob/master/src/thrift_clj/client.clj#L23 |
| 18:29 | gfredericks | bracki: so what's the first arg you're passing to connect!? |
| 18:29 | bracki | Oh noes, overwritten import. |
| 18:29 | bracki | Everything is fine. |
| 18:29 | bracki | But thanks for the destructuring bit |
| 18:35 | gfredericks | I am having some issue with clojure.test and records/protocols |
| 18:35 | gfredericks | something to do with the loading-everything-twice tactic I bet |
| 18:35 | cbp | what's up with cider now starting at some 'clojure.test.mode' namespace? |
| 18:35 | gfredericks | specifically a record claimed to not satisfy the protocol when it certainly should |
| 18:36 | cbp | which, much to my dismay, does not have clojure.repl use'd |
| 18:37 | hiredman | cider hates the living |
| 18:39 | gfredericks | cbp: I've given up on using things; switched to (ns .) |
| 18:39 | hiredman | gfredericks: throw in some aot'ing and you are totally screwed |
| 18:39 | gfredericks | hiredman: I'm pretty sure I can avoid that thankfully |
| 18:40 | hiredman | in theory if you are just loading everything twice you should be fine, but if you are doing anything at all between the reloads everything will likely break |
| 18:41 | hiredman | if you miss a reload, things will break, if you reload in the wrong order, things will break |
| 18:42 | gfredericks | I'm certainly not doing anything other than using normal requires |
| 18:43 | gfredericks | maybe it's time to bisect my code until I can isolate it |
| 18:45 | hiredman | ah, but do you have :reload in your requires? |
| 18:45 | gfredericks | nope |
| 18:45 | gfredericks | that would be weird |
| 18:45 | hiredman | lein used to stick :reloads in the requires for test namespaces |
| 18:45 | gfredericks | O_O |
| 18:45 | hiredman | for reasons |
| 18:45 | abp | help, i'm bleeding clojure for hours now |
| 18:46 | rasmusto_ | whatas wrong |
| 18:46 | cbp | he's bleeding clojure |
| 18:46 | hiredman | when I slip shaving parens get everywhere |
| 18:46 | abp | it feels so exciting |
| 18:47 | rasmusto_ | hiredman: like ~@? |
| 18:49 | abp | cut down maintenance? |
| 18:50 | gfredericks | no, figure out why clojure no work |
| 18:51 | abp | duh |
| 18:53 | amalloy | i like to imagine maintenance is the name of a really old tree in abp's yard |
| 18:57 | TimMc | noooo, don't cut it down! |
| 18:58 | arohner | has anyone seen 'java.lang.NoClassDefFoundError: clojure/tools/reader/reader_types/Reader' when AOT'ing? |
| 18:59 | Janiczek | any thoughts on the coding style / where it's not idiomatic etc. of https://github.com/Janiczek/cook ? (maybe play with the demo first: http://janiczek.github.io/cook/ - it's short but with a bit of reading) |
| 19:00 | cbp | I have in cljs (:require [goog.date.DateRange :as DateRange]) and (:import [goog.date DateRange]) and other such things. I'm not sure im doing this right |
| 19:03 | danielsz` | (inc hiredman) |
| 19:03 | lazybot | ⇒ 49 |
| 19:03 | danielsz` | That's for the comment on Cider. |
| 19:03 | danielsz` | It really does hate the living. |
| 19:03 | amalloy | cbp: if you have both of this things and others beside it's pretty likely you're not doing it right |
| 19:04 | amalloy | probably you want only one such thing |
| 19:04 | cbp | and.. it's probably wrong since my repl doesn't like it even though the browser does |
| 19:05 | gfredericks | okay so here's my setup |
| 19:05 | cbp | i guess the answer is to remove the one in the require and switch to DateRange.foo instead of DateRange/foo |
| 19:05 | gfredericks | I have three namespaces: protocol, record, and test |
| 19:05 | gfredericks | protocol defines a protocol |
| 19:05 | gfredericks | record defines a record that implements the protocol |
| 19:06 | gfredericks | (and requires the protocol namespace of course) |
| 19:06 | gfredericks | the test namespace requires both, and the test creates an instance of the record and calls the protocol fn with it |
| 19:06 | gfredericks | and I get an implementation error |
| 19:06 | gfredericks | but only with `lein test` |
| 19:06 | gfredericks | if I run `lein test :only the-test-ns` then it passes |
| 19:08 | cbp | actually nevermind that was due to my namespace declaration in the repl not reloading or something |
| 19:08 | amalloy | cbp: Foo.bar is kinda like an escape hatch into plain old js; you shouldn't need to use it |
| 19:09 | abp | amalloy: test-maintenance can be a problem. for example testing every single query of an application while also testing the whole api via declarative specs |
| 19:10 | amalloy | gfredericks: try putting a (println "compiling x") in each of your namespaces, to see it get double-compiled? |
| 19:10 | gfredericks | amalloy: why haven't I done that yet |
| 19:10 | cbp | amalloy: but then I need to do (DateRange. x y) (DateRange/foo) and DateRange/some-value, and neither import nor require alone allow me to do all of those |
| 19:11 | gfredericks | amalloy: the compile order in the bad case is protocol->record->protocol->test |
| 19:11 | gfredericks | in the good case, protocol->record->test |
| 19:11 | gfredericks | SO THIS IS GREAT |
| 19:13 | cbp | er actually import might |
| 19:13 | cbp | le sighs |
| 19:17 | amalloy | interesting, gfredericks. are you sure your tests aren't doing anything weird? |
| 19:17 | amalloy | or your ns forms? |
| 19:17 | amalloy | i say this, as if it were at all useful as a suggestion |
| 19:18 | gfredericks | amalloy: the weirdest thing is that the protocol and records are in test namespaces rather than src namespaces |
| 19:18 | gfredericks | amalloy: my guess is that I didn't reproduce due to nondeterministic namespace ordering? |
| 19:18 | technomancy | gfredericks: maybe try putting them in :source-paths in the :dev profile |
| 19:18 | technomancy | instead of in test/ |
| 19:19 | gfredericks | technomancy: you're suggesting that test helpers should be separate from the for-realsies-tests? |
| 19:20 | cbp | in which i deref an atom and get a core.async exception |
| 19:20 | cbp | wat |
| 19:20 | technomancy | gfredericks: not sure whether that's a general-purpose suggestion or a "this might help in this particular case" suggestion, but yeah |
| 19:21 | gfredericks | technomancy: please stay on the line while I try this and a customer service representative will be with you as soon as possible |
| 19:21 | technomancy | gfredericks: only if there's decent hold music |
| 19:22 | noncom | is there any existing library to get images from google image search ? |
| 19:22 | danielsz` | technomancy: I meant to ask you: after writing OCaml code on Grenchman, did you have a moment when you said to yourself, this is it, I'm not going back to Clojure? |
| 19:22 | amalloy | cbp: i don't think you can get an exception from derefing an atom, in clojure or clojurescript. you *could* get one from attempting to print the result, or really do anything at all with it |
| 19:23 | gfredericks | technomancy: the hold music will be good but it will be interrupted every 47 seconds for a message about how super excited we are to have you as a customer |
| 19:23 | noncom | i suppose it is possible with clj-http + some stuff, but probably there is a ready solution |
| 19:23 | cbp | amalloy: yes from printing |
| 19:23 | amalloy | gfredericks: i hate you now |
| 19:23 | gfredericks | amalloy: because of how much I appreciate you as a customer? |
| 19:24 | gfredericks | technomancy: it worked |
| 19:24 | gfredericks | why do we even need the :reload? |
| 19:24 | technomancy | gfredericks: for folks with resident project JVMs |
| 19:25 | gfredericks | O_O_O |
| 19:25 | amalloy | gfredericks: technomancy runs his tests through swank or cider or whatever, not lein test |
| 19:25 | technomancy | like if you keep your process up in between task runs |
| 19:25 | technomancy | :eval-in :nrepl, ccw, grenchman, etc |
| 19:26 | gfredericks | amalloy: how do I install swank or cider or whatever on my jenkins |
| 19:26 | amalloy | prolly apt-get. the answer to everything |
| 19:26 | gfredericks | where is gtrak |
| 19:26 | technomancy | danielsz`: haha, not really. OCaml and Clojure are very complementary. |
| 19:26 | cbp | brushing up on his coffeescript |
| 19:27 | technomancy | danielsz`: it definitely made me 10x more frustrated at clojure's sloppy nil handling though |
| 19:27 | technomancy | "embrace the platform" is a two-edged sword, as we all know |
| 19:28 | amalloy | technomancy: but nils are awesome! 10x zero frustration is still zero! |
| 19:28 | technomancy | http://p.hagelb.org/get-out.gif |
| 19:28 | gfredericks | lin is an object that signifies the presence of a value; it is always truthy |
| 19:29 | gfredericks | the SQL equivalent is called LLUN, and it has the property that LUNN = x is always true |
| 19:29 | gfredericks | s/LUNN/LLUN/ |
| 19:29 | aperiodic | even if x is NULL? |
| 19:29 | danielsz` | technomancy: Interesting. I thought there was solace in a native environment vs the hosted one of Clojure (with so many levels of indirectness). And I thought maybe type-oriented development would be addictive. And also more principled design instead of the hackinesss of meta-programming, but maybe all of those are also seductive in their own right. |
| 19:30 | gfredericks | aperiodic: don't do that |
| 19:30 | technomancy | danielsz`: it also made me realize how little I care about homoiconicity |
| 19:30 | gfredericks | technomancy: but but paredit! |
| 19:30 | amalloy | aperiodic: testing NULL==LLUN is defined to uninstall your database server |
| 19:30 | hiredman | gfredericks: I jave a jenkins plugin that launches an nrepl repl inside the jenkins jvm |
| 19:30 | technomancy | danielsz`: the main pain point with ocaml syntax is its precedence rules, not the lack of macros |
| 19:31 | rasmusto_ | hmm, I have to do a lein clean && lein deps to get my target/native stuff to show up |
| 19:31 | hiredman | it was super painful |
| 19:31 | hiredman | the insides of jenkins are terrible |
| 19:31 | amalloy | rasmusto_: everytime you run *one* of those commands god kills a kitten |
| 19:31 | gfredericks | the insides of _______ are pretty bad too |
| 19:32 | technomancy | danielsz`: avoiding the large runtime just means you can apply it to a different class of problems. better at small utilities but worse at long-running servers, etc. |
| 19:32 | hiredman | https://github.com/hiredman/jenkins-clojure-injector/blob/master/src/leiningen/jpi.clj |
| 19:32 | amalloy | technomancy: i had to run `lein clean && lein deps` a few weeks ago, but this was on lein 1.6 and so i didn't think you'd appreciate the bug report |
| 19:32 | technomancy | amalloy: I forgive you. |
| 19:33 | rasmusto_ | part of my confusion is trying to deal with a project that has a lot of native stuff and non-specific dependencies |
| 19:33 | rasmusto_ | the leiningen stuff is very usable so far, thanks for the support technomancy |
| 19:33 | technomancy | rasmusto_: cool |
| 19:33 | technomancy | native code is definitely a weak point right now since no one understands how it works |
| 19:35 | danielsz` | technomancy: Maybe if you had written Grenchman in Haskell where precedence rules are configurable we would have lost you for good :-) |
| 19:35 | technomancy | danielsz`: lost me to raving lunacy, probably |
| 19:36 | arrdem | technomancy: what, you aren't raving already? you built a build tool ffs |
| 19:36 | technomancy | debatable |
| 19:36 | turbofail | hm. when i have to switch between ruby and clojure i find homoiconicity to be a huge deal |
| 19:37 | turbofail | but perhaps ocaml is different |
| 19:37 | technomancy | turbofail: homoiconicity or clarity? |
| 19:37 | turbofail | both |
| 19:37 | technomancy | clojure achieves clarity/consistency through homoiconicity I would say |
| 19:37 | turbofail | i really miss being able to use paredit commands for shuffling my code around |
| 19:37 | technomancy | ruby fairs to achieve clarity most of the time, and ocaml achieves it through other means |
| 19:38 | technomancy | also, you can do C-M-k (kill expression at point) without paredit, which goes a long way |
| 19:38 | technomancy | so actually bitemyapp threatened to port grenchman to haskell |
| 19:38 | turbofail | ha |
| 19:38 | technomancy | haha "Derelict repo, abandoned because I have no interest in making tools for the Clojure community." |
| 19:39 | technomancy | cute |
| 19:39 | arrdem | yeah... pls flounce more |
| 19:39 | technomancy | https://github.com/bitemyapp/grom |
| 19:39 | danielsz` | is it only me or this place feels less threatening since bitemyapp left? |
| 19:40 | aperiodic | it's not just you |
| 19:40 | arrdem | not just you... it's been an improvement since blocking him on twitter as well.. |
| 19:41 | arrdem | last time we met in person he had some one-liner about how he's keeping a scorecard for how many blocks he can accumulate from clojure users... |
| 19:41 | danielsz` | amazing how 1 person can set a general mood. |
| 19:41 | technomancy | how is this an improvement? https://github.com/bitemyapp/grom/blob/master/src/Main.hs#L29 over https://github.com/technomancy/grenchman/blob/master/grench.ml#L35 |
| 19:42 | turbofail | hm. how does C-M-k work in ocaml? isn't the entire notion of "next sexp" kind of fuzzy? |
| 19:42 | technomancy | turbofail: not at all; it's quite clear |
| 19:43 | ttasterisco | so what's the story behind bitemyapp? met him once last year at a clj meetup, he sounded peaceful. fast forward a few months and he moved to haskell and all I saw was some rages at clojure? |
| 19:43 | danielsz` | turbofail: Emacs adjusts the meaning of "expression at point" based on context. |
| 19:43 | technomancy | at least, emacs is smart enough to figure it out consistently |
| 19:44 | amalloy | ttasterisco: from what i understand he's a pretty mellow guy in person. in #clojure, he was abrasive |
| 19:44 | arrdem | amalloy: meh... he's way more abrasive online, but he's not exactly mellow in person either |
| 19:44 | technomancy | he's out to prove how right slash smart he is |
| 19:45 | danielsz` | ttasterisco: He's just an assertive and opinionated person. He discovered Haskell and preaches it now. If you don't mind his style, use it to your benefit. Everybody wins at learning Haskell. |
| 19:45 | technomancy | one of my favourite things about OCaml is how it doesn't attract that kind of person |
| 19:46 | amalloy | haskell is pretty cool. it's just, knowing that doesn't have to correlate with being a jerk. i don't think haskell was really that important in his decision to leave |
| 19:46 | gfredericks | camel-like personalities |
| 19:46 | amalloy | technomancy: what is List.tl? clojure.core/rest? |
| 19:46 | danielsz` | Haskell are known to be a peaceful bunch too. Bitemyapp is not representative of Haskell any more than he was of Clojure. |
| 19:47 | technomancy | amalloy: yeah |
| 19:47 | turbofail | technomancy: so when you have something like "|List.fold_left (+) 0 xs", what's the "next sexp"? |
| 19:47 | turbofail | in clojure, depending on where i put the point, the next sexp could be `fold-left', or it could be the whole `(fold-left ...) thing |
| 19:48 | turbofail | but it doesn't seem like i have those options here |
| 19:48 | technomancy | turbofail: probably the whole thing. it's been almost a year since I was using it though. |
| 19:48 | turbofail | hm |
| 19:50 | amalloy | i would have guessed List.fold_left is the next sexp, because in that world you can get the whole thing if you want, via M-4 C-M-k |
| 19:50 | technomancy | kinda want to get back into it, but hard to justify when the only clojure I write is lein itself |
| 19:51 | technomancy | I really miss option types and pattern matching |
| 19:52 | danielsz` | technomancy: Exactly. |
| 19:53 | danielsz` | technomancy: I saw this earlier today. I haven't read it seriously though: http://brehaut.net/blog/2011/error_monads |
| 19:53 | technomancy | danielsz`: option types without pattern matching isn't really worth the trouble though |
| 19:54 | danielsz` | technomancy: Good point. |
| 19:54 | technomancy | there's a big difference between "using this technique in our own codebase" and "this technique is pervasively used in the language" |
| 19:55 | danielsz` | technomancy: Very true. Would you say the same for CSP and core.async? |
| 19:55 | technomancy | I don't really know enough about csp to comment |
| 19:56 | technomancy | I suspect it's different just because async communication is a much less common need than representing potential failures |
| 19:57 | technomancy | (witness the fact that I have basically never needed the former personally, whereas any nontrivial program needs the latter) |
| 19:58 | danielsz` | technomancy: I mean that Lisp languages can adopt paradigms and really sway the constituency, like core.async. |
| 19:59 | danielsz` | Lots of people use core.async like it was part of Clojure. While no Option types implementation has convinced. We have the parts. We have core.match and error monads. But it didn't take on. |
| 20:00 | technomancy | core.match was horribly broken for years |
| 20:00 | danielsz` | Maybe that's the reason. Is it better now? |
| 20:00 | technomancy | yeah, but it still never had nearly as much work poured into it as core.async |
| 20:00 | technomancy | which is really infuriating imo |
| 20:00 | technomancy | because it's so much more useful |
| 20:01 | danielsz` | I've used it in cljs projects. Very useful, I love it. |
| 20:01 | arrdem | tbaldridge: so given that I'm gonna have to eat the price of compiling clojure/core.clj with the reference compiler whenever I finally hook into RT, do you think it's worth the effort to hack the way require behaves so that core.clj is loaded, analyzed and reduced by Oxcart? I'd like to be able to use the tightest core that Oxcart can build but given that RT is gonna build the "normal" core anyway I'm not sure it buys me anything without starting to write m |
| 20:01 | technomancy | oh yeah, I speak only for server-side stuff |
| 20:01 | turbofail | core.match looks kind of awkward compared to racket's pattern matcher |
| 20:01 | turbofail | syntactically anyway |
| 20:02 | brehaut | technomancy: the error monad thing is useful but yes, problematic. i used polymorphism and it works but it makes me sad |
| 20:02 | brehaut | technomancy: i'd rewrite that with core.match in a second if i could |
| 20:02 | technomancy | brehaut: erlang just uses pattern matching against lists. works great and is a fairly pervasive pattern |
| 20:02 | technomancy | but core.match is too fast-moving for me to include in lein |
| 20:03 | technomancy | since it would preclude plugins from using newer versions =( |
| 20:03 | technomancy | I've only used core.match in a brief seajure hack night |
| 20:03 | brehaut | right |
| 20:04 | brehaut | i think core.match has settled a bit recently? mostly due to some hard problems that dnolen is still working out? |
| 20:04 | technomancy | I've been burned by too-old deps several times in the past |
| 20:05 | technomancy | brehaut: it's not just that new versions must be backwards-compatible, it's that new versions literally cannot be loaded by plugins =\ |
| 20:05 | brehaut | youch yeah |
| 20:06 | technomancy | https://github.com/technomancy/leiningen/issues/1563 =( |
| 20:06 | gfredericks | technomancy: just renamespace the libs you want :P |
| 20:07 | technomancy | ._. |
| 20:07 | gfredericks | hey man, do it for leiningen. |
| 20:07 | gfredericks | (ns leiningen.clojure.core.match ...) |
| 20:07 | brehaut | technomancy: :S |
| 20:08 | technomancy | http://p.hagelb.org/10no.gif |
| 20:09 | brehaut | haha |
| 20:11 | danielsz` | What makes or breaks compatibility with leiningen? Is it only version clashes with leiningen's own dependencies? |
| 20:12 | technomancy | danielsz`: plugins can only introduce new dependencies, not new versions of existing ones. |
| 20:13 | technomancy | which I guess is what you said |
| 20:14 | danielsz` | I think so. And those existing dependencies are those listed in leinignen's project.clj: https://github.com/technomancy/leiningen/blob/master/project.clj |
| 20:14 | danielsz` | Very few dependencies. |
| 20:15 | danielsz` | Ah, yes, core.cache gave some trouble |
| 20:16 | technomancy | http://p.hagelb.org/lein-deps-tree.html 66 deps in the full tree |
| 20:17 | danielsz` | Oh, I see. |
| 20:17 | technomancy | data.xml and apache http-client are another source of troubles |
| 20:18 | danielsz` | Ah, yes, http-client, talking about fast-moving... |
| 20:19 | Shayanjm | If I wanted to run a function, wait for some time, then recur indefinitely - how might I do this without committing code suicide? |
| 20:20 | danielsz` | Shayanjm: Would this help? https://github.com/joegallo/robert-bruce |
| 20:21 | Shayanjm | why yes, yes it would danielsz` |
| 20:21 | Shayanjm | thanks :) |
| 20:21 | rurumate | is there any source on how to convert the result of (go 42) to a java.concurrent.Future or something similar |
| 20:22 | rurumate | in java preferably |
| 20:22 | _99hats_ | danielsz: nice find! I've been looking for something like that too |
| 20:22 | brehaut | ,(class (future 1)) |
| 20:22 | clojurebot | #<SecurityException java.lang.SecurityException: no threads please> |
| 20:23 | brehaut | &(class (future 1)) |
| 20:23 | lazybot | java.lang.SecurityException: You tripped the alarm! future-call is bad! |
| 20:23 | danielsz` | Shayanjm: That's a library solution. Many ways to achieve this with built-in fns too. Look at delay, future, etc. |
| 20:23 | brehaut | le sigh |
| 20:23 | brehaut | ,(source future-call) |
| 20:23 | clojurebot | Source not found\n |
| 20:23 | Shayanjm | much appreciate danielsz` :) |
| 20:23 | Shayanjm | appreciated** |
| 20:23 | danielsz` | Welcome. |
| 20:31 | tuft_ | is there a way to make certain functions available in all namespaces for repl sessions? |
| 20:31 | tuft_ | keep needing to "cd" back to user for doc, refresh, etc. |
| 20:32 | technomancy | tuft: not really; the best way to do stuff like that is to expose it from the editor |
| 20:32 | technomancy | cider for instance has doc, source, etc, but it makes adding new commands difficult |
| 20:33 | tuft | ah hrm, ok |
| 20:33 | tuft | thought there might be a way to "patch" clojure.core or something |
| 20:34 | tuft | my workflow is to run files in the repl, which changes the ns |
| 20:34 | arrdem | tuft: not really, you'd have to hack either the namespace macro or in-ns, neither of which is an awesome idea. |
| 20:34 | tuft | (i'm using cursive) |
| 20:34 | tuft | ok, thanks |
| 20:35 | technomancy | gfredericks: did you notice how I helped with your defrecord problem without ever once chastising you for using records? |
| 20:36 | rurumate | not sure if this works: https://www.refheap.com/87852 |
| 20:36 | rurumate | can just call macros using RT.var() ?? |
| 20:36 | lazybot | rurumate: Uh, no. Why would you even ask? |
| 20:36 | technomancy | tuft: a better solution would be https://github.com/technomancy/nrepl-discover |
| 20:36 | technomancy | except it's kinda half-baked |
| 20:37 | rurumate | let's be nice lazybot mkay |
| 20:39 | amalloy | rurumate: well, he was right |
| 20:39 | amalloy | and robots can afford to be rude |
| 20:40 | rurumate | RT.var("clojure.core","->").invoke(5) |
| 20:40 | rurumate | don't know how to write that in a repl so not even trying lol |
| 20:41 | amalloy | rurumate: calling macros from java is basically impossible; you can do it, but all they produce is clojure code, which does you no good |
| 20:41 | noonian | ,#'-> |
| 20:41 | clojurebot | #'clojure.core/-> |
| 20:41 | rurumate | so what call RT.var("clojure.core","eval").invoke("(-> 5)") maybe? |
| 20:41 | amalloy | the core.async macros like <! are even worse, because they don't actually exist as real macros: they're just placeholders that go looks for |
| 20:43 | rurumate | is <! a macro? |
| 20:43 | arrdem | yep |
| 20:43 | amalloy | no, it's magic |
| 20:43 | arrdem | (assert (magic? macros)) |
| 20:43 | rurumate | well it could be a function for instance, or just data |
| 20:43 | rurumate | a symbol? |
| 20:43 | amalloy | it's none of those things. it doesn't exist |
| 20:44 | amalloy | core.async/go looks for it in your code |
| 20:44 | rurumate | since we're in a go block it doesn't matter what it is right |
| 20:44 | rplaca | well, it *is* a symbol |
| 20:44 | rurumate | so just a symbol? but I had to require it |
| 20:45 | rplaca | but the go block macro expansion recognizes it and transforms around it |
| 20:45 | rurumate | anyway how to convert the return value of a go-block to a Future<Object>, there surely is something yet? |
| 20:46 | rurumate | just for interop goodness |
| 20:47 | noonian | you could write it in clojure and just call that var |
| 20:47 | rurumate | uuh, that fn you mean? |
| 20:47 | noonian | yes |
| 20:47 | rurumate | thatt would work, provided we have already written it in clojure :D |
| 20:47 | noonian | go-blocks return channels that return the last form of the body of the go-block |
| 20:48 | rurumate | yes, but there is no java interface "channel" and it can be treated like a Future in manyn cases, to from java perspective, it is a Future right? |
| 20:49 | rurumate | sorry keyboard is falling apart |
| 20:49 | technomancy | amalloy: I wonder if it qualifies as a special form |
| 20:50 | technomancy | iirc thrown? in clojure.test is the same way |
| 20:50 | amalloy | technomancy: well, compare to catch and finally in a try |
| 20:51 | rurumate_ | I mean we should probable also write a converter channel -> Queue and a new interface Channel maybe but for now I'm trying to convert the ch to a Future |
| 20:51 | technomancy | amalloy: yup |
| 20:51 | amalloy | try is a special form, and it dictates how to handle catch/finally, neither of which are themselves special |
| 20:51 | technomancy | if you consider the macro the "compiler" I think it fits the definition |
| 20:52 | rurumate_ | how to evaluate whole clojure expression given as string, from java? |
| 20:53 | rurumate_ | RT.var("clojure.core",:eval read-string can do |
| 20:54 | rurumate_ | sigh, RT.var("clojure.core","eval").invoke("clojure.core","read-string").invoke("(-> 5)") |
| 20:57 | amalloy | rurumate_: in clojure 1.6, clojure.java.api.Clojure makes that slightly more convenient, but you've got the basic idea |
| 20:57 | rurumate_ | still wrong tho |
| 20:57 | amalloy | oh? did you forget to require clojure.core? |
| 20:59 | rurumate_ | why is this so hard? |
| 20:59 | technomancy | because it's java |
| 21:00 | amalloy | i don't know what he's complaining about. the thing he pasted works |
| 21:00 | amalloy | ,(-> (RT/var "clojure.core" "eval") (.invoke (-> (RT/var "clojure.core" "read-string") (.invoke "(-> 5)")))) |
| 21:00 | clojurebot | #<CompilerException java.lang.RuntimeException: No such namespace: RT, compiling:(NO_SOURCE_PATH:0:0)> |
| 21:01 | amalloy | ,(-> (clojure.lang.RT/var "clojure.core" "eval") (.invoke (-> (clojure.lang.RT/var "clojure.core" "read-string") (.invoke "(-> 5)")))) |
| 21:01 | clojurebot | 5 |
| 21:01 | technomancy | well, I wouldn't know how to do that in java |
| 21:01 | amalloy | it's what he pasted |
| 21:01 | amalloy | oh, except he needs to cast to IFn |
| 21:02 | amalloy | no, i guess he doesn't. dunno what was wrong for him |
| 21:08 | gfredericks | technomancy: no I did not notice that. thank you for helping me with my defrecord porblem |
| 21:08 | gfredericks | (inc technomancy) |
| 21:08 | lazybot | ⇒ 116 |
| 21:08 | technomancy | I was holding back |
| 21:10 | gfredericks | technomancy: I'm curious how you would model the problem; can't splain it right now though |
| 21:13 | gfredericks | technomancy: I guess it's just an unqualified "multimethods" eh? |
| 21:13 | arrdem | happy 4th people |
| 21:13 | arrdem | murica |
| 21:29 | technomancy | gfredericks: if it's a legitimate polymorphism need, sure |
| 21:29 | technomancy | *legitimate non-bottleneck polymorphism |
| 21:31 | gfredericks | technomancy: I use component and I like how protocols formalize the relationship between different parts of the application |
| 21:32 | gfredericks | and make it easy to mock stuff in tests |
| 21:32 | Shayanjm | not sure if this function does what I want it to do... |
| 21:32 | Shayanjm | https://gist.github.com/shayanjm/383b5847738c35f748a6 |
| 21:33 | Shayanjm | Basically, when I pass a function into infinite-loop-on-realization, I would like it to execute the function, wait for it to return, and then repeat without blocking the execution of anything else |
| 21:34 | hiredman | uh |
| 21:35 | hiredman | realized? is always true for a promise you have delivered to |
| 21:35 | Shayanjm | Even if the promise hasn't fully resolved yet hiredman? |
| 21:35 | Shayanjm | i.e: if 'func' takes like a minute to fully execute |
| 21:35 | Shayanjm | is current-promise realized before func finishes executing? |
| 21:36 | hiredman | Shayanjm: you are calling func as an argument to deliver, so by the time deliver runs, func as already finished |
| 21:36 | hiredman | (while true (func)) is equivilant to what you have written there |
| 21:37 | Shayanjm | Oh I see |
| 21:37 | Shayanjm | So I actually don't even need the when |
| 21:37 | Shayanjm | I just loop after deliver? |
| 21:38 | hiredman | no, the promise and the deliver are doing nothing there |
| 21:38 | hiredman | (while true (func)) will run exactly the same |
| 21:38 | Shayanjm | oic |
| 21:38 | Shayanjm | Okay let me ask this a different way |
| 21:38 | Shayanjm | given a function which I would like to execute continuously without blocking, and loop on return, what's the easiest way to do that? |
| 21:39 | Shayanjm | since I'm assuming (while true (func)) will block |
| 21:39 | hiredman | Shayanjm: rigth, and so will your code |
| 21:39 | Shayanjm | Okay let me try refactoring this really quickly |
| 21:46 | Shayanjm | hiredman: https://gist.github.com/shayanjm/d37b5b34b08281fa0aa7 |
| 21:46 | Shayanjm | threw the function into a future |
| 21:47 | Shayanjm | waiting until the function finishes executing, then recurs |
| 21:54 | Shayanjm | Yeah I don't think this is doing what I want it to do... |
| 22:06 | hellofunk | i'm trying to find the best way to architect a series of source files that communicate via async channels; but they must all know the same channel object to do so. to avoid circular dependencies, i'm giving each one an atom, then a controller source file creates the channel and each file gets a copy of it. but seems like potential for state mess |
| 22:08 | ddellacosta | hellofunk: why can't you put the shared channel in one namespace, and then include that in all the other namespaces that need it? |
| 22:09 | hellofunk | ddellacosta: but just including a namespace isn't the same as including the data in an atom stored in that namespace, right? wouldn't all the includes lead to different default values for the atom? |
| 22:09 | ddellacosta | hellofunk: or is that what you're doing and I'm not understanding your question? |
| 22:10 | ddellacosta | hellofunk: it doesn't have to do with namespaces, it has to do with threads and the type of construct you choose to use |
| 22:10 | ddellacosta | hellofunk: I like Arthur Ulfeldt's answer here: http://stackoverflow.com/questions/9132346/clojure-differences-between-ref-var-agent-atom-with-examples |
| 22:11 | hellofunk | ddellacosta for example, i have a (def a (atom 0)) in a namespace. now I include this namespace in a bunch of others. But if the atom is swapped by one file, that wouldn't mean that the other files that include the atom file will see that new atom's state |
| 22:11 | ddellacosta | hellofunk: yes. So you have to know that that's the model you want to use. |
| 22:12 | hellofunk | ddellacosta: you mean "yes" as in, I am correct, the swapped atom would not in that case be seen by other files. |
| 22:13 | ddellacosta | hellofunk: no, it would. You are updating that atom and that update would be visible to all namespaces using it. |
| 22:13 | ddellacosta | hellofunk: sorry if I responding confusingly, I meant, "yes it would update" |
| 22:14 | hellofunk | ddellacosta: oh that's interesting. I thought that when a file does a require, it basically reads the source file as if it was brand new and hadn't been loaded before and any (def a (atom...)) creates a new atom; therefore every require in the whole project would be creating new atoms |
| 22:15 | nathan7 | hellofunk: namespaces are like, actual objects |
| 22:15 | nathan7 | hellofunk: held in a global table of all namespaces |
| 22:15 | nathan7 | hellofunk: they're loaded once |
| 22:16 | nathan7 | hellofunk: if you're AOT compiling, they're just classfiles |
| 22:16 | hellofunk | nathan7, ddellacosta: ah! so no matter how many times you load (require) a namespace, it really only exists once, including any defs (atoms) it has? wow this is definitely not what I thought was happening. |
| 22:16 | ddellacosta | well, think about defonce |
| 22:16 | nathan7 | hellofunk: yep |
| 22:16 | nathan7 | hellofunk: see (all-ns) |
| 22:16 | nathan7 | ,(all-ns) |
| 22:16 | clojurebot | (#<Namespace clojure.uuid> #<Namespace user> #<Namespace clojure.core> #<Namespace sandbox> #<Namespace clojure.repl> ...) |
| 22:17 | hellofunk | nathan7 well this certainly makes things easier. i was forging into spaghetti and now i see that was unnecessary |
| 22:17 | nathan7 | ,(->> (all-ns) (map #(vector (.name %) %)) (into {})) |
| 22:17 | clojurebot | {user #<Namespace user>, clojure.core.protocols #<Namespace clojure.core.protocols>, clojure.core #<Namespace clojure.core>, sandbox #<Namespace sandbox>, clojure.uuid #<Namespace clojure.uuid>, ...} |
| 22:18 | nathan7 | that map exists somewhere, the global namespace table |
| 22:18 | hellofunk | nathan7 so the first namespace to require another namespace "instantiates" it, while any other requires just "point" to it |
| 22:18 | nathan7 | hellofunk: yep |
| 22:19 | nathan7 | hellofunk: you could consider all the namespaces as 'already there', but just lazily loaded |
| 22:19 | hellofunk | nathan7 i was so wrapped up in the functional nature of how clojure works, it did not occur to me that this object-oriented type of state could be happening |
| 22:19 | ddellacosta | hellofunk: yes, I was going to say, think about defonce--its existence tells you a lot about how namespaces work in Clojure |
| 22:19 | ddellacosta | (doc defonce) |
| 22:19 | clojurebot | eval service is offline |
| 22:20 | ddellacosta | $&!#&! |
| 22:20 | ddellacosta | &(doc defonce) |
| 22:20 | lazybot | ⇒ "Macro ([name expr]); defs name to have the root value of the expr iff the named var has no root value, else expr is unevaluated" |
| 22:21 | hellofunk | ddellacosta but if require points to existing namespace objects already, i would think that just plain ol' def would not get recreated if what nathan7 says is correct, that def would not re-def everytime the file is loaded |
| 22:21 | nathan7 | hellofunk: it would re-def every time the file is loaded |
| 22:21 | nathan7 | hellofunk: however, the file is loaded only once |
| 22:21 | nathan7 | hellofunk: unless you require it with :reload |
| 22:22 | hellofunk | nathan7 ah, so if i have a (def (atom ...)) then indeed every time that namespace is required, the def will indeed be reset. thus, defonce would prevent this and ensure that only one piece of state existed unchanged no matter how many requires |
| 22:22 | nathan7 | hellofunk: no |
| 22:22 | ddellacosta | hellofunk: not required, reloaded |
| 22:23 | hiredman | require loads the namespace if it is not already loaded |
| 22:23 | nathan7 | hellofunk: require looks like (if (contains? namespaces) (get namespaces ns) (load ns)) |
| 22:23 | hellofunk | well, i mean the :require in the (ns at the top of the file. |
| 22:23 | nathan7 | hellofunk: yes |
| 22:23 | nathan7 | hellofunk: it'll load it if it isn't loaded yet |
| 22:24 | hellofunk | so, going back to ddellacosta original suggestion, i could put all my shared atoms in a single namespace, but they should be defonce for all of them |
| 22:24 | hiredman | ugh |
| 22:24 | hiredman | terrible |
| 22:24 | hiredman | how about you just pass arguments to functions |
| 22:24 | hellofunk | hiredman, well this gets back to my original question |
| 22:25 | hellofunk | hiredman, the problem is circular dependencies. |
| 22:25 | nathan7 | hellofunk: even just def would be fine |
| 22:25 | hiredman | hellofunk: it isn't |
| 22:25 | nathan7 | ,@#'clojure.core/*loaded-libs* |
| 22:25 | clojurebot | #<Ref@7643fa: #{clojure.core.protocols clojure.instant clojure.java.io clojure.repl clojure.string ...}> |
| 22:25 | hellofunk | nathan7 you say that because everything is loaded at once, therefore all the multiple defs just happen at the same time |
| 22:25 | hiredman | create a namespace foo, it requires the other namespaces and calls functions from them |
| 22:26 | nathan7 | hellofunk: http://sprunge.us/YOTZ?clojure |
| 22:26 | nathan7 | hellofunk: src/clj/clojure/core.clj around line 5475 |
| 22:26 | hiredman | (require '[foo.bar :as foo] '[a.b :as a]) (let [c (chan] (foo/bar c) (a/bar c)) etc |
| 22:27 | nathan7 | hellofunk: if you haven't passed :reload, and it's already loaded, it'll just grab it from *loaded-libs* |
| 22:27 | hiredman | global atoms in a namespace? what are you guys even thinking? |
| 22:27 | nathan7 | q= |
| 22:28 | hellofunk | hiredman so you are suggesting to just pass the channel as arguments instead of sharing it in a piece of state |
| 22:28 | ddellacosta | hiredman: I've had cases where global atoms are the right solution--for example if I need initialization of a resource to happen at a specific time, and I know it won't change. |
| 22:28 | hiredman | hellofunk: yes |
| 22:29 | nathan7 | my main clojure app has an agent like this for similar reasons |
| 22:29 | hellofunk | hiredman well I can't really argue with that. but part of this model is stemming from the fact that I'm using Om, which uses a single global atom for state. and i'm trying to interact with it from various source files |
| 22:29 | nathan7 | it's the state everything operates on |
| 22:29 | hiredman | nathan7: ugh |
| 22:29 | nathan7 | hiredman: it's a server, it has one global piece of state I need to interact with everywhere |
| 22:29 | hiredman | nathan7: ugh |
| 22:29 | nathan7 | hiredman: if there is >1 instance of it everything is fucked |
| 22:30 | nathan7 | hiredman: and I need access to it from nREPLs etc |
| 22:30 | nathan7 | hiredman: I'm considering moving it into the file with my -main and passing it to everywhere from there |
| 22:30 | nathan7 | hiredman: but that's still kind of painful |
| 22:30 | nathan7 | hiredman: like, I am totally with you on this |
| 22:31 | nathan7 | hiredman: but this is just like, say, the global table of namespaces |
| 22:31 | nathan7 | hiredman: because it's basically this app's namespaces of domain data |
| 22:32 | nathan7 | I still have to think a bunch about how the state works for this thing though |
| 22:32 | hellofunk | hiredman or i guess one could just pass the atom itself around in the arguments |
| 22:33 | hellofunk | hiredman it just seemed easier to reduce lots of extra args on every function |
| 22:33 | ddellacosta | hellofunk: I think an atom is a perfectly reasonable place to put a channel that you know won't change for the lifecycle of the app |
| 22:33 | ddellacosta | hellofunk: but opinions may differ |
| 22:33 | nathan7 | ddellacosta phrased what I was trying to say perfectly |
| 22:34 | nathan7 | like, passing this around everywhere would lead to state being strewn all over the place |
| 22:34 | nathan7 | and I'm writing Clojure because I wish to avoid that |
| 22:34 | hellofunk | ddellacosta regarding defonce vs just def seems this is useful only if you might actually call def on something more than once |
| 22:35 | nathan7 | I use defonce for this because I'd rather not have all my state reappear when I re-evaluate the file it's in |
| 22:35 | hellofunk | nathan7 be "reappear" you mean get reset to the default state noted in the source file |
| 22:36 | nathan7 | hellofunk: which is 'empty' |
| 22:36 | nathan7 | hellofunk: (defonce world (agent (WorldState.)) |
| 22:37 | hellofunk | nathan7 so i think you mean "disappear" upon re-eval rather than "appear" ? |
| 22:37 | ddellacosta | nathan7: yes, passing stuff around exclusively can lead to equally hard-to-reason-about code |
| 22:37 | nathan7 | err, disappear, yes |
| 22:37 | gfixler | Is there a version of drop-while that returns the result of the predicate test, instead of the shorter collection? |
| 22:37 | nathan7 | Clojure namespaces are a really pleasant mechanism for this stuff |
| 22:38 | hellofunk | well all this has been quite enlightening. all this time i thought :require statements were giving each source file its own copy of everything in the :require'd namespace. fantastic to hear that's not the case. |
| 22:38 | ddellacosta_ | hiredman: can you please allow my handle (ddellacosta) access to clojurebot? |
| 22:38 | nathan7 | namespaces just… magically reify a concept I already use in any module system |
| 22:38 | nathan7 | and it's grand |
| 22:39 | nathan7 | like, my code is data, and it's state |
| 22:39 | hellofunk | that namespaces are basically an object-oriented structure inside any clojure project is pretty cool, actually. |
| 22:40 | ddellacosta_ | hellofunk: not object-oriented. ;-) |
| 22:40 | nathan7 | object-oriented in the sense that they are objects that can be manipulated, perhaps |
| 22:41 | hellofunk | nathan7 object-oriented in that they are single copies of everything they contain, where all the defs are like stored state made available to any other namespace that uses it |
| 22:43 | nathan7 | hellofunk: I suppose they're actually quite OO |
| 22:43 | nathan7 | hellofunk: they're state and behaviour |
| 22:43 | gfixler | Nevermind, found it: (some #(when (pred? %) %) coll) ; Clojure is cool |
| 22:43 | nathan7 | gfixler: hm, there should be a better way |
| 22:43 | ddellacosta_ | nathan7: but not encapsulated; there's no data hiding, no? |
| 22:43 | nathan7 | ddellacosta_: ^:private |
| 22:44 | ddellacosta_ | nathan7: hmm, fair point, although there's a good amount of debate over use of ^:private |
| 22:44 | gfixler | nathan7: how about (winner pred? coll)? :) |
| 22:45 | danielsz` | gfixler: that reads like 'filter to me |
| 22:45 | gfixler | danelsz: you're right - so maybe (first (filter pred? coll)) |
| 22:46 | nathan7 | okay now I feel very stupid for not thinking of that |
| 22:46 | gfixler | It's worse for me; I've been looking at this for about 20 minutes :( |
| 22:46 | nathan7 | this is the thing about functional programming languages |
| 22:47 | danielsz` | give it some time. it sinks in and becomes second nature |
| 22:47 | nathan7 | like, once I start doing complex objects I can just worry about how my shit fits into this complicated structure |
| 22:47 | nathan7 | and I can avoid solving actual, well, math, technically |
| 22:48 | gfixler | Even though I'm a newb to FP, it's happening. It's becoming more normal each day. |
| 22:48 | nathan7 | I'm a functional JS programmer, people pay me money to write JavaScript |
| 22:48 | nathan7 | and I love it |
| 22:49 | gfixler | Nice. I'm in games - mostly Python for tools/pipeline stuff in Autodesk Maya. |
| 22:49 | nathan7 | because they're convinced that I'm writing JS, and I'm just writing functional code, that happens to be encoded as JavaScript |
| 22:50 | nathan7 | and JS lends itself perfectly to this |
| 22:50 | clojurebot | It's greek to me. |
| 22:50 | gfixler | Hehe. I'm also doing somewhat functional things in Python, and no one is the wiser. |
| 22:50 | nathan7 | something I've been doing for a few projects is just prototyping the concepts in Clojure |
| 22:50 | nathan7 | and then transliterating it |
| 22:50 | gfixler | Are you on Linux? |
| 22:50 | nathan7 | Yep |
| 22:50 | gfixler | nice |
| 22:50 | nathan7 | like, I have a bunch of little helper libs |
| 22:50 | gfixler | same here - I can hop in and out of languages instantly |
| 22:51 | gfixler | "How would I do this in Clojure?" - seconds later hammering away in a repl |
| 22:51 | gfixler | then I go back to Python and sigh, because it's much harder there |
| 22:51 | nathan7 | I wrote a helper lib that's just all the hashmap functions from Clojure |
| 22:51 | nathan7 | like, assoc/assoc-in/dissoc/keys/vals/etc |
| 22:51 | gfixler | cool - FP is giving JS a second life |
| 22:52 | nathan7 | and each of the mutation functions has a matching one postfixed with M |
| 22:52 | nathan7 | which actually mutates objects in place instead of copying them completely for every operation |
| 22:53 | nathan7 | I write my stuff using the pure functions |
| 22:53 | gfixler | You didn't reimplement Clojure's shared structure stuff, did you? |
| 22:53 | nathan7 | I did not |
| 22:53 | gfixler | phwew |
| 22:53 | nathan7 | it's a naive copy |
| 22:53 | gfixler | that would be crazy |
| 22:53 | nathan7 | there's a lib, mori, that just re-exports all ClojureScript's stuff to JSland |
| 22:54 | nathan7 | but I want to work with just raw JS objects because mori is giant |
| 22:54 | nathan7 | once I'm done writing my logic |
| 22:54 | nathan7 | I go through my code and look at where state enters and leaves |
| 22:54 | gfixler | Ah, swannodette, I should've known |
| 22:54 | gfixler | that guy is brilliant |
| 22:54 | nathan7 | and append an M to function calls |
| 22:55 | nathan7 | like, same thing you'd do in Clojure with transients |
| 22:55 | gfixler | I haven't heard of transients yet |
| 22:55 | gfixler | Well, I guess that's now technically untrue |
| 22:56 | nathan7 | so, Clojure data structures are like all structure-sharing and stuff, so creating new ones instead of mutating in-place is fast |
| 22:56 | nathan7 | but if you're doing, say, group-by, and just modifying the same hashmap a hundred times, you're creating a hundred objects and letting them be GC'd again |
| 22:57 | nathan7 | so instead, you do (transient {}), and use assoc! instead of assoc |
| 22:57 | nathan7 | and get an object that actually mutates in-place |
| 22:57 | gfixler | got it |
| 22:57 | nathan7 | they implement IEditableCollection |
| 22:58 | nathan7 | so, assoc! returns a new transient, and marks the old one as being unusable (every operation on it throws, I think), and you pass them around inside your function the same way you'd do otherwise |
| 22:58 | gfixler | interesting |
| 22:58 | nathan7 | and when you're done with it, you call persistent! and it turns it into a regular hashmap |
| 22:59 | gfixler | sweet - I just found this possibly related thing tonight: http://z.caudate.me/you-took-3-months-to-write-a-mutable-array/ |
| 22:59 | nathan7 | like, check (source group-by) in your REPL |
| 23:00 | nathan7 | gfixler: like, mutable state creates huge trouble for applications |
| 23:00 | nathan7 | gfixler: but functions mutating something internally, not externally visible -> "if a tree falls in a forest, and nobody is around to hear it" |
| 23:01 | nathan7 | -> if a function mutates a structure internally, and nobody's around to see it |
| 23:01 | gfixler | Right, as with loop invariants |
| 23:01 | gfixler | things are free to change inside the loop, but must be stable at the start and end of each iteration |
| 23:01 | nathan7 | Yep. |
| 23:07 | dbasch | nathan7: I don't think that's correct (assoc! may return the same object, although there are no guarantees) |
| 23:25 | nathan7 | dbasch: oh? |
| 23:25 | nathan7 | dbasch: hmm, yes |
| 23:26 | dbasch | e.g. |
| 23:26 | dbasch | ,(let [a (transient {})] (= a (assoc! a :b :c))) |
| 23:26 | clojurebot | true |
| 23:28 | nathan7 | dbasch: identical? would be more clear, but yeah |
| 23:28 | nathan7 | (I'm aware transients don't do actual deep equality) |
| 23:29 | dbasch | ,(let [a (transient {})] (identical? a (assoc! a :b :c))) |
| 23:29 | clojurebot | true |
| 23:32 | dbasch | nathan7: other than that, I like your explanation |
| 23:33 | nathan7 | dbasch: I basically pull the same tricks in JS |
| 23:34 | nathan7 | dbasch: like, perform escape analysis in your head, add some M's in places |
| 23:37 | nathan7 | dbasch: I'm a compiler nerd (though a fairly half-assed one), so I spend a lot of time thinking about this kind of thing |
| 23:38 | nathan7 | dbasch: I have a pile of notes on a fully-refcounted language, where every heap object has an atomic refcounter |
| 23:38 | nathan7 | dbasch: and then using that to mutate objects in place opportunistically |
| 23:39 | nathan7 | dbasch: and avoiding a lot of allocation using this |
| 23:39 | nathan7 | dbasch: and smart ahead-of-time escape analysis style trickery to do even more magic like this |
| 23:40 | dbasch | sounds cool, but at the same time a lot of work |
| 23:41 | nathan7 | like, every time I have to think about this, I go scribble in my notes for a bit on how the compiler could do it for me |
| 23:41 | nathan7 | a lot of abstractions can be zero-cost |
| 23:43 | nathan7 | and all of these things are incremental — you have a little more information on how the program works, the compiler can do a bunch more |
| 23:43 | nathan7 | like, a system I admire very much is ZFS, which has this magical property too |
| 23:43 | nathan7 | you throw more hardware at it, and it magically becomes faster, in ways that are actually really intelligent, but a lot of it is emergent behaviour |
| 23:44 | nathan7 | I haven't found a word or a good way to describe this concept |
| 23:45 | nathan7 | lisps are helping me a lot in this, because in a hundred lines of code I can build another lisp |
| 23:45 | nathan7 | and in like, maybe two hundred lines I can do it in any nice language |
| 23:46 | nathan7 | so I can build entire languages around single concepts very quickly |
| 23:46 | nathan7 | and each time I understand more, and my understanding becomes more abstract |
| 23:47 | dbasch | reminds me of this: http://www.buildyourownlisp.com/ |
| 23:47 | nathan7 | yeah, I saw that |
| 23:47 | nathan7 | I still want to build one in Rust so I can do stuff like the refcounting lang |
| 23:48 | nathan7 | but I have several implementations of my f-expr lisp which are all cool in their own way |
| 23:48 | nathan7 | the one issue I have with writing lisps in lisps is that the lines are blurred easily |
| 23:48 | nathan7 | I have an implementation of my fexpr lisp, Plan, in Clojure |
| 23:49 | nathan7 | and I'm very confused about how it actually works now because I have a hard time telling what is my stuff, and how it works with Clojure stuff |
| 23:50 | nathan7 | because I'm doing a lot of voodoo that unites the worlds of Clojure and Plan |
| 23:50 | nathan7 | and I don't actually have debugging tools at all |
| 23:50 | nathan7 | so I have a null pointer exception somewhere that I can't really debug |
| 23:51 | nathan7 | and my mental model of it all is very murky |
| 23:56 | nathan7 | dbasch: maybe I should actually follow the buildyourownlisp sometime, but in Rust |
| 23:56 | dbasch | I guess it shouldn't be that hard to do it in Go either |
| 23:57 | nathan7 | Yeah, I have a very strong dislike of Go |
| 23:58 | nathan7 | bnoordhuis (possibly drunkenly) perfectly described it as the language that "missed the last 20 years of computer science" |
| 23:58 | dbasch | to me it's just another language, neither here nor there |
| 23:58 | nathan7 | it's neither here nor there indeed |
| 23:58 | serjeem | it makes me sad that in TYOOL 2014 they're still putting out non-polymorphic typed languages |
| 23:59 | nathan7 | elaborate |
| 23:59 | nathan7 | oh, nvm, makes sense now |