2015-05-21
| 00:07 | WickedShell | When calling a java object from clojure will the java object update its internal state correctly and retain the same reference from clojure? |
| 00:21 | andyf | WickedShell: The Java object will update its internal state the same way it would if the method were called from Java. |
| 00:22 | andyf | Not sure what you mean by 'retain the same reference from Clojure'. Any reference you have to the object in Java or Clojure code will still be a reference to that object after the method call. |
| 00:42 | WickedShell | andyf, it's possible I'm tripping over my own feet here, all I could think of to explain the behavior I'm seeing (calling a function that updates the internal state will never seem to update) might be a different problem though |
| 00:43 | andyf | Is it a tiny example, or something that is easily demonstrated? |
| 00:44 | andyf | Also, do you know for a fact that the Java method is being called from the Clojure code? |
| 00:44 | andyf | laziness in Clojure can make you think some code should be executed, but it is not until later, or never. |
| 00:45 | WickedShell | running the code from the repl, so I'm pretty sure it is, but the only indication is the return value not being null after having been updated with enough bytes |
| 00:47 | andyf | are their methods on the Java object that can show you some of its internal state that should be changing? |
| 00:47 | andyf | s/their/there/ |
| 00:49 | WickedShell | andyf, http://pastebin.com/m9dANmCw the first bit is some hacked together clojure, where the doseq only ever prints nil rather then returning an object, and then the java code that works on the same java code is below (which works) |
| 00:49 | WickedShell | totally believe I'm doing something wrong |
| 00:50 | andyf | mavlink_parse_char should be called with a sequence of bytes, or a sequence of characters? |
| 00:51 | WickedShell | bytes, although it actually takes an int as the argument |
| 00:51 | andyf | I guess the Java code calling those methods that you pasted is working as desired? |
| 00:51 | WickedShell | yeah that java code works correctly, so I believe I'm doing something wrong in clojure |
| 00:53 | andyf | What value does the .read call return? |
| 00:54 | WickedShell | the buffer is filled with bytes from the file |
| 00:54 | andyf | so it returns 1024? |
| 00:55 | WickedShell | yeah |
| 00:56 | andyf | Does the Java version get a non-null return value from mavlink_parse_char method in the first 1024 bytes? |
| 00:57 | andyf | I don't see in your paste how you initialized mavParse in Clojure code. |
| 01:00 | WickedShell | oops initilized it in the repl it was (def mavParse (Parser.)) |
| 01:02 | andyf | that looks like it matches the Java init. Do you know how many times the Java version calls mavlink_parse_char before it returns a non-null value? If it is more than 1024, then the Clojure code you have shown will not get far enough. |
| 01:02 | andyf | You could change 1024 to a larger number if that is the case. |
| 01:03 | andyf | Or write a loop that keeps calling mavlink_parse_char until it returns a non-null value, or the end of file is reached. |
| 01:03 | andyf | I do not see anything wrong with the Clojure code you have tried, though. |
| 01:04 | WickedShell | There are 27 in the first 1024 bytes |
| 01:04 | WickedShell | I'm wondering if I'm gettting a different implicit conversion between the two |
| 01:05 | WickedShell | IE if I (println x) in the clojure code I get values within +/-127 while java System.ou.println(tlog.read()) gives me a range of 0-255 so I'm wodnering if thats the cause |
| 01:06 | andyf | The Java code is calling the method read that returns one int at a time, rather than a whole array of bytes. |
| 01:06 | andyf | Maybe the int values returned by the read() method return ints in the range 0..255 ? |
| 01:08 | andyf | I haven't run across that behavior with Java's FileInputStream class before, but it may be how it has worked for a long time. Seem strange to me, if that is how read() works. |
| 01:08 | andyf | If so, I bet changing the Java code to read bytes into a byte array would have the same problem your Clojure code does. |
| 01:08 | WickedShell | java returns an int or -1 on an empty file so that may be the issue ( https://docs.oracle.com/javase/7/docs/api/java/io/FileInputStream.html#read() ) |
| 01:09 | andyf | Yeah, use the read method that returns an int from your Clojure code, and I bet you get matching results in Clojure. |
| 01:10 | andyf | If you really want to use a byte buffer for some reason (e.g. maybe it gets better efficiency), you'll need to loop through only the portion of the buffer that actually gets filled by the read(byte[]) method, and convert each value -128..127 to 0..255 before passing to mavlink_parse_char |
| 01:11 | andyf | that issue is not Clojure-specific, though -- just the way the Java methods work. |
| 01:14 | WickedShell | derp, your right (and there isn't much of a gain with the buffer (and really once I got past prototyping on the file stream it turns into a network stream later) |
| 01:14 | WickedShell | thanks for the help |
| 01:21 | andyf | no problem |
| 01:25 | iamjarvo | http://pastie.org/private/6ekv5mneapz0xkemnxwuw this syntax should work right? |
| 01:59 | andyf | iamjarvo: looks correct |
| 02:30 | WickedShell | I think I'm missing something obvious, but how do I import multiple java classes? (the equivelent of import com.Package.* in java?) (I need 100+ java classes imported and don't want to type all the names in) |
| 02:30 | justin_smith | WickedShell: you can't |
| 02:31 | WickedShell | oh... that's... painful :/ I guess I'ma go write a generator to make me all the import statements then |
| 02:32 | justin_smith | the closest is (import '[com.foo Bar Baz ...]) but you still need to type each class out, you just don't need to repeat the package that way |
| 02:35 | WickedShell | I'm in slight shock at that still, not sure why just really surprised |
| 02:36 | justin_smith | Clojure is very opinionated about things being bound explicitly, in this case arguably to an extreme. |
| 02:36 | justin_smith | the plus side is you can almost always directly and clearly see where any given thing came from |
| 02:37 | WickedShell | I mean it makes sense, the problem in this case is that I'm using a library to decode a packed strucutre and the library puts each subtype of message in it's own class so I have something like 100+ classes to import |
| 02:38 | justin_smith | what about just using each one complete with package prefix instead of importing? I guess that's verbose, but it works. |
| 02:38 | justin_smith | or, of course, a macro |
| 02:39 | WickedShell | ie whenever referencing it use (com/package/class/method foo) everywhere? |
| 02:39 | justin_smith | the methods are not prefixed |
| 02:39 | justin_smith | it would be (let [instance (com.package.Class.)] (.method instance)) |
| 02:40 | justin_smith | unless you are talking about static methods |
| 02:40 | justin_smith | that would be (com.package.class/method foo) |
| 02:41 | justin_smith | it's ugly, probably not a desirable alternative |
| 02:41 | WickedShell | its actually all just pulling public fields for the most part, with some methods |
| 02:41 | justin_smith | then (.accessor instance) |
| 02:42 | justin_smith | and the instance creation would be the part to either import or explicitly prefix |
| 02:50 | TEttinger | ooh ooh ooh my macro could be handy here! |
| 02:53 | WickedShell | tettinger oohh for imports/package type problems? |
| 02:54 | TEttinger | yah, I'm trying to find it |
| 02:54 | TEttinger | really it just lets you alias java packages |
| 02:56 | TEttinger | ,(defmacro import-alias [new-name imported] `(defmacro ~new-name [f# & body#] `(. ~'~imported ~f# ~@body#))) |
| 02:56 | clojurebot | #'sandbox/import-alias |
| 02:56 | TEttinger | ,(import-alias ju java.util) |
| 02:56 | clojurebot | #'sandbox/ju |
| 02:57 | TEttinger | ,(ju HashMap.) |
| 02:57 | clojurebot | #error {\n :cause "java.util"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: java.util, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6740]}\n {:type java.lang.ClassNotFoundException\n :message "java.util"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net... |
| 02:57 | TEttinger | kinda expecting that |
| 02:58 | TEttinger | ah, this was for changing the name of a class, not a package. still, could be altered |
| 03:28 | TEttinger | wow, it looks like try/catch won't actually catch class not found exceptions |
| 03:28 | TEttinger | can't test with clojurebot, since clojurebot doesn't allow try/catch |
| 03:31 | opqdonut | the problem is probably that the exception is in the runtime and not in your code |
| 03:33 | opqdonut | user=> (try (throw (ClassNotFoundException.)) (catch ClassNotFoundException e (prn :SUCCESS))) |
| 03:33 | opqdonut | :SUCCESS |
| 03:36 | te | !see ordnungswidrig, |
| 03:36 | te | !seen ordnungswidrig, |
| 03:36 | ordnungswidrig | te: poong |
| 03:39 | te | ordnungswidrig, thx for liberator, currently i' |
| 03:44 | te | ordnungswidrig, thx for liberator, currently i'm working on extending compojure-api (swagger) so it works better with defresource. I would like to inject a schema validation function into a liberator handler just before the body is is encoded into a representation (eg json) whats the best handler? for this purpose. For request's body I'm using the Malformed? key. |
| 03:46 | ordnungswidrig | re |
| 03:52 | te | ordnungswidrig, do you have any suggestions for the best place to inject a validation function of the response body ? |
| 03:53 | ordnungswidrig | te: what shall happen if the validation fails? |
| 03:55 | te | probably return an status code (eg. 500) or optionally log it (and then return the 'falsy' data) |
| 04:01 | ordnungswidrig | te: I think the best way would be to use a custom `as-response` function that throws an exception. handle-exception can handle that exception. |
| 04:03 | ordnungswidrig | te: wait, if as-response throws and exception it's too late for handle-exception, you need to use some ring middle to handle that exception |
| 04:04 | te | thx :) |
| 04:04 | ordnungswidrig | te: or you wrap handle the handlers with a validation function that returns a 500 status using ring-response. |
| 04:34 | H4ns | i often use reduce in a fashion where based on some condition, i need to add something to the result, and if the condition or conditions don't hold, just keep the result. this often leads to unpleasant repetition of the unmodified result. is there a common idiom to deal with that? |
| 04:35 | H4ns | i could wrap my reduction function with #(or (handle %1 %2) %1), but i somehow suspect that this is not the best or most idomatic way |
| 04:36 | oddcully | filter beforehand? |
| 04:39 | H4ns | not really, no - i need to process each element and accumulate if the processing yielded a non-nil result |
| 04:40 | H4ns | i now have (reduce #(if-let [result (process %2)] (conj %1 result) %1) [] seq-of-elements) |
| 04:40 | H4ns | but i don't like it too much |
| 04:41 | H4ns | i could say (mapv (filter nil? (map process seq-of-elements))) of course |
| 04:42 | amalloy | ,(doc keep) |
| 04:42 | clojurebot | "([f] [f coll]); Returns a lazy sequence of the non-nil results of (f item). Note, this means false return values will be included. f must be free of side-effects. Returns a transducer when no collection is provided." |
| 04:43 | H4ns | amalloy: that is it, thanks! |
| 04:43 | amalloy | H4ns: honestly your reduce is literally just an implementation of filter, though. i'm unclear on why you can't just use filter |
| 04:44 | H4ns | amalloy: i'm interested in the values after processing the elements. |
| 04:44 | amalloy | right, that's a map |
| 04:45 | H4ns | keep is great, though. thanks! |
| 06:38 | entity | I want to iterate over a function that takes multiple arguments |
| 06:38 | entity | what's the standard way to do this? Apperantly I can't use a list as a tuple |
| 06:39 | entity | I was thinking I make the argument a tuple, but it's impossible to pattern-match on a list |
| 06:44 | TEttinger | entity: I'm not qyite sure what you mean here |
| 06:44 | TEttinger | iterate over a collection? using a fn that takes 2 args at a time? would be reduce |
| 06:45 | entity | ,(iterate inc 1) |
| 06:45 | clojurebot | (1 2 3 4 5 ...) |
| 06:45 | TEttinger | oh that one |
| 06:45 | entity | so what if inv takes multiple args? |
| 06:45 | entity | inc* |
| 06:45 | TEttinger | does it take & args or does it take a fixed number over 1 args? |
| 06:46 | entity | it takes 3 args |
| 06:46 | entity | then returns 3 again to serve as input for the next iteration |
| 06:46 | entity | at least that was the plan |
| 06:46 | TEttinger | well returning 3 args isn't actually possible. you would return a sequence of args |
| 06:47 | TEttinger | let's see... |
| 06:48 | TEttinger | ,(defn tritri [args] (mapv (partial * 3) args)) |
| 06:48 | clojurebot | #'sandbox/tritri |
| 06:48 | TEttinger | ,(take 4 (iterate tritri [1 2 3])) |
| 06:48 | clojurebot | ([1 2 3] [3 6 9] [9 18 27] [27 54 81]) |
| 06:48 | TEttinger | if you have a function that takes 3 args already, |
| 06:49 | TEttinger | ,(defn tritri [x y z] (mapv (partial * 3) [x y z])) |
| 06:49 | clojurebot | #'sandbox/tritri |
| 06:49 | TEttinger | ,(take 4 (apply iterate (comp tritri vector) [1 2 3])) |
| 06:49 | clojurebot | #error {\n :cause "Wrong number of args (4) passed to: core/iterate"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (4) passed to: core/iterate"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.AFn invoke "AFn.java" 44]\n [clojure.lang.AFn applyToHelper "AFn.java" 165]\n [clojure.lang... |
| 06:50 | TEttinger | ,(take 4 (iterate (partial apply tritri) [1 2 3])) |
| 06:50 | clojurebot | ([1 2 3] [3 6 9] [9 18 27] [27 54 81]) |
| 06:50 | TEttinger | there we go |
| 06:50 | TEttinger | entity, did any of that make sense? |
| 06:51 | TMA | ,(take 4 (iterate (comp tritri vector) [1 2 3])) |
| 06:51 | clojurebot | #<ArityException clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox/tritri> |
| 06:51 | TEttinger | pretty much, fns in clojure have only one return value, which can be a collection |
| 06:51 | TMA | (doc comp) |
| 06:51 | clojurebot | "([] [f] [f g] [f g & fs]); Takes a set of functions and returns a fn that is the composition of those fns. The returned fn takes a variable number of args, applies the rightmost of fns to the args, the next fn (right-to-left) to the result, etc." |
| 06:52 | TEttinger | comp isn't the right tool here, I realized |
| 06:52 | TEttinger | since you need to take a collection and turn it into separate args |
| 06:52 | TEttinger | (which is what apply does) |
| 06:53 | entity | alright, I think I got it |
| 06:53 | entity | thanks a lot |
| 06:53 | TEttinger | cool, no prob |
| 06:54 | TMA | ,((comp) 1 2 3) |
| 06:54 | clojurebot | #error {\n :cause "Wrong number of args (3) passed to: core/identity"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (3) passed to: core/identity"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.AFn invoke "AFn.java" 40]\n [sandbox$eval213 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.C... |
| 06:59 | oddcully | (inc TEttinger) |
| 06:59 | lazybot | ⇒ 55 |
| 06:59 | TEttinger | thanks! |
| 07:03 | TMA | ,(defn comp-- ([] identity) ([f] f) ([f & gs] (fn [& a] (f (apply (apply comp-- gs) a))))) |
| 07:03 | clojurebot | #'sandbox/comp-- |
| 07:04 | TMA | ,(comp--) |
| 07:04 | clojurebot | #object[clojure.core$identity 0x55769723 "clojure.core$identity@55769723"] |
| 07:04 | TMA | ,(comp-- comp--) |
| 07:04 | clojurebot | #object[sandbox$comp__ 0x7c7bdd9 "sandbox$comp__@7c7bdd9"] |
| 07:04 | TMA | ,((comp-- inc inc) 0) |
| 07:04 | clojurebot | 2 |
| 07:04 | TMA | ,((comp-- inc inc inc) 0) |
| 07:04 | clojurebot | 3 |
| 07:29 | noncom | hello! i'd be glad if annyone can suggest a solution: https://groups.google.com/forum/#!topic/clojure/dY4AmXCDnxw |
| 07:36 | donbonifacio | how can I do a (if (empty-atom?) (swap...) (deref atom)) atomically? |
| 07:38 | hyPiRion | donbonifacio: what is the function `empty-atom?` doing? Does it take the atom as a parameter? |
| 07:38 | donbonifacio | yes, it derefs the atom to check if it has something |
| 07:39 | hyPiRion | donbonifacio: (swap! atom (fn [content] (if (empty? content) content (do-stuff-on content)))) |
| 07:40 | donbonifacio | ah, nice, thanks hyPiRion |
| 07:40 | hyPiRion | np |
| 08:16 | crocket | How can I make a list reader form do nothing? |
| 08:19 | crocket | Hello? |
| 08:20 | gfredericks | crocket: hello |
| 08:21 | gfredericks | crocket: I'm not sure what your question means |
| 08:21 | crocket | (+ 1 2 (+ 1 2)<--ignore this) |
| 08:22 | gfredericks | ,(+ 1 2 #_ (+ 1 2)) |
| 08:22 | hyPiRion | (+ 1 2 #_(+ 1 3)) |
| 08:22 | clojurebot | 3 |
| 08:22 | crocket | Ah yes |
| 08:22 | crocket | #_ |
| 08:22 | crocket | The joy of #_ |
| 09:04 | kaiyin | could anyone help with this? http://stackoverflow.com/questions/30374620/unbound-fn-error-while-function-is-declared-and-defined |
| 09:16 | noncom | kaiyin: it has nothing to do with arity. for some mysterious reason, this kind of error always comes up from that throwArity thing... idk :) |
| 09:17 | noncom | kaiyin: as for your problem - you're calling the function before it is being defined |
| 09:18 | noncom | kaiyin: as a solution - place the declaration before the call. if this is not possible due to a dependency among fns, then, as a workaround, - add (declare new-board) top form somewhere before your first call to the function |
| 09:19 | kaiyin | ok |
| 09:19 | noncom | noncom: also, as the commenters have pointed out, there is some mess with namespaces.. |
| 09:24 | kaiyin | yeah, there is, I move the code a round a bit. |
| 09:24 | crocket | How do I solve http://www.4clojure.com/problem/134 ? |
| 09:26 | i-blis | crocket: contains? ? |
| 09:28 | crocket | #(and (contains? %2 %1) (= nil (%1 %2))) solves http://www.4clojure.com/problem/134 |
| 09:29 | i-blis | crocket: nil? on get with non-nil default value works too |
| 09:31 | crocket | i-blis, like #(nil? (get %2 %1 :not-found))? |
| 09:31 | i-blis | crocket: for instance (i like the :not-found, more readable than false or whatever) |
| 10:27 | entity | ,(map inc [1 2 3]) |
| 10:27 | clojurebot | (2 3 4) |
| 10:27 | entity | hm, why does that return a list and not a vector? |
| 10:28 | matthavener | entity: it returns a seq |
| 10:28 | matthavener | if you want a vector you can use mapv |
| 10:28 | entity | ah, nice |
| 10:28 | entity | thanks |
| 10:28 | matthavener | sure |
| 11:12 | justin_smith | entity: most clojure functions do not preserve the type of their input |
| 11:12 | justin_smith | entity: one trick though is (into (empty c) (map f c)) |
| 11:12 | justin_smith | which gets the order funky for lists, but preserves type |
| 11:14 | justin_smith | ,(defn finc [c] (into (empty c) (map inc c))) |
| 11:14 | clojurebot | #'sandbox/finc |
| 11:14 | justin_smith | (finc #{1 2 3}) |
| 11:14 | justin_smith | ,(finc #{1 2 3}) |
| 11:14 | clojurebot | #{4 3 2} |
| 11:14 | justin_smith | ,(finc '(1 2 3)) |
| 11:14 | clojurebot | (4 3 2) |
| 11:14 | justin_smith | ,(finc [1 2 3]) |
| 11:14 | clojurebot | [2 3 4] |
| 11:29 | entity | justin_smith: thanks, good to know that |
| 11:44 | puredanger | justin_smith: see http://clojure.github.io/algo.generic/clojure.algo.generic.functor-api.html#clojure.algo.generic.functor/fmap for that :) |
| 11:45 | justin_smith | puredanger: I did name that silly function finc for a reason, thanks |
| 11:45 | puredanger | although really I'd just recommend using transducers now for that |
| 11:45 | puredanger | ,(into [] (map inc) [1 2 3]) |
| 11:45 | clojurebot | [2 3 4] |
| 11:45 | puredanger | ,(into #{} (map inc) #{1 2 3}) |
| 11:45 | clojurebot | #{4 3 2} |
| 11:46 | justin_smith | ,(into () (map inc) '(1 2 3)) |
| 11:46 | clojurebot | (4 3 2) |
| 11:46 | puredanger | transducers separate input source from transformation from output target and let you make those decisions separately |
| 11:47 | justin_smith | (inc puredanger) |
| 11:47 | lazybot | ⇒ 56 |
| 12:28 | andyf | puredanger: No open issues for Clojure 1.7.0. Congrats! (Not to say that none will arise, but IT'S CLOSE!) |
| 12:28 | puredanger | I'm shutting down jira |
| 12:29 | puredanger | :) |
| 12:29 | andyf | NO! All those hours of work. |
| 12:29 | puredanger | rc1 is in the chute |
| 12:30 | andyf | puredanger: Are you part bulldog, by any chance? :) |
| 12:30 | andyf | (referring to the persistence bordering on stubbornness that it takes to get these things through, not your anatomy) |
| 12:31 | justin_smith | andyf: I often tell people who are interested in learning to program that stubbornness is the main required trait. |
| 12:32 | andyf | So many words with different connotations, e.g. stubborn / persistent |
| 12:33 | TEttinger | justin_smith yeah, agreed |
| 12:33 | TEttinger | the willingness to keep at a seemingly impossible problem until it clicks |
| 12:34 | wink | or until someone releases the bugfix |
| 12:34 | justin_smith | heh |
| 12:34 | wasamasa | TEttinger: that's how I feel all the time now that I'm learning frontend development with om |
| 12:34 | wasamasa | it's just so different ._. |
| 12:34 | wink | no seriously, no matter how full stack you are - at some point it's a kernel/fs/firmware issue :P |
| 12:34 | TEttinger | or even hardware |
| 12:35 | TMA | that's not stubborness, that's perseverance |
| 12:35 | TEttinger | maybe your thing works on intel but not AMD CPUs! |
| 12:35 | wink | TEttinger: yes, but then it's called replacement and not fix :P |
| 12:35 | TEttinger | not necessarily |
| 12:35 | TEttinger | if you're releasing code that only works on some end users' machines, it needs a fix :) |
| 12:36 | TEttinger | thankfully, JVM helps a lot there |
| 12:36 | puredanger | Clojure 1.7.0-RC1 is out https://groups.google.com/forum/#!msg/clojure/ccZuKTYKDPc/xpaz44UDqYwJ |
| 12:36 | TEttinger | woo puredanger! |
| 12:36 | TEttinger | (inc puredanger) |
| 12:36 | lazybot | ⇒ 57 |
| 12:36 | TEttinger | (inc clojure) |
| 12:36 | lazybot | ⇒ 23 |
| 12:37 | puredanger | now everyone go try it and tell me it's great so we can release it |
| 12:40 | TEttinger | is it on clojars or maven central yet? |
| 12:40 | puredanger | Maven central |
| 12:41 | justin_smith | TEttinger: I don't think clojure.core ever canonically ends up in clojars? |
| 12:42 | TEttinger | yah, you're right |
| 12:44 | puredanger | correct |
| 12:50 | justin_smith | TEttinger: another good one is a very firm sense of the importance of minor distinctions :) |
| 12:50 | TEttinger | pedantic mode |
| 12:50 | arrdem | -Wpendantic |
| 12:51 | arrdem | were transients new in 1.6? I forget... |
| 12:51 | arrdem | I don't think they were 1.4 |
| 12:51 | Bronsa | 1.2 or earlier |
| 12:52 | arrdem | thanks Bronsa |
| 12:52 | Bronsa | ,(-> #'transient meta :added) |
| 12:52 | clojurebot | "1.1" |
| 12:57 | puredanger | Props to Stu H for screening tickets and releasing RC1 on his birthday :) |
| 13:03 | ionthas | Hei! Is there any way to remove the first element of a vector? I'm using (pop (vector 1 2 3)) but that it's not what I want. |
| 13:03 | Bronsa | (inc puredanger) |
| 13:03 | lazybot | ⇒ 58 |
| 13:04 | Bronsa | ionthas: not efficiently, you should use a list for that |
| 13:04 | Bronsa | ionthas: you can get a subvector in constant time but the elemnts you're not accessing will stay in memory |
| 13:05 | ionthas | mmm... I'm trying to program a genetic algorithm using lists instead of vectors will affect the performance in any way? |
| 13:07 | TEttinger | ionthas, short answer yes |
| 13:07 | TEttinger | but not predictably in general |
| 13:07 | puredanger | You might want something like finger trees instead |
| 13:07 | TEttinger | there's a reason clojure has both |
| 13:08 | TEttinger | you may, if you don't specifically want persistent immutable behavior, find a java collection useful |
| 13:10 | ionthas | thanks! I will look at them. |
| 13:17 | TEttinger | http://b010.blogspot.com/2009/05/speed-comparison-of-1-javas-built-in.html not sure how relevant this is 6 years later |
| 13:18 | TEttinger | incanter includes the lib that performed best there https://github.com/incanter/incanter |
| 13:18 | TEttinger | also incanter should be much easier to use from clojure |
| 13:20 | iamjarvo | so i am trying to use environ and it seems like ":plugins [[lein-environ "1.0.0"]]" that is definitely needed but the instructions say "If you want to be able to draw settings from the Leiningen project map, you'll also need the following plugin:" am i doing something wrong? it's in a fresh lein app. i was getting CompilerException java.lang.Exception: namespace 'environ.core' not found, compiling: |
| 13:21 | ionthas | TEttinger: I didn't know that lib, I will look at it. thanks! |
| 13:22 | TEttinger | iamjarvo: it may be needed in profile. I do not know what environ is. |
| 13:45 | puredanger | I think you can also just hack the .lein-environ file too |
| 13:47 | puredanger | You might also look at immuconf |
| 14:13 | andyf | gfredericks: Not sure if you are interested in dynalint still, but I've got a fork with some enhancements & better docs you may be interested to try out: https://github.com/jafingerhut/dynalint |
| 14:13 | andyf | You have to 'lein install' it yourself. Not released as a JAR anywhere yet. |
| 14:42 | TimMc | puredanger: There's one problem I'm seeing upgrading from 1.6 to 1.7 that could be a Clojure thing or could be a classpath thing. |
| 14:43 | TimMc | Probably the latter, but I don't have a lot of time to debug it right now to be sure. :-( |
| 14:48 | gfredericks | andyf: cool, thanks -- are you trying to get that merged back to the main project? |
| 14:50 | TimMc | (clj-http.util/url-encode is yelling about not being called with the right arity even though it is definitely being called with the right one -- and calling source on it from the REPL gives the wrong line. *Probably* classpath or build tool issues...) |
| 14:55 | TimMc | I wish there was a way to quickly bisect a code base to create SSCCEs. |
| 15:02 | andyf | gfredericks: Definitely. I'm just being impatient by mentioning it more widely before that happens :) |
| 15:03 | puredanger | TimMc: sounds like your env to me but let me know |
| 15:04 | TimMc | If it's clj it would have to be a classloader thing. |
| 15:06 | Bronsa | TimMc: the classloader doesn't change a var's arity :) |
| 15:07 | TimMc | AOT! |
| 15:10 | TimMc | We have an AOT'd library that depends on clj-http and the main project also depends on it... but of a different version. |
| 15:11 | Bronsa | ah, that changed in 1.7 then, yeah |
| 15:11 | puredanger | what changed? |
| 15:12 | Bronsa | puredanger: 1.6 loaded AOT first, 1.7 loads clj first if clj is newer than AOT |
| 15:13 | Bronsa | so if TimMc has both a jit and an aot version of the same library in its classpath, it could behave differently |
| 15:13 | clojurebot | Excuse me? |
| 15:13 | puredanger | gotcha |
| 15:13 | TimMc | So... both answers are right, then. :-( |
| 15:14 | puredanger | can you exclude the version you don't want in your deps? |
| 15:14 | Bronsa | puredanger: I believe he's having the same issue core.typed had -- one of its deps is distributing an AOT version of another lib |
| 15:15 | puredanger | yeah |
| 15:15 | puredanger | (did we ever fix that for core.typed? I know I looked at it but I can't remember now.) |
| 15:15 | Bronsa | puredanger: yeah I saw ambrose close the ticket days ago |
| 15:16 | Bronsa | or weeks -- I'm not good with time :P |
| 15:18 | Bronsa | https://github.com/clojure/core.typed/commit/e0f9bb33e37503f4ab51a4af61abaa2f63442b35 |
| 15:20 | TimMc | Is there a generic solution to this? |
| 15:21 | puredanger | don't do that? |
| 15:22 | Bronsa | probably the transitive AOT stuff will help |
| 15:22 | puredanger | I don't know enough about your classpath to understand exactly what to suggest |
| 15:23 | TimMc | puredanger: It's a library that we AOT so Java consumers can use it, but when Clojure consumers use it, things get gross. |
| 15:24 | TimMc | Bronsa: Ooh, do tell. |
| 15:24 | puredanger | Bronsa: you mean CLJ-322? |
| 15:24 | Bronsa | TimMc: well the ticket is still open and AFAIK no decision has been made so it can't really help you right now |
| 15:24 | puredanger | (also kinda worried that I didn't have to look up that #) |
| 15:24 | Bronsa | puredanger: yeah |
| 15:25 | TimMc | Aw, I thought you were implying something was on the way. |
| 15:25 | puredanger | TimMc: are the Clojure consumers using the AOT or the non-AOT? |
| 15:25 | TimMc | AOT. We only produce one artifact. |
| 15:25 | puredanger | so where does the non-AOT version come in? |
| 15:26 | Bronsa | puredanger: heh, I spend way less time than you do spelunking tickets in jira and have a number of tickets memorized too |
| 15:27 | TimMc | puredanger: It doesn't, I think there's a misunderstanding. Library A is AOT'd, app B uses library A, both use clj-http. |
| 15:27 | Bronsa | puredanger: TimMc I thought about that ticket because this problem currently arises in clojure since there's no way to AOT library code and not deps code. |
| 15:27 | puredanger | does A happen to also include an AOT'ed version of clj-http? |
| 15:27 | TimMc | puredanger: Yes, exactly. |
| 15:27 | Bronsa | TimMc: just exclude clj-http so it doesn't get pulled in. you'll use the AOT version included in A |
| 15:27 | puredanger | ah |
| 15:28 | TimMc | Bronsa: Each consumer of lib A has to do this, yes? Transitively? |
| 15:28 | puredanger | well I think the problem is that A includes AOT'ed deps |
| 15:28 | Bronsa | TimMc: dunno |
| 15:28 | puredanger | A's jar should include... A |
| 15:29 | TimMc | That's difficult with current tooling. :-( |
| 15:29 | Bronsa | puredanger: yeah but if we want to be honest the problem is that clojure has no way to avoid AOT compiling deps |
| 15:29 | puredanger | I hear ya |
| 15:30 | puredanger | TimMc: leiningen I presume? |
| 15:30 | TimMc | yeah |
| 15:31 | puredanger | so this is CLJ-322 as Bronsa said |
| 15:32 | TimMc | One approach would be to construct a compilation boundary around the core of lib A such that only the very outer interface is AOT'd and the rest is loaded dynamically. |
| 15:32 | TimMc | Easy to do with an app (a la lein-otf), harder to do with a lib. |
| 15:32 | Bronsa | TimMc: hacky solution is to JIT load all deps before AOT compilation starts |
| 15:33 | sorbo_ | I'm trying to accomplish what this SO user is looking for: http://stackoverflow.com/questions/16320739/merge-with-merge-can-this-be-simplified |
| 15:33 | Bronsa | TimMc: super hacky solution is to do that in user.clj |
| 15:33 | puredanger | bleh |
| 15:33 | Bronsa | don't judge me |
| 15:33 | sorbo_ | but his/her `(val ...)` solution doesn't seem to work (ClassCastException user$eval803$fn__804 cannot be cast to clojure.lang.IPersistentCollection) |
| 15:33 | sorbo_ | and I can't use the accepted solution because my keys are not contiguous |
| 15:33 | TimMc | Bronsa: "JIT load all deps before AOT compilation starts", how would this work? |
| 15:34 | sorbo_ | anyone successfully done a (merge-with merge) to selectively merge a vector of maps? |
| 15:34 | puredanger | Bronsa: I'm not. not your fault... :) |
| 15:36 | puredanger | I have done a few builds where we post-processed to filter just things we wanted in the AOT jar |
| 15:36 | puredanger | definitely works, also definitely annoying |
| 15:37 | TimMc | sorbo_: Sort by id first? |
| 15:37 | sorbo_ | TimMc: then they'll increase monotonically, but they won't be contiguous (there'll be gaps) |
| 15:37 | sorbo_ | will that still work with partition-by? |
| 15:38 | Bronsa | TimMc: disclaimer: it's terribly hacky and horrible, but if you add a src/user.clj filled with "(require 'my.dep)", those deps will be JIT loaded by leiningen, and won't be loaded (thus compiled) when compiling the lib |
| 15:38 | TimMc | sorbo_: I don't know what you mean by "gaps". The SO question could have :id values 1 and 1000, it doesn't matter. |
| 15:38 | Bronsa | TimMc: still something that needs to be done in lib A though, nothing you can do just as a consumer |
| 15:38 | TimMc | Bronsa: Fascinating. /me sidles away |
| 15:39 | Bronsa | TimMc: OT but was your last `c` always lowcase? |
| 15:39 | TimMc | yeah |
| 15:40 | TimMc | short for Tim McCormack |
| 15:40 | Bronsa | stupid brain is playing tricks on my memory then |
| 15:42 | creese | What's the best way to build when you have private dependencies? |
| 15:42 | xemdetia | TimMC is just his DJ name |
| 15:42 | creese | I've been using checkouts to develop. |
| 15:43 | puredanger | use a private repository? |
| 15:44 | wink | (inc xemdetia) |
| 15:44 | lazybot | ⇒ 5 |
| 15:44 | TimMc | xemdetia: :-) |
| 15:47 | creese | puredanger: maven repository? |
| 15:47 | TimMc | ~repeatability |
| 15:47 | clojurebot | repeatability is crucial for builds, see https://github.com/technomancy/leiningen/wiki/Repeatability |
| 15:47 | TimMc | creese: ^ I think this has some options. |
| 15:47 | arohner | creese: yes, you'll want a private maven repo |
| 15:48 | arohner | I like https://github.com/technomancy/s3-wagon-private, but that works for everything except lein plugins |
| 15:48 | TimMc | The private S3 bucket is another solution. |
| 15:48 | TimMc | arohner: Ah, interesting! |
| 15:48 | arohner | TimMc: something about when lein loads plugins vs. resolves deps |
| 15:48 | puredanger | I've found s3-wagon-private to work pretty well |
| 15:48 | puredanger | I've also run a company nexus etc |
| 15:49 | puredanger | that has other potential benefits - like caching the internet, allowing you to set policies, potentially serve to public, etc |
| 15:49 | TimMc | arohner: Hmm, makes sense -- a plugin that determines how plugins are loaded would be tricky. |
| 15:50 | arohner | puredanger: I wrote a plugin to cache the internet in S3 :-) |
| 15:50 | arohner | now, what was it called... |
| 15:51 | arohner | TFW when you released a plugin, used it in production, and can't remember it's name |
| 15:52 | creese | puredanger: is it possible to build locally? |
| 15:52 | arohner | aha, https://github.com/circleci/lein-deploy-deps |
| 15:52 | arohner | I forked it, not original |
| 15:53 | TimMc | creese: You *can* deploy private stuff to a local filesystem repo, but it will eventually cause you sadness. |
| 15:54 | puredanger | well if you're in a team, that sadness will start right away :) |
| 15:54 | creese | ok |
| 15:54 | creese | I'll try the wagon one |
| 15:54 | justin_smith | andyf: is there a way to make eastwood warn me if I require a namespace but don't use it? |
| 15:55 | TimMc | puredanger: True! |
| 15:55 | Bronsa | justin_smith: enable the :unused-namespaces linter |
| 15:55 | justin_smith | Bronsa: cool, thanks |
| 15:56 | justin_smith | (inc Bronsa) |
| 15:56 | lazybot | ⇒ 111 |
| 15:59 | kaiyin | could anyone help with this? http://stackoverflow.com/questions/30383222/side-effects-not-realized-without-deref |
| 16:13 | zerokarmaleft | does instaparse have a pretty printer for failures that returns a formatted string instead of actually printing to stdout? |
| 16:15 | zerokarmaleft | I suppose I could just use with-out-str |
| 16:21 | fourq | I see "xs" used often as a param in clojure examples. What the significance? |
| 16:21 | fourq | or rather as an arg to a function signature |
| 16:22 | fourq | (fn [xs] (vec (remove #(= contact %) xs))) |
| 16:22 | infinity777 | Disco Melee is hiring Clojure developers to accelerate the development of our platform. Come join the team that is attempting to redefine social streaming! https://docs.google.com/document/d/1GvnrSCUbYgbY9XdFs_DUx-0QZG2bIYT8Mbr0zdpTeew/edit?usp=sharing |
| 16:29 | amalloy | fourq: plural of x |
| 16:30 | fourq | hehe really? |
| 16:30 | andyf | justin_smith: Try enabling the linter called :unused-namespaces (IIRC), which is disabled by default because it can be too noisy |
| 16:30 | andyf | Sample command line: lein eastwood '{:add-linters [:unused-namespaces]}' |
| 16:31 | dnolen | fourq: FP convention I believe arising either from Philip Wadler or David Turner |
| 16:31 | fourq | interesting. thanks amalloy, dnolen |
| 16:31 | andyf | justin_smith: Yeah, checked the docs and that should be the one. A little bit more about it here: https://github.com/jonase/eastwood#unused-namespaces |
| 16:32 | justin_smith | andyf: yeah, I actually like that linter a lot because it helps make refactors a lot cleaner |
| 16:32 | andyf | And now I'm caught up to Bronsa answering the question :-) |
| 16:32 | justin_smith | heh |
| 16:32 | justin_smith | you actually showed the syntax (thought I did end up looking it up myself already) |
| 16:40 | andyf | justin_smith: You can have an :eastwood key in your project.clj, or user-wide $HOME/.lein/profiles.clj, with that value, if you want it always on. |
| 16:42 | justin_smith | andyf: awesome, thanks |
| 16:48 | creese | for s3-wagon-private, where do I put pom.xml? |
| 16:50 | justin_smith | creese: "lein deploy private" should do the part where it makes a pom for you |
| 16:51 | justin_smith | or whatever you named the repo, if you didn't name it private like I did |
| 16:53 | creese | I'm getting an error. S3ServiceException: 404 Not Found NoSuchKey The specified key does not exist |
| 16:53 | justin_smith | creese: it does that for me on my first upload with a new project |
| 16:53 | justin_smith | next upload, all is well |
| 16:53 | TimMc | creese: Is that the expected error mentioned in the docs? |
| 16:53 | justin_smith | in general, s3-wagon-private throws exceptions in a lot of weird circumstances where you would not expect it |
| 16:54 | creese | weird, it's working now |
| 16:54 | justin_smith | eg. getting a stack trace because you checked if the repo contained an artifact that wasn't there |
| 16:54 | justin_smith | creese: like I said, it works on the second try, and throws stack traces like they grow on trees |
| 17:29 | fourq | If I want to inspect a symbol (print it to console) how should I go about it? (fn [e] (print e)) just prints that it's an Object. |
| 17:29 | fourq | should I read-string it to see it's pre-eval'd form? |
| 17:30 | fourq | in js, I would typically JSON.stringify(something) |
| 17:30 | TimMc | fourq: A symbol should print nicely. Maybe you don't have a symbol. |
| 17:30 | TimMc | ,(prn 'foo) |
| 17:30 | clojurebot | foo\n |
| 17:30 | justin_smith | fourq: also, (fn [e] (print e)) is just an arity limited print |
| 17:31 | fourq | yeah, just as an ex |
| 17:32 | TimMc | fourq: Can you gist or refheap an example that shows your problem? |
| 17:33 | fourq | https://gist.github.com/fourq/7247640ac9e58cb89dcd#file-core-cljs-L16 |
| 17:33 | fourq | TimMc |
| 17:34 | fourq | I'd like see what the params actually are when they are passed in |
| 17:34 | fourq | the doc's leave a bit to be desired |
| 17:34 | fourq | (Om docs) |
| 17:35 | amalloy | i don't think you care about this. it's just gonna be a function |
| 17:35 | amalloy | you might care about delete |
| 17:35 | fourq | I just want to know the proper function to call in order to inspect, "this" was just my first attempt |
| 17:35 | fourq | but I am curious about it too |
| 17:36 | TimMc | fourq: Oh, you didn't mention this was CLJS. That explains a lot. |
| 17:36 | fourq | TimMc I wasn't sure it mattered considering I'd like to inspect a symbol or key |
| 17:37 | amalloy | fourq: you don't want to inspect a symbol |
| 17:37 | fourq | no? I want to eval it? |
| 17:37 | amalloy | you want to inspect a value, which you coincidentally have bound to a symbol |
| 17:37 | TimMc | fourq: You're trying to inspect a value that is *bound* to a symbol. |
| 17:37 | TimMc | amalloy-sniped! |
| 17:38 | TimMc | and this time I used fewer characters! |
| 17:38 | fourq | ok, so I want to inspect the value of the symbol assoc to the current ns right? |
| 17:38 | amalloy | you had to press shift more than i did. we'll say that was the problem |
| 17:38 | fourq | just to see if I got this right |
| 17:38 | fourq | you both win |
| 17:38 | TimMc | amalloy: Let's go with that. |
| 17:39 | fourq | clojure isn't coming very easy to me. I've been oop forever it seems, and between fp and the syntax, i'm just barely hanging on atm |
| 17:39 | TimMc | fourq: Just as in JS, not every value you can get your hands on is particularly amenable to printing. |
| 17:40 | fourq | even if it told me it was a func, I could (souce some-func) right? |
| 17:40 | TimMc | source is a hack |
| 17:40 | fourq | or not in cljs during runtime? |
| 17:41 | TimMc | source gets the metadata of the var, finds out the file it was defined in, then goes out to the filesystem and looks in the file and goes to the appropriate line and reads the first thing it sees. |
| 17:41 | fourq | hmm |
| 17:41 | TimMc | It's not really showing you the source of the thing as it is in memory. |
| 17:41 | amalloy | TimMc: is that true even in cljs? js actually keeps source around |
| 17:41 | fourq | ok, well how do you suggest that I inspect param values? I just want to know what I'm dealing with |
| 17:41 | amalloy | and doesn't have vars anyway |
| 17:42 | TimMc | amalloy: Man, I don't know anything about cljs. |
| 17:42 | dnolen | fourq: ClojureScript has good debugging support, use it :) |
| 17:42 | dnolen | you can set breakpoints and inspect the stack frame |
| 17:42 | amalloy | fourq: (prn x) |
| 17:42 | fourq | yes, that's what I need. debugging tools |
| 17:42 | fourq | prn? diff than print, println? |
| 17:42 | dnolen | fourq: just open Chrome Dev Tools, ClojureScript enables debugging support by default |
| 17:42 | fourq | oh right, sourcemaps! |
| 17:42 | fourq | shesh |
| 17:43 | fourq | thanks, I'm like Kelly Bundy sometimes |
| 17:43 | dnolen | if you need to print something in a strackframe, cljs.core.prn(whatever) should do what you want |
| 17:43 | justin_smith | fourq: prn is different from print, it tries to print in a way that can be read back again |
| 17:43 | fourq | too much of one thing and old stuff spills out |
| 17:43 | lvh | I love that that's actually better than the situation in regular clojure |
| 17:43 | clojurebot | Huh? |
| 17:43 | justin_smith | fourq: so for example you can distinguish symbols from strings |
| 17:43 | lvh | where you can get debugging but only if you use these 2 ides |
| 17:43 | fourq | thanks everyone. |
| 17:44 | fourq | super helpful chan |
| 18:18 | mischov | Is pipeline how one would go about taking a core.async chan and returning a core.async chan that has a function applied to the contents of the original chan? |
| 18:21 | mischov | Or would you just pipe from a channel into a channel with a transformer? |
| 18:23 | chomwitt | trying to run a very simple jetty server with a simple handler leiningen will retrive 40-50 .pom packages!! 1) where do the get installed? 2) what if i change the version or a package in the dependency line in project file will that result in more retreiving ?? |
| 18:23 | lazybot | chomwitt: What are you, crazy? Of course not! |
| 18:24 | chomwitt | 1) where do they get installed? |
| 18:24 | amalloy | chomwitt: (1) ~/.m2 (2) yes |
| 18:25 | chomwitt | amalloy: wow! so that makes thinks simpler in a way.. but seems more reduntant and complex in another aspect .(i mean having many version of the same library installed) in your program's dir |
| 18:26 | TimMc | chomwitt: 2) Yes, but fewer, since only a few of the dependencies are likely to change. |
| 18:27 | TimMc | chomwitt: What language are you coming from? |
| 18:27 | chomwitt | c, javascript, php |
| 18:27 | chomwitt | and cpp |
| 18:27 | chomwitt | mainly webdev |
| 18:28 | chomwitt | clojure slowly is getting under my skin :-) |
| 18:29 | justin_smith | TimMc: glib answer is "it doesn't" |
| 18:29 | chomwitt | amalloy: i found the .m2 dir. thanks! |
| 18:29 | TimMc | s/ in C-land// :-P |
| 18:30 | TimMc | chomwitt: A tip: Never blow that away unless you want to re-download the internet. (But sometimes it is helpful to move it temporarily in case you suspect the repository has gotten into a bad state.) |
| 18:30 | sdegutis | Is it safe to nest -> macros? |
| 18:30 | sdegutis | (-> foo (-> bar)) ? |
| 18:31 | sdegutis | Or will that give unexpected results? |
| 18:31 | justin_smith | sdegutis: yeah, ->> inside -> is very handy |
| 18:31 | sdegutis | Great. Thanks. |
| 18:31 | TimMc | sdegutis: Ever since 1.6.0 or so, they behave properly. |
| 18:31 | sdegutis | Dang, I'm on 1.5.1 |
| 18:31 | TimMc | Depends what you mean by "expected" though. |
| 18:31 | TimMc | sdegutis: http://dev.clojure.org/jira/browse/CLJ-1121 |
| 18:32 | amalloy | TimMc: it's always behaved fine for ->, i thought. it's nesting ->> that was a little weird |
| 18:32 | amalloy | although why would you. (-> foo f (-> g h)) is always the same as (-> foo f g h) |
| 18:32 | sdegutis | True. |
| 18:33 | TimMc | sdegutis: This will run an infinite loop in 1.5.1: (macroexpand '(->> a b (->> c d))) |
| 18:35 | sdegutis | Ah. |
| 18:35 | TimMc | They used to be implemented recursively. |
| 18:37 | sdegutis | I may not even be able to do what I wanted. |
| 18:37 | sdegutis | I've been using the approach of taking in the same state input as the first argument as I spit out, in all my functions, so that I can chain them with -> |
| 18:37 | sdegutis | For example, (-> (create-cart) (add-item-to-cart "item1") (remove-item-from-cart "item2 |
| 18:39 | amalloy | sdegutis: so far so good |
| 18:39 | sdegutis | ")) |
| 18:39 | sdegutis | But I want to add functions within. |
| 18:40 | sdegutis | So, (-> (create-cart) (-> (add-item-to-cart "item1") (set-item-description "foo")) (remove-item-from-cart "item2")) |
| 18:40 | amalloy | sdegutis: i mean, you can do that, but you're just using -> as a grouping construct then. it's the same as if you just lifted all the stuff inside it up into the main -> |
| 18:41 | sdegutis | Right. My API design doesn't allow for returning a sub-item in some contexts and the item itself in others. |
| 18:42 | sdegutis | So add-item-to-cart always returns a cart, and set-item-description must take a cart, not an item. |
| 18:42 | sdegutis | This is a problem in my design, and makes -> not be compatible. |
| 18:42 | amalloy | i think you mean (-> (create-cart) (add-item-to-cart (-> "item1" (set-item-description "foo"))), then |
| 18:43 | sdegutis | I suppose I could do it with (-> (create-item "item") (set-item-desc "foo")) |
| 18:43 | amalloy | here you're threading two totally distinct things, and they both make sense to thread, but they don't interact at all |
| 18:43 | sdegutis | But then that would build up a description rather than using the real state, since it has not access to the state param returned from create-cart. |
| 18:47 | sdegutis | The problem with the design of building up a description, is that I can't separate the APIs of creating and updating an object. |
| 18:48 | amalloy | sdegutis: did you look at my suggestion? is there some reason this is impossible to do? why does creating an item need to know about the cart it's going to be added to? |
| 18:48 | sdegutis | So if create-item and set-item-desc just build up a description of what to do, and create-item does the real work, then update-item needs also to be able to do the real work, and needs a separate way of getting a hold on an item, whereas create-item already has a reference to the item (it just created it). |
| 18:48 | sdegutis | amalloy: yes, I'm responding to your suggestion. |
| 18:51 | sdegutis | amalloy: creating an item only makes sense in the context of the cart it's being added to, since an item cannot be created separately from a cart or without a cart |
| 18:52 | sdegutis | amalloy: thus the creation function must take a cart immediately, to avoid having an inconsistent database state |
| 18:52 | amalloy | sdegutis: that doesn't sound like much of a model of the real world |
| 18:52 | amalloy | i'm pretty sure boxes of cereal exist on the shelf even before i put them into my cart |
| 18:52 | sdegutis | amalloy: er sorry, I may be using a bad analogy, I don't really have a cart and an item in my real model, I just picked two model concepts off the top of my head for this |
| 18:52 | sdegutis | amalloy: I didn't realize how silly my analogy was until you said that :) |
| 18:53 | amalloy | sdegutis: i don't think you should use an analogy. i think you should describe a thing you are actually trying to do, because people have to respond to the stuff you say, rather than the stuff you are thinking |
| 19:05 | url- | aloha |
| 19:14 | travisrodman | is anyone using clojail and running into OOM issues with the JVM? |
| 19:15 | travisrodman | I have been using it to sequester calls, and about 1.5 days into excution, it is OOM-ing, due to references to the sandbox being retained by the DynamicClassLoader |
| 19:15 | travisrodman | has anyone worked around this? |
| 19:16 | amalloy | travisrodman: lazybot uses clojail, and his uptime is a bit over 2 months at the moment |
| 19:16 | travisrodman | but is lazybot using only one jail, or is it generating a new one for each request? |
| 19:17 | travisrodman | thanks for responding to me on this BTW |
| 19:17 | travisrodman | we are generating a new jail for each inbound request |
| 19:18 | amalloy | i can see how that might be a problem. why do you have to do that? |
| 19:18 | travisrodman | it is those reference that are being retained i.e., sandbox123423... eventually they are hard-referenced and overrun memory. |
| 19:19 | travisrodman | we are eval-ing tools written with the taxi dsl in individual containers since each caller could be defining their own logic, so we don't want namespace redefinitions and clashes |
| 19:19 | travisrodman | hence, we spawn a new jail per request. |
| 19:20 | travisrodman | normally, if this were java, we would sequester them under a class loader and dump the loader at the end of the execution, to free the memory, but the references in the clojure code are all retained by the DynamicLoader |
| 19:21 | amalloy | i'm afraid i don't know enough about the problems with classloader GC to help you, really. the usual cause of this is a thread-local variable, right? so that a thread holds a reference to an object, which holds a reference to the classloader? |
| 19:21 | travisrodman | basically yes, and the classloader in this case is the root loader in Clojure |
| 19:22 | travisrodman | so the only way to dump it is to restart, or to create a classloader above the Dynamic laoder, containering the system, so the parent to the DynamicLoader can be dumped |
| 19:22 | travisrodman | but this is clojure turtles all the way down. |
| 19:22 | travisrodman | in this system... |
| 19:24 | travisrodman | amalloy: is that assessment correct, I am not missing something that you are aware of? |
| 19:24 | amalloy | travisrodman: i'm not sure. i think there is some way to clean up the classloaders. you might look into what clojure.repl or clojure.main is doing, since it makes a new dynamic classloader for every eval request |
| 19:25 | amalloy | and repls don't seem to have this problem |
| 19:26 | amalloy | also, i don't know if it is at all helpful to you, but the threads created by clojail are un the threadgroup "sandbox"; if getting a reference to those threads would help you, you could try that |
| 19:27 | travisrodman | i think they are just making new DCLs, hence the fn__234123 naming, and the map constructions in the classes... that way a new function can be def'd without dumping the old class definition. this is why deftypes force a restart, since they are generating a non-generic class |
| 19:27 | travisrodman | yeah.. thanks, I will check avenues related to that... I appreciate it. |
| 19:28 | travisrodman | lazybot help |
| 19:28 | travisrodman | ,lazybot help |
| 19:28 | clojurebot | #error {\n :cause "Unable to resolve symbol: lazybot in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: lazybot in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6543]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: lazybot i... |
| 19:28 | travisrodman | $lazybot help |
| 19:28 | amalloy | travisrodman: hiredman probably knows more about classloaders than i do. he's responsible for clojurebot, which doesn't use clojail, but probably has similar issues |
| 19:28 | travisrodman | ahh, I thought this channel was using lazybot... |
| 19:28 | travisrodman | or, is it? |
| 19:29 | Raynes | There are two bots in this channel. |
| 19:29 | Raynes | Both of them. |
| 19:29 | travisrodman | ,(defn test-fxn [a] (println a)) |
| 19:29 | clojurebot | #'sandbox/test-fxn |
| 19:29 | travisrodman | ,(test-fxn "print me") |
| 19:29 | clojurebot | print me\n |
| 19:30 | travisrodman | ,(defn test-fxn [a] (println (str a "some other data"))) |
| 19:30 | clojurebot | #'sandbox/test-fxn |
| 19:30 | travisrodman | ,(test-fxn "print me") |
| 19:30 | clojurebot | print mesome other data\n |
| 19:30 | travisrodman | hmm... it looks to use the same namespace for every request |
| 19:30 | Raynes | Well, yes. |
| 19:30 | Raynes | That's half of the purpose of clojail. |
| 19:30 | Raynes | To make that a thing that can safely be done. |
| 19:30 | Raynes | It does a pretty solid job of that when it does a pretty solid job of that. |
| 19:31 | travisrodman | but that means everyone is using the same namespace |
| 19:31 | travisrodman | so any defs happening in that space will clash with everyone else |
| 19:31 | travisrodman | which is fine... as long as it is an acceptable situation |
| 19:31 | url- | why not just wrap an Actor around the sandbox? |
| 19:33 | travisrodman | url-: i will look into that |
| 19:34 | url- | if you think of it as a service instead of a monolithic object that may help frame out a solution |
| 19:35 | travisrodman | url-: well, it is a service, spread over 25 machines, but each of them can be running over 60 tools each... |
| 19:36 | travisrodman | url-: originally, the design was to allow people to design their own tools, so we didn't want them clashing with each other, hence the sandboxing |
| 19:36 | travisrodman | url-: but we may forego that to avoid the memory problems |
| 19:38 | travisrodman | url-: thanks for the actor tip, i will look into seeing if it will work with the current model. thanks! |
| 19:42 | travisrodman | amalloy: i may re-think this entire approach with using binding to abstract the tool... that way a single sandbox could be used, but the memory will be assocaiated with the thread, and not the namespace so it can be dumped... |
| 19:42 | travisrodman | thanks all for the feedback, and Raynes, thanks for the lib, it really is useful... sorry about appering to knock on it... it is a good piece of work. |
| 19:43 | Raynes | I read approximately two of your prior messages, so I appreciate your honesty. |
| 19:43 | amalloy | travisrodman: if the need for sandboxing is just for sequestration, you can avoid putting stuff into namespaces, but instead use your own named maps, and give those around to whatever this "tool" is |
| 19:43 | amalloy | then you wouldn't need multiple sandboxes, as you say |
| 19:44 | Raynes | Clojail is way more of an experiment in how far you can go with Clojure's metaprogramming facilities to implement an embedded sandbox. |
| 19:44 | Raynes | If I were rewriting tryclojure today, I'd be unlikely to use it. |
| 19:44 | Raynes | Same goes for lazybot. |
| 19:44 | travisrodman | amalloy: right... I am thinking that approach could be a viable solution... thanks again for the feedback |
| 19:44 | travisrodman | Raynes: intersting... what would you do instead? |
| 19:45 | Raynes | Ephemeral machines. |
| 19:45 | Raynes | Better yet, docker |
| 19:45 | Raynes | Sometimes of that sort. |
| 19:45 | Raynes | And lots of money to afford the memory consumption of a JVM process. |
| 19:46 | Raynes | Tryclj would be horrifying to scale, but it'd actually work properly. |
| 19:47 | amalloy | even ephemeral JVMs in one machine would work okay |
| 19:47 | Raynes | Not if you don't use the JVM sandbox. |
| 19:47 | amalloy | sure |
| 19:47 | Raynes | Or something like docker |
| 19:47 | Raynes | Or selinux |
| 20:11 | travisrodman | thanks for describing your approach... sorry, had to step away for a moment. |
| 20:12 | travisrodman | Raynes: --^ |
| 20:50 | WickedShell | I have a seesaw gui using swinglayout, when I update the items in my mig panel any items that had been in it before I swapped the other items disappear, but if I fully rebuild the panel works correctly, any idea why this is happening? |
| 21:06 | mcohen01 | anything obvious to look for when lein uberjar never finishes? |
| 21:06 | WickedShell | I apologize, I had it right before, spelling errors are the root of all evil (and you know, running the same misspelled command again) |
| 21:06 | mcohen01 | i've got a main method that does nothing and it still hangs |
| 21:06 | mcohen01 | with no imports either |
| 21:13 | justin_smith | mcohen01: (shutdown-agents) |
| 21:13 | justin_smith | mcohen01: clojure starts an agent pool, the vm doesn't want to quite while that pool is running |
| 21:14 | justin_smith | mcohen01: oh, uberjar - you are probably using def to create a server |
| 21:14 | amalloy | justin_smith: if it's lein uberjar that never finishes, shutdown-agents is not the answer |
| 21:14 | justin_smith | or spawn a thread that does something |
| 21:14 | justin_smith | amalloy: right |
| 21:14 | justin_smith | mcohen01: if you use jstack to get a dump for all your running stacks (it's a command line program, run outside the vm) one of those stack traces will have your offending code in it |
| 21:35 | travisrodman | amalloy: are you still there? |
| 21:44 | mcohen01 | justin_smith: thanks much for the recommendation re jstack. worked like a charm. i was starting a netty hashwheeltimer and didn |
| 21:44 | mcohen01 | t't realize it |
| 21:45 | amalloy | travisrodman: what's up? |
| 21:49 | travisrodman | amalloy: just wanted to give you a working solution to the earlier question, if you are interested... |
| 21:49 | travisrodman | amalloy: i set up a pool for the sandboxes, so when a session closses, it is returned to the pool. |
| 21:50 | travisrodman | it is still possible to crash the system, but essentially, you would have to have all the sessions (millions) persist in parallel for that to happen |
| 21:50 | travisrodman | not a likely scenario. so in the event you need to have individual jails, it appears to be a viable solution |
| 21:50 | travisrodman | fyi |
| 22:27 | wha123 | I am getting a ClassNotFoundException when trying to pass a custom record type to a Java library |
| 22:28 | gfredericks | wha123: probably some code & stack trace would help |
| 22:59 | wha123 | the issue seems to be that the Java library is trying to load a class using Class.forName(string_name_of_class), and it can't find the class for my record |
| 23:00 | gfredericks | huh. |
| 23:00 | gfredericks | I wonder if AOT could fix that. |
| 23:00 | justin_smith | wha123: are you providing the full munged and package qualified class name? |
| 23:00 | gfredericks | justin_smith: I imagined an object was being passed in and something reflective was happening. Which made me guess classloaders were to blame |
| 23:01 | wha123 | Yeah, I originally pass in an object, and it uses reflection to get the class name and writes it out to a file (it is part of a serialization framework) |
| 23:02 | wha123 | but then when trying to deserialize, it can't find the class |
| 23:02 | justin_smith | during the same vm session, or a later one? |
| 23:02 | wha123 | all in the same repl session currently |
| 23:05 | gfredericks | I blame ye olde classloaders |
| 23:05 | wha123 | yeah, Class/forName works in the repl as well -_- |
| 23:05 | gfredericks | make sure the defrecord is in one of your source files, add :aot :all to your project.clj, quit the repl, run `lein do clean, compile` and then `lein repl` and try it again |
| 23:05 | wha123 | it must be using its own |
| 23:06 | gfredericks | I don't actually know how classloaders work so who knows if this will do it or not |