2015-04-09
| 00:00 | Igor | But when I reset! atom, if I first need calculate new value, depends on this atom, another thread can running between calculating and reset! |
| 00:00 | justin_smith | yes |
| 00:00 | Igor | Hmm.. I think I must use swap! in this case =) |
| 00:01 | justin_smith | reset! is for if you unconditionally want to set the value, swap! is if you want to calculate a new value based on an old one, and you want to recalculate if there was any modification in the meantime |
| 00:07 | Igor | thx |
| 01:28 | grehuo | Hi everyone. I've got a newbie problem, that I'm stuck at and can't figure out from the docs. I'm creating a todo app, and have my state in an atom like this: http://pastebin.com/ETgz4b5g. I want to make a function to change the state of one of the items in the vector, so that it has {:done true}. I think the function I'm looking for is assoc-in, but I can't get it to work like I want to and can't figure out how to use it. Does anyone |
| 01:28 | grehuo | know how you would update one specific map in the vector in the atom? |
| 01:30 | grehuo | Basically: how can you swap! a value of a map inside a vector inside an atom, without making changes to the other parts of the atom? |
| 01:31 | nuwanda__ | grehuo: |
| 01:32 | nuwanda__ | you want assoc-in |
| 01:32 | nuwanda__ | with [index :done] |
| 01:33 | nuwanda__ | ,(def todos [{:id 1 :done false} {:id 2 :done true}]) |
| 01:33 | clojurebot | #'sandbox/todos |
| 01:33 | nuwanda__ | ,(assoc-in todos [0 :done] true) |
| 01:33 | clojurebot | [{:id 1, :done true} {:id 2, :done true}] |
| 01:37 | grehuo | I wrote `(swap! todos (assoc-in @todos [0 :done] true))`, but am getting the error "No item [the vector] in vector of length 2". This is cljs. Also, this will only update the first item, every time right? Not any item I chose? |
| 01:45 | tomjack | (swap! todos assoc-in [0 :done] true) |
| 01:45 | tomjack | true |
| 01:46 | tomjack | it seems maybe a bit odd to have a vector of maps with ids -- do you want to update by id, or by position in the vector? |
| 01:46 | tomjack | 0 in [0 :done] means "the first element" |
| 01:47 | tomjack | if you want to update by id, it might be easier to have (def todos (atom {1 {:done false} 2 {:done true}})), then (swap! todos assoc-in [1 :done] true) means "the element under key/id 1" |
| 01:50 | tomjack | (swap! todos assoc-in [0 :done] true) probably looks mysterious, it's shorthand for (swap! todos #(assoc-in % [0 :done] true)) |
| 01:50 | tomjack | when swapping you must take the current value as a function parameter, _not_ dereference like @todos |
| 01:51 | tomjack | (reset! todos (assoc-in @todos [0 :done] true)) would be the non-exception-throwing way to do what you tried, but it would be wrong |
| 01:51 | grehuo | I see.. Yeah having :id in a vector makes no sense, removing it and using position in vector as id instead. |
| 01:51 | tomjack | because you may dereference todos, then someone else swaps the atom, then you reset, losing state |
| 01:53 | tomjack | (OTOH having :id in a vector could make sense, if e.g. the todo items can be moved around in the list but you want to remember their identities :) ) |
| 01:55 | tomjack | s/losing state/possibly causing any number of weird race condition problems/ |
| 01:56 | grehuo | nuwanda__ tomjack I'm starting to make it work now, this is so cool! Now I just have to figure out how to select the index of the todo that is being clicked on in my app, but I'll have a go at that myself :). I can not thank you enough for helping me figure out what was wrong in my example, and helping me understand assoc-in! THANK YOU!!! |
| 01:57 | grehuo | The solution seems to be to not set the :id |
| 01:57 | grehuo | and then do (swap! todos assoc-in [0 :done] true), like you saik |
| 01:57 | grehuo | said |
| 02:17 | celwell | Hello, I find I'm having to use this quite often (when (not *compile-files*) ...) and it's dirtying my code up. Any ideas? Is there a prettier solution? The reason I need that conditional is because those expressions cause uberjar (and uberwar) to hang if they are run at compile time. |
| 02:19 | mavbozo | celwell, interesting, are those expressions have side-effects? |
| 02:21 | celwell | mavbozo: e.g., one starts a thread that modifies a db every 5 seconds |
| 02:22 | sveri | celwell: I have never seen something like this before. I would say you have some code which you are evaluating during compilation / macro evaluation maybe which causes your process to hang |
| 02:23 | mavbozo | celwell, those expressions are (defns ...) ? |
| 02:23 | celwell | heres an example: |
| 02:23 | celwell | (when (not *compile-files*) |
| 02:23 | celwell | (def zones (map #(assoc % :zip_codes (util/split-on-comma (:zip_codes %))) |
| 02:23 | celwell | (get-all-zones (db/conn))))) |
| 02:24 | celwell | where, get-all-zones grabs from db |
| 02:24 | celwell | if I take off the (when (not *compile-files*) it will hang on ring uber war |
| 02:24 | celwell | or whatever the command is |
| 02:24 | sveri | because of the (get-all-zones... I assume |
| 02:25 | celwell | yeah |
| 02:25 | mavbozo | celwell, you should't put side-effecty expressions at the top-level of your namespace. |
| 02:25 | sveri | celwell: read about component: https://github.com/stuartsierra/component this is valuable for what you want to do |
| 02:26 | mavbozo | celwell, put it inside a function and call those function in your (defn -main [] ...) |
| 02:26 | celwell | I don't have a -main currently. |
| 02:26 | celwell | i guess i should read about it? |
| 02:27 | celwell | I'm lein ring server, and then making uberwars for deployment |
| 02:28 | sveri | Does an uberwar work at all without a -main method? |
| 02:28 | celwell | yeah |
| 02:29 | celwell | This is the entrance to the program I guess: |
| 02:29 | celwell | (def app |
| 02:29 | celwell | (-> (handler/site app-routes) |
| 02:29 | celwell | (middleware/wrap-json-body) |
| 02:29 | celwell | (middleware/wrap-json-response))) |
| 02:29 | sveri | hm, interesting. still, I find the idea very unusal not to have one entry point |
| 02:29 | sobel | -main is not the entry point for a war |
| 02:29 | celwell | I guess ring handles the -main business, unless I'm mistaken |
| 02:29 | sobel | well, not your -main |
| 02:29 | sobel | :) |
| 02:32 | sveri | sobel: not? How does the container figure out which class and method to start? |
| 02:36 | sobel | sveri: afaik, that's part of the servlet spec |
| 02:39 | sveri | sobel: right, I remember, you can define an entry point in some xml file. Been to long since I had to use it |
| 02:45 | sobel | sveri: what entry point do you mean? there is a -main that brings up the server, but it's ring's |
| 02:45 | sobel | all the entry points you define for a web app are request handlers |
| 02:52 | sveri | sobel: Yea, It's been some time, but once I worked with GWT and I had to define a class as an entry point in some xml file somewhere |
| 03:25 | dysfun | hrm, have to say i'm rather liking boot so far |
| 03:25 | dysfun | even if i'm missing about a dozen plugins i quite like |
| 03:34 | mavbozo | celwell, if you use lein-ring plugin you can specify your init function in :ring options in project.clj |
| 03:35 | mavbozo | celwell, the init function called once before your handler starts |
| 04:00 | mpenet | just wondering: any advantage of using an uberwar vs uberjar? |
| 04:01 | dysfun | mpenet: there is if you deploy via an appserver |
| 04:01 | mpenet | yes, appart from that |
| 04:03 | mpenet | I guess an appserver is mandatory in prod if you use war files |
| 04:06 | dysfun | i think they can still be executable |
| 04:06 | dysfun | it's just that war files mandate all that xml as well |
| 04:07 | dysfun | (well, for stuff that doesn't matter) |
| 04:08 | dysfun | there's no need to have an appserver for a good production environment either |
| 04:08 | dysfun | i certainly don't have the level of experience required to actually administer an appserver |
| 04:09 | mpenet | I guess if I had to use an app server (as per client request), wars make sense, otherwise not so much |
| 04:09 | dysfun | that's a good rule of thumb |
| 04:09 | sveri | me uses an uberjar too |
| 04:09 | dysfun | there are some circumstances where appservers win, like if you're using J2EE stuff, but in clojure, there's really no need to use J2EE stuff |
| 04:10 | dysfun | it's mostly handy to have it there as a way of integrating with an aging java codebase |
| 04:11 | sveri | I guess appservers also make sense if you want multiple apps running inside one server to save resources |
| 04:12 | dysfun | there's some of that, but it starts to get complicated very quickly |
| 04:12 | dysfun | memory is cheap. i hope your time is not :) |
| 04:13 | dysfun | back in the day, appservers were the only way to make performant web stuff |
| 04:13 | dysfun | then we got Netty. Then it got good. really good. |
| 04:13 | dysfun | now i deploy netty in an uberjar (via aleph) |
| 04:15 | sveri | dysfun: Well, there are people running vps with only limited memory, so for some this is a concern. That said, I am on your side too, I'd rather pay a bit more before I go ahead and fiddle with theses app servers and all the complexity they bring in |
| 04:15 | dysfun | there's also something to be said about valuing your sanity :) |
| 07:04 | blashyrk | hello, is it possible to convert a hashmap into an atom? |
| 07:04 | blashyrk | or at least construct an atomic hashmap from a normal, immutable map? |
| 07:05 | TEttinger | blashyrk, I'm not sure atoms mean what you think they do |
| 07:05 | TEttinger | ,(atom {}) |
| 07:05 | blashyrk | probably not :) |
| 07:05 | clojurebot | #<Atom@be611cf: {}> |
| 07:05 | blashyrk | I'm using cheshire to parse JSON |
| 07:06 | TEttinger | ,(def kinda-variable (atom {})) |
| 07:06 | clojurebot | #'sandbox/kinda-variable |
| 07:06 | blashyrk | but I want to make modifications to the hashmap I get as a result |
| 07:06 | TEttinger | ,(swap! kinda-variable assoc :a 1) |
| 07:06 | clojurebot | {:a 1} |
| 07:06 | TEttinger | ,@kinda-variable |
| 07:06 | clojurebot | {:a 1} |
| 07:06 | TEttinger | you may want transients |
| 07:06 | blashyrk | yes, but is it possible to assoc an entire hashmap to the newly defined atom? |
| 07:07 | blashyrk | and if so wouldn't that be kinda expensive? |
| 07:07 | TEttinger | yeah |
| 07:07 | TEttinger | no |
| 07:08 | TEttinger | ,(def kinda-variable (atom (zipmap (range 1000) (map char (range 32 1032))))) |
| 07:08 | clojurebot | #'sandbox/kinda-variable |
| 07:08 | TEttinger | ,@kinda-variable |
| 07:08 | clojurebot | {0 \space, 893 \Ν, 920 \θ, 558 \Ɏ, 453 \ǥ, ...} |
| 07:08 | TEttinger | unsorted |
| 07:11 | blashyrk | say I have a map in a var "some-map" |
| 07:11 | blashyrk | but it's a standard immutable map |
| 07:11 | TEttinger | blashyrk, the neat thing about clojure's data structures is that even though they are immutable, and cannot be modified after being created, if you make another, say, hashmap with most of its keys and values from an existing hashmap, the keys and values that are the same will be shared, not using additional memory and not requiring a copy |
| 07:11 | blashyrk | that sounds great, but what is the idiomatic way to construct an atomic map completely from an existing map? |
| 07:12 | TEttinger | so it isn't expensive to just return a modified version of that immutable map, and pass it to another fn expecting another map |
| 07:12 | TEttinger | the fn atom |
| 07:12 | TEttinger | (doc atom) |
| 07:12 | clojurebot | "([x] [x & options]); Creates and returns an Atom with an initial value of x and zero or more options (in any order): :meta metadata-map :validator validate-fn If metadata-map is supplied, it will become the metadata on the atom. validate-fn must be nil or a side-effect-free fn of one argument, which will be passed the intended new state on any state change. If the new state is unacceptable, the validate-fn should return false or thro |
| 07:12 | TEttinger | basically, you only care about the first part of that |
| 07:13 | TEttinger | the initial value of the atom will be the argument you pass to (atom) |
| 07:13 | blashyrk | I tried that already but it didn't work for some reason |
| 07:13 | blashyrk | let me check |
| 07:13 | blashyrk | ,(def some-map {:somekey 0, :someotherkey 2}) |
| 07:13 | clojurebot | #'sandbox/some-map |
| 07:14 | blashyrk | ,(def mutable-map (atom some-map)) |
| 07:14 | clojurebot | #'sandbox/mutable-map |
| 07:14 | blashyrk | ,@mutable-map |
| 07:14 | clojurebot | {:somekey 0, :someotherkey 2} |
| 07:14 | blashyrk | hmmm interesting |
| 07:14 | TEttinger | you still won't modify some-map |
| 07:14 | blashyrk | not sure why it didn't work for me |
| 07:14 | TEttinger | but mutable-map can be altered |
| 07:15 | TEttinger | ,(swap! mutable-map assoc :yetanotherkey [:whee :vecs]) |
| 07:15 | clojurebot | {:somekey 0, :someotherkey 2, :yetanotherkey [:whee :vecs]} |
| 07:16 | blashyrk | ah I remember what failed in my case |
| 07:16 | blashyrk | can I use swap to basically assign? |
| 07:16 | blashyrk | like |
| 07:17 | blashyrk | ,(def mutable-map (atom {})) |
| 07:17 | clojurebot | #'sandbox/mutable-map |
| 07:17 | blashyrk | (swap! mutable-map ? some-map) |
| 07:18 | blashyrk | what would I use here to directly "assign" the original map to the atom? |
| 07:18 | blashyrk | or should I just redefine mutable map (after parsing the original map) ? |
| 07:18 | blashyrk | with def |
| 07:21 | oddcully | ,(doc reset!) |
| 07:21 | clojurebot | "([atom newval]); Sets the value of atom to newval without regard for the current value. Returns newval." |
| 07:21 | oddcully | ,(reset! mutable-map {:a 1}) |
| 07:21 | clojurebot | {:a 1} |
| 07:22 | oddcully | ,(@mutable-map) |
| 07:22 | clojurebot | #error{:cause "Wrong number of args (0) passed to: PersistentArrayMap", :via [{:type clojure.lang.ArityException, :message "Wrong number of args (0) passed to: PersistentArrayMap", :at [clojure.lang.AFn throwArity "AFn.java" 429]}], :trace [[clojure.lang.AFn throwArity "AFn.java" 429] [clojure.lang.AFn invoke "AFn.java" 28] [sandbox$eval93 invoke "NO_SOURCE_FILE" -1] [clojure.lang.Compiler eval "C... |
| 07:22 | oddcully | clojurebot: stop confusing me! |
| 07:22 | clojurebot | Pardon? |
| 07:22 | oddcully | ,@mutable-map |
| 07:22 | clojurebot | {:a 1} |
| 07:24 | blashyrk | thanks! |
| 07:24 | opqdonut | ,(deref mutable-map) -- aka |
| 07:24 | clojurebot | {:a 1} |
| 07:28 | TEttinger | (inc oddcully) |
| 07:28 | lazybot | ⇒ 1 |
| 07:35 | mavbozo | i put core.async/<! inside a try catch block the repl, I get this exception CompilerException java.lang.RuntimeException: Unable to resolve symbol: user in this context, compiling:(/tmp/form-init7054017936426169058.clj:1:1) |
| 07:35 | mavbozo | https://www.refheap.com/99395 |
| 07:36 | mavbozo | weird, why it can not resolve the symbol of the namespace? |
| 07:36 | mavbozo | any suggestions on how to debug this problem? |
| 07:39 | TEttinger | that is odd, you didn't, say, paste an earlier line that started with user> did you? |
| 07:41 | mavbozo | TEttinger, no, i included the 'user>' prompt in the paste as a information that i was in namespace named 'user' |
| 07:42 | TEttinger | yeah, it's odd that it's not understanding the ns properly |
| 07:42 | TEttinger | very very strange |
| 07:56 | farzad | guys can i ask a dumb question? :D |
| 07:56 | TEttinger | no, there are no dumb questions |
| 07:56 | TEttinger | go right ahead :) |
| 07:56 | TEttinger | ~ask |
| 07:56 | clojurebot | The Ask To Ask protocol wastes more bandwidth than any version of the Ask protocol, so just ask your question. |
| 07:57 | farzad | ok how do i subclass a class like Class SimpleChannelInboundHandler<I> |
| 07:57 | farzad | that <I> thingie is puzzling me |
| 07:58 | TEttinger | it's a generic type, which actually isn't even used at the VM level. it's the same to clojure as SimpleChannelInboundHandler |
| 07:59 | TEttinger | a good example is the Java class ArrayList<T>, which usually contains one type specified by T. you could have, say, ArrayList<Point> |
| 07:59 | TEttinger | but clojure doesn't care, because the <T> is erased after compilation anyway, and is only used by Java to make sure that the ArrayList is what it thinks it is |
| 07:59 | farzad | well i subclass that with proxy and i get a class cast exception :/ |
| 08:00 | TEttinger | (doc proxy) |
| 08:00 | clojurebot | "([class-and-interfaces args & fs]); class-and-interfaces - a vector of class names args - a (possibly empty) vector of arguments to the superclass constructor. f => (name [params*] body) or (name ([params*] body) ([params+] body) ...) Expands to code which creates a instance of a proxy class that implements the named class/interface(s) by calling the supplied fns. A single class, if provided, must be first. If not provided it default |
| 08:00 | TEttinger | this is a tough docstring... |
| 08:00 | farzad | lemme read that brb |
| 08:02 | TEttinger | ,(.add (proxy [ArrayList] [] (add [o] 5))) |
| 08:02 | clojurebot | #error{:cause "Can't resolve: ArrayList", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.Exception: Can't resolve: ArrayList, compiling:(NO_SOURCE_FILE:0:0)", :at [clojure.lang.Compiler macroexpand1 "Compiler.java" 6636]} {:type java.lang.Exception, :message "Can't resolve: ArrayList", :at [clojure.core$proxy$fn__5680 invoke "core_proxy.clj" 329]}], :trace [[clojure.core... |
| 08:02 | TEttinger | ,(.add (proxy [java.util.ArrayList] [] (add [o] 5))) |
| 08:02 | clojurebot | #error{:cause "No matching field found: add for class sandbox.proxy$java.util.ArrayList$ff19274a", :via [{:type java.lang.IllegalArgumentException, :message "No matching field found: add for class sandbox.proxy$java.util.ArrayList$ff19274a", :at [clojure.lang.Reflector getInstanceField "Reflector.java" 271]}], :trace [[clojure.lang.Reflector getInstanceField "Reflector.java" 271] [clojure.lang.Ref... |
| 08:02 | TEttinger | I uh don't use proxy much |
| 08:03 | farzad | well nothing new in the doc |
| 08:03 | farzad | i use proxy for other thing with no problem |
| 08:03 | farzad | things* |
| 08:03 | TEttinger | ,(.add (proxy [java.util.ArrayList] [] (add [this o] 5))) |
| 08:03 | clojurebot | #error{:cause "No matching field found: add for class sandbox.proxy$java.util.ArrayList$ff19274a", :via [{:type java.lang.IllegalArgumentException, :message "No matching field found: add for class sandbox.proxy$java.util.ArrayList$ff19274a", :at [clojure.lang.Reflector getInstanceField "Reflector.java" 271]}], :trace [[clojure.lang.Reflector getInstanceField "Reflector.java" 271] [clojure.lang.Ref... |
| 08:03 | TEttinger | hm |
| 08:04 | TEttinger | you don't include the <I> just so we're clear |
| 08:04 | farzad | yup |
| 08:05 | farzad | this is the proxy (defn get-handler [] |
| 08:05 | farzad | (proxy [io.netty.channel.ChannelHandler] [] |
| 08:05 | farzad | (channelRead [context msg] |
| 08:05 | farzad | (alert "Channel Read:" "") |
| 08:05 | farzad | (.close context)) |
| 08:05 | farzad | (exceptionCaught [context cause] |
| 08:05 | farzad | (println "Exception Caught:" context cause) |
| 08:05 | farzad | (.close context)))) |
| 08:05 | Empperi | doesn't proxy methods always have to have "this" as the first argument? |
| 08:06 | Empperi | which effectively references the proxy object itself |
| 08:06 | farzad | no its there by default |
| 08:06 | Empperi | I'm pretty sure it isn't |
| 08:06 | Empperi | not 100% though |
| 08:06 | farzad | Each method fn takes an additional implicit |
| 08:06 | farzad | first arg, which is bound to 'this. |
| 08:06 | farzad | read the doc |
| 08:07 | hyPiRion | ,(= (proxy [Object] (equals [this that] false)) 1) |
| 08:07 | clojurebot | #error{:cause "Unable to resolve symbol: equals in this context", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.RuntimeException: Unable to resolve symbol: equals in this context, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyze "Compiler.java" 6535]} {:type java.lang.RuntimeException, :message "Unable to resolve symbol: equals in this context", :at [... |
| 08:08 | farzad | you need to put [] after [Object] |
| 08:08 | farzad | for empty param |
| 08:08 | hyPiRion | ,(= (proxy [Object] [] (equals [that] true)) 1) |
| 08:08 | clojurebot | true |
| 08:09 | hyPiRion | well there you go |
| 08:09 | hyPiRion | ,(= (proxy [Object] [] (equals [that] (prn this) true)) 1) |
| 08:09 | clojurebot | #object[sandbox.proxy$java.lang.Object$ff19274a "sandbox.proxy$java.lang.Object$ff19274a@5a7bfbc6"]\ntrue |
| 08:10 | TEttinger | wow nice |
| 08:11 | hyPiRion | this is the answer to almost every 4clojure problem |
| 08:13 | farzad | so any ideas why i get that cast exception? |
| 08:20 | TEttinger | hyPiRion, that's evil |
| 08:20 | TEttinger | "you just redefine equality so you're always right, classic political computer science" |
| 08:20 | TEttinger | it depends on what the meaning of the word is... is |
| 08:36 | TEttinger | wow. https://twitter.com/servertastic/status/586113649766494208 |
| 08:36 | justin_smith | haha |
| 08:37 | mavbozo | i think i got disconnected |
| 08:37 | mavbozo | TEttinger, i found the source of the problem. but still, very strange |
| 08:37 | mavbozo | it's the ordering in :dependencies for clojure.core.async and pedestal-service. the problem happens if i put pedestal-service before clojure.core.async |
| 08:37 | TEttinger | woah, wow |
| 08:37 | TEttinger | how did you find that? nice work |
| 08:39 | justin_smith | go blocks are weird |
| 08:39 | TEttinger | (inc mavbozo) ; for the independent spirit that keeps clojure going |
| 08:39 | lazybot | ⇒ 5 |
| 08:39 | mavbozo | bisecting the dependencies vector and removing each part til i the problem gone |
| 08:41 | mavbozo | even writing [io.pedestal/pedestal.service "0.4.0-SNAPSHOT" :exclusions [[org.clojure/core.async]]] still doesn't remove the problem |
| 08:41 | justin_smith | mavbozo: that vector nesting is too deep (has to do with a weird bug in lein deps :tree output that it would even suggest such a thing) |
| 08:42 | ragge | mavbozo: did you diff output of `lein deps :tree` with/without problematic dep order? |
| 08:42 | bordatoue | anyone experienced any issue with GC pauses, due to vmop taking long time |
| 08:44 | mavbozo | justin_smith, fixed it like this [io.pedestal/pedestal.service "0.4.0-SNAPSHOT" :exclusions [org.clojure/core.async]] |
| 08:44 | mavbozo | justin_smith, and the problem still happens |
| 08:44 | justin_smith | mavbozo: oh, OK |
| 08:45 | mavbozo | ragge, ok, i'll try to diff those |
| 08:46 | ragge | mavbozo: this can also be useful: `lein classpath | tr ':' '\n' | sort` |
| 08:47 | ragge | to see what actually ends up on your classpath |
| 09:03 | mavbozo | ragge, here is the result from my terminal on diffing the problematic deps with non-problematic deps |
| 09:03 | mavbozo | https://www.refheap.com/99396 |
| 09:04 | mavbozo | looks like the difference is only the version of org.clojure/tools.analyzer.jvm |
| 09:05 | farzad | anyone see something wrong with this error message? "Cannot cast io.netty.channel.ChannelInboundHandlerAdapter to [Lio.netty.channel.ChannelHandler;" |
| 09:05 | farzad | that [Lio part bugs me |
| 09:06 | justin_smith | [Lio.netty.channel.ChannelHandler; is how the jvm says io.netty.channel.ChannelHandler[] |
| 09:06 | justin_smith | it means the same thing |
| 09:06 | justin_smith | ,(type (double-array [0.0])) |
| 09:06 | clojurebot | [D |
| 09:06 | farzad | i see thanks |
| 09:06 | justin_smith | ,(type (into-array ["hello" "world"])) |
| 09:06 | clojurebot | [Ljava.lang.String; |
| 09:07 | justin_smith | so anyway, it's getting a ChannelInboundHandlerAdapter where it expects to get an array of ChannelHandlers |
| 09:07 | justin_smith | you may need to use into-array? perhaps it was a varargs method? |
| 09:08 | justin_smith | you need to create arrays to use varargs |
| 09:08 | farzad | oh... let me check that |
| 09:08 | justin_smith | if that's the case, the example with the strings above is how you do that |
| 09:08 | justin_smith | it takes an optional type argument |
| 09:09 | justin_smith | ,(type (into-array Number [0.0])) |
| 09:09 | clojurebot | [Ljava.lang.Number; |
| 09:09 | farzad | yes! thank you! |
| 09:10 | justin_smith | np - this is another one to add to my "why did my clojure code broke" blog |
| 09:10 | justin_smith | (which isn't up yet) |
| 09:11 | farzad | XD |
| 09:11 | farzad | the java code is this: ch.pipeline().addLast(new TimeClientHandler()); |
| 09:11 | justin_smith | ahah, and addLast was varargs |
| 09:11 | farzad | why doesn't that throw cast exception? |
| 09:12 | farzad | oh i see |
| 09:12 | justin_smith | because javac turns the varargs into a list automatically |
| 09:12 | justin_smith | the clojure interop does not do this |
| 09:13 | farzad | damn, should have checked the addLast doc... |
| 09:13 | farzad | wasted a nice couple of hours on this |
| 09:13 | justin_smith | farzad: well now, you know that errors mentioning that it expects Lfoo; means it was probably varargs (or at the very least it wanted an array) |
| 09:14 | justin_smith | I mean "now you know" |
| 09:14 | farzad | yep thanks again man! |
| 09:14 | justin_smith | farzad: and that's why I need to put this oral tradition from #clojure in a blog |
| 09:14 | justin_smith | so many "simple" things that you wouldn't really figure out on your own |
| 09:15 | mavbozo | like dependencies ordering problem |
| 09:15 | justin_smith | haha, that too |
| 09:16 | blashyrk | can someone who's willing to help me regarding changing a map (mutability) please send me a private message? thanks |
| 09:16 | justin_smith | clojure hash-maps are not mutable |
| 09:17 | justin_smith | at least not in any sane manner |
| 09:17 | farzad | justin_smith: if you ever start that blog, post it to /r/clojure maybe they put it next to the must read links XD |
| 09:17 | justin_smith | farzad: yeah, I'll be sure to put out the signal once it's ready |
| 09:17 | justin_smith | I really need to get off my lazy ass and do more writing for that actually |
| 09:19 | blashyrk | @justin_smith I can see that, but I'd appreciate any help (even doing it in an utterly 'insane' way). I'm about to start pulling my hair out |
| 09:21 | justin_smith | blashyrk: clojure is a functional language, the point of the language is that we can do these things without mutation, maybe if you give a small example of what you are trying to do we can help you. It's an actual proven scientific thing that anything that can be calculated via mutation can be calculated without mutation using recursion |
| 09:21 | justin_smith | "scientific" as in there are CS proofs of this |
| 09:22 | blashyrk | Ok, I'll put up a pastebin |
| 09:30 | dnolen | blashyrk: I don't think you need to paste anything yet. If you need state why are you not putting your map in an atom? |
| 09:31 | blashyrk | I don't explicitly need state |
| 09:31 | blashyrk | I just need to alter the map once like this |
| 09:31 | blashyrk | http://pastebin.com/cCfRMT7J |
| 09:31 | blashyrk | this is the fictional map |
| 09:31 | justin_smith | dnolen: he just wants to merge some maps |
| 09:31 | justin_smith | dnolen: he doesn't need mutation at all |
| 09:31 | blashyrk | what I want to do is fill the "defaults" onto each "model" |
| 09:31 | dnolen | blashyrk: then you don't need to mutate the map |
| 09:32 | dnolen | ,(merge {:foo 1} {:bar 2}) |
| 09:32 | clojurebot | {:foo 1, :bar 2} |
| 09:32 | blashyrk | meaning if :something or :something2 are omitted in the "model" map, they should be added |
| 09:32 | justin_smith | blashyrk: yes, that's what merge does |
| 09:32 | blashyrk | yes, but I also need some aditional logic in case a default value is overriden |
| 09:33 | dnolen | blashyrk: so write that logic |
| 09:34 | blashyrk | let me see |
| 09:39 | blashyrk | so how could I merge those that aren't overriden in the models and do something else for those that are? |
| 09:40 | dnolen | blashyrk: there are lot of ways to do this |
| 09:40 | blashyrk | also it seems that merge would automatically overwrite the values under the same keys |
| 09:41 | dnolen | you know the keys in the default map, you can get these keys, you can get the user supplied options keys |
| 09:41 | dnolen | you can set difference to figure out what precisely is going to be supplied by the user |
| 09:41 | justin_smith | blashyrk: merge goes in a predictable direction |
| 09:42 | dnolen | ,(merge {:default 'default} {:default 'custom}) |
| 09:42 | clojurebot | {:default custom} |
| 09:42 | justin_smith | blashyrk: the keys from a later argument in the list will not be replaced by keys earlier in the list |
| 09:42 | dnolen | ,(merge {:default 'default} {:other 'foo}) |
| 09:42 | clojurebot | {:default default, :other foo} |
| 09:42 | blashyrk | alright, that's one part of the problem solved :) |
| 09:43 | blashyrk | thanks guys |
| 09:43 | blashyrk | for the other part of the problem, let's keep it simple and say I just want to concatenate the two entries under the same key |
| 09:43 | justin_smith | blashyrk: merge-with |
| 09:44 | dnolen | ,(merge-with concat {:foo [1]} {:foo [2]}) |
| 09:44 | clojurebot | {:foo (1 2)} |
| 09:44 | blashyrk | ah |
| 09:44 | blashyrk | so the entire problem turned out to be a two-liner |
| 09:44 | blashyrk | thanks a lot |
| 09:45 | blashyrk | I have still a ways to go in terms of transferring my mindset from imperative to functional programming |
| 09:45 | justin_smith | it's worth it :) |
| 09:46 | justin_smith | the only drawback is that some things really do require imperative programming for pragmatic reasons, and you won't enjoy going back |
| 09:46 | puredanger | Bronsa: yt? |
| 09:46 | Bronsa | puredanger: yes, hi |
| 09:46 | puredanger | hey, I looked through your changes and they look good |
| 09:47 | puredanger | nice catch in that one read-tagged* case too :) |
| 09:48 | puredanger | I was just reading through the cljs change dnolen is working on and one thing I really don't like poking through over there is the knowledge of pending-forms |
| 09:48 | Bronsa | puredanger: what do you think about the TaggedLiteral/ReaderConditional change? |
| 09:48 | puredanger | that's fine |
| 09:49 | puredanger | the pending-forms stuff is purely an implementation detail and something that we've discussed alternative solutions for |
| 09:49 | Bronsa | right, I saw that in the cljs code too |
| 09:49 | puredanger | in the clojure one, the read arities that take that are private |
| 09:50 | puredanger | do you think we could pull the read arities that take pending-forms into a different private function? |
| 09:50 | puredanger | read-internal or something? |
| 09:50 | puredanger | we could either add an arity or cljs could call into the existing opts-only one - I've already recommended he do that |
| 09:50 | Bronsa | puredanger dnolen I don't think cljs needs to use that arity though, the opts+stream arity should be fine |
| 09:50 | puredanger | yes, that's what I'd recommend too |
| 09:51 | puredanger | but I don't want to expose the pending-forms ones so other people might use them |
| 09:51 | Bronsa | puredanger: current workaround is to inject custom arglists https://github.com/clojure/tools.reader/commit/eb5153cbaec849e726cdac0202c446380a21e19a#diff-c18d0a09dfeefd43739ea3593cf209d2R881 |
| 09:52 | Bronsa | moving the impl to a private read-internal is reasonable though |
| 09:52 | puredanger | seems easier to move those to private fn |
| 09:52 | puredanger | (the alternate impl we've talked about is having a reader that could wrap the pbr and allow you to pushback whole forms instead, rather than keeping the side buffer) |
| 09:52 | puredanger | we still might do that in the clojure one, but we didn't want to gate on getting around to that |
| 09:55 | ragge | mavbozo: sorry went away for a while. difference between tools.analyzer versions is huge (0.6.5 vs. 0.1.0-beta12) so I wouldn't be surprised if things expecting 0.6.5 would break |
| 09:56 | ragge | things like the core.async go macro, for instance |
| 09:56 | dnolen | puredanger: Bronsa: what does it need to look like, two arg read does not work |
| 09:57 | mavbozo | ragge, at least my problem gone when I exlude tools.analyzer from pedestal-service and then put core.async after pedestal |
| 09:57 | mavbozo | like this, https://www.refheap.com/99401 |
| 09:57 | Bronsa | dnolen: (read {:eof eof-sentinel} pbr) should work |
| 09:58 | mavbozo | ragge, might be related to this http://dev.clojure.org/jira/browse/ASYNC-86 |
| 09:58 | Bronsa | mavbozo: next core.async release will be t.a 0.6.5 compatible |
| 09:58 | dnolen | Bronsa: strange to flip the order for arity 2 but ok |
| 09:58 | Bronsa | dnolen: that's how c.c/read does it |
| 09:58 | dnolen | erg |
| 09:58 | puredanger | Bronsa: dnolen rich requested that for partial-ing |
| 09:59 | mavbozo | (inc ragge) ; for pointing the way to find which dependency which causes the problem |
| 09:59 | lazybot | ⇒ 1 |
| 09:59 | puredanger | mavbozo: that change has not yet been released in core.async |
| 10:02 | dnolen | puredanger: Bronsa: done |
| 10:05 | acron^ | noob question? |
| 10:05 | acron^ | how would I swap! using cons |
| 10:06 | acron^ | I can't seem to get the syntax quite right |
| 10:06 | justin_smith | ,(let [a (atom 1)] (swap! a cons '(2 3))) |
| 10:06 | Bronsa | dnolen: puredanger merging, will cut 0.9.0 in a couple of minutes |
| 10:06 | clojurebot | (1 2 3) |
| 10:06 | acron^ | using conj: (swap! my-atom conj new-value) |
| 10:07 | justin_smith | acron^: not particularly useful - cons requires the thing to be added as the first arg |
| 10:08 | acron^ | hmm, i suppose i could just use reverse... |
| 10:08 | justin_smith | why reverse? |
| 10:08 | justin_smith | if the collection is not a vector, conj will do the what you expect |
| 10:08 | justin_smith | just make sure you have the collection type with the behavior you require |
| 10:09 | acron^ | i want the item adding at the front of the collection, not the end |
| 10:09 | acron^ | that's all |
| 10:09 | justin_smith | ,(let [a (atom '(1))] (swap! a conj 0)) |
| 10:09 | clojurebot | (0 1) |
| 10:09 | justin_smith | acron^: right, like I said, if you have the right collection type, conj will do what you want |
| 10:09 | acron^ | interesting |
| 10:10 | justin_smith | acron^: conj is meant to add in the most efficient place |
| 10:10 | justin_smith | which is different for different collection types |
| 10:10 | acron^ | I see |
| 10:11 | acron^ | Are there any implicit differences for using a list over a vector? |
| 10:11 | acron^ | when using* |
| 10:11 | justin_smith | lists are not good for indexed lookup |
| 10:11 | acron^ | ok |
| 10:11 | acron^ | that's fine |
| 10:11 | acron^ | for my use case |
| 10:11 | acron^ | thanks justin! |
| 10:11 | justin_smith | np |
| 10:31 | m4farrel | is there a function like scan in clojure? i.e. reduce with a running total: (scan + 0 [1 2 3]) => [0 1 3 6] ? |
| 10:31 | justin_smith | m4farrel: reductions |
| 10:31 | justin_smith | ,(reductions + 0 [1 2 3]) |
| 10:31 | clojurebot | (0 1 3 6) |
| 10:32 | m4farrel | justin_smith: thanks |
| 10:52 | tap | Hi there, quick question. I want to gen-class that similar to this class https://github.com/properssl/java-jdbc-postgresql/blob/master/src/main/java/org/properssl/SingleCertValidatingFactory.java. What's the equivalent expression to `_factory = ...` in clojure? |
| 10:53 | tap | Modifying protected member of a super class |
| 10:53 | justin_smith | well, initializing right? |
| 10:54 | justin_smith | anyway, I think you would want reify or proxy, and inside that you can establish the values of fields |
| 10:54 | justin_smith | reify if WrappedFactory is an interface, proxy otherwise |
| 10:57 | tap | Ok. WrappedFactory is an abstract class. Thanks for pointing out that I shouldn't use gen-class here. Good to know that I was learning the wrong thing for this. |
| 10:57 | tap | Need to reread a bit more about proxy |
| 10:58 | justin_smith | tap: it would be possible with gen-class, but gen-class usually isn't the easier way to do something - best reserved as the last resort before writing java code |
| 11:02 | tap | justin_smith: I got a (wrong) impression that proxy is for creating an object. What I want is a class to replace 'NonValidatingFactory' in `sslfactory=org.postgresql.ssl.NonValidatingFactory` . FYI, I'm refering from this document https://jdbc.postgresql.org/documentation/81/ssl-client.html |
| 11:04 | justin_smith | tap: oh, if you specifically need a class and not a class instance, then you I think you'll need gen-class |
| 11:07 | tap | justin_smith: Ok. So for gen-class, I should be able to set `_factory` from `init` function, right? I can't really find an example to do that. |
| 11:07 | justin_smith | tap: for your initial question, you want the :exposes key to gen-class if you are creating a field that must be visible |
| 11:08 | tap | justin_smith: please disregard my previous message, didn't saw your recent one. |
| 11:09 | justin_smith | also, see the :state key if you need to create a field |
| 11:09 | justin_smith | and :init for setting fields of the superclass |
| 11:11 | justin_smith | so if you need to set something protected on the parent, you create a setter with :exposes and then call it in your :init |
| 11:11 | justin_smith | tap: if you haven't seen it, conj.io is helpful in general http://conj.io/store/v1/org.clojure/clojure/1.7.0-alpha4/clj/clojure.core/gen-class/ |
| 11:15 | ircxy | ,(Math/pow 1.4 1/3) |
| 11:15 | clojurebot | 1.1186889420813968 |
| 11:15 | ircxy | ,(let [y 3] (Math/pow 1.4 1/y)) ; fails |
| 11:15 | clojurebot | #<NumberFormatException java.lang.NumberFormatException: Invalid number: 1/y> |
| 11:15 | tap | justin_smith: conj.io looks nice. I like the syntax highlight. Never heard about it before. For some reason, it never hit my search result |
| 11:15 | justin_smith | ircxy: x/y is not a function call, it is a syntax for literals |
| 11:16 | justin_smith | ircxy: you can't embed a symbol in that kind of numeric literal |
| 11:16 | ircxy | Is there a way to use a var in a fraction? |
| 11:16 | justin_smith | ircxy: it's the equivalent of (let [x 9] 1.x) |
| 11:16 | justin_smith | ircxy: sure, use the / function |
| 11:17 | justin_smith | tap: it's a relatively recent thing, but arrdem puts a lot of work into it |
| 11:17 | justin_smith | ,(let [y 3] (/ y)) |
| 11:17 | clojurebot | 1/3 |
| 11:17 | ircxy | justin_smith: right on! ,(/ 1 3) |
| 11:17 | justin_smith | ircxy: it's special cased so that (/ x) is the same as (/ 1 x) |
| 11:17 | justin_smith | which is the most frequent usage, so that's cool |
| 11:18 | ircxy | justin_smith: very cool,thanks! |
| 11:18 | justin_smith | ,(/ (/ 20)) |
| 11:18 | clojurebot | 20N |
| 11:18 | justin_smith | :) |
| 11:18 | justin_smith | ,(iterate / 20) |
| 11:18 | clojurebot | (20 1/20 20N 1/20 20N ...) |
| 11:19 | tap | justin_smith: thanks for pointing out :exposes. I'll learn more about it tomorrow. It's late night here |
| 11:27 | dnolen | Clojure 0.0-3190 pre-release going out to Maven and available here https://github.com/clojure/clojurescript/releases/tag/r3190 |
| 11:27 | dnolen | includes conditional reading support, which touched many things |
| 11:28 | dnolen | so needs some serious tire kicking. If no bad news, would like cut a proper release tomorrow |
| 11:29 | dnolen | er s/Clojure/ClojureScript of course |
| 11:29 | saik0 | Any book recommendations for somebody familiar with java and lisps (scheme in my case), nice and terse? |
| 11:30 | justin_smith | ~books |
| 11:30 | clojurebot | books is programming clojure |
| 11:31 | justin_smith | there's also "joy of clojure" which shows more common lisp influence and takes a more erudite approach |
| 11:31 | justin_smith | that is, it kind of expects you either know things its referencing or can go read up yourself |
| 11:31 | justin_smith | not that it's a dissertation or anything, just less beginner focused |
| 11:32 | saik0 | justin_smith: thanks |
| 11:32 | tbaldridge | saik0: if you know Java and Scheme, I highly recommend Joy of Clojure... |
| 11:32 | justin_smith | yeah, it's a great book if you don't let it intimidate you :) |
| 11:32 | tbaldridge | like justin_smith said, it gets rather advanced rather quickly, but sounds like that's what you want/need |
| 11:35 | saik0 | tbaldridge: right, I'm mostly concerned with poking Clojure's macros and concurrency/parallism. not a 5 chapter into to functional programming. sounds up my alley thanks both of you. |
| 12:46 | crazydiamond | Hi. Is there way to beautify (pretty-print) bunch of data in Clojure other than clojure/pprint.prrint? It fails for me, while println works well |
| 12:47 | justin_smith | crazydiamond: fails? |
| 12:47 | justin_smith | crazydiamond: are you trying to supply multiple arguments? the solution is to pprint each thing separately, or put them all in one vector or hash-map |
| 12:48 | crazydiamond | justin_smith, StackOverflow errr |
| 12:48 | crazydiamond | *error |
| 12:48 | justin_smith | oh, wow |
| 12:48 | justin_smith | infinite lazyseq? |
| 12:48 | crazydiamond | justin_smith, may be, yes, something lazy |
| 12:48 | crazydiamond | though unlikely infinite |
| 12:49 | crazydiamond | may I... make all lazy stuff non-lazy? |
| 12:49 | crazydiamond | must I postwalk or something? but with what func |
| 12:49 | justin_smith | if you fully realize the collection via walk/post-walk, do you get the same error? |
| 12:49 | justin_smith | or just walk/tree-seq |
| 12:49 | justin_smith | ,(require 'clojure.walk) |
| 12:49 | clojurebot | nil |
| 12:50 | justin_smith | ,(clojure.walk/tree-seq {:a 0 :b [1 2 3]}) |
| 12:50 | clojurebot | #error{:cause "No such var: clojure.walk/tree-seq", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.RuntimeException: No such var: clojure.walk/tree-seq, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyze "Compiler.java" 6535]} {:type java.lang.RuntimeException, :message "No such var: clojure.walk/tree-seq", :at [clojure.lang.Util runtimeException "Util.j... |
| 12:50 | justin_smith | err |
| 12:50 | justin_smith | ,(tree-seq {:a 0 :b [1 2 3]}) |
| 12:50 | clojurebot | #error{:cause "Wrong number of args (1) passed to: core/tree-seq", :via [{:type clojure.lang.ArityException, :message "Wrong number of args (1) passed to: core/tree-seq", :at [clojure.lang.AFn throwArity "AFn.java" 429]}], :trace [[clojure.lang.AFn throwArity "AFn.java" 429] [clojure.lang.AFn invoke "AFn.java" 32] [sandbox$eval72 invoke "NO_SOURCE_FILE" -1] [clojure.lang.Compiler eval "Compiler.ja... |
| 12:51 | justin_smith | ,(tree-seq coll? seq {:a 0 :b [1 2 3]}) |
| 12:51 | clojurebot | ({:a 0, :b [1 2 3]} [:a 0] :a 0 [:b [1 2 3]] ...) |
| 12:51 | crazydiamond | yep |
| 12:51 | justin_smith | yep as in you do get the same error? |
| 12:51 | crazydiamond | 1 sec |
| 12:52 | crazydiamond | yes |
| 12:52 | justin_smith | right, so there is a problem with the code generating one of your lazy-seqs I think |
| 12:53 | crazydiamond | I was thinking to turn it into the str and parse |
| 12:53 | crazydiamond | LOL |
| 12:53 | crazydiamond | but I don't have anything like (range) though |
| 12:54 | justin_smith | concat? sometimes nested concat calls can lead to weirdness (especially if you had something chunked like range or a vector going in) |
| 12:54 | crazydiamond | uhm, a lot of vecs |
| 12:55 | hiredman | crazydiamond: have you tried fipp? |
| 12:55 | hiredman | https://github.com/brandonbloom/fipp |
| 12:55 | crazydiamond | no |
| 12:55 | crazydiamond | hiredman, thanks! |
| 12:56 | bbloom | crazydiamond: if fipp doesn't work for you, please file an issue w/ a minimal repo |
| 12:57 | crazydiamond | bbloom, hiredman works! excellent |
| 13:00 | noncom | can anyone confirm that when you add [selmer "0.8.2"] to your project.clj and then (:require [selmer.parser :as selmer]) in some ns of your project, you get an exception of classloading ? |
| 13:00 | justin_smith | (inc bbloom) |
| 13:00 | lazybot | ⇒ 54 |
| 13:17 | noncom | nope, spotted |
| 13:19 | mavbozo | noncom, you found the culprit? |
| 13:20 | noncom | mavbozo: yes, had to manually delete the "bin" and "target" folders.. |
| 13:33 | michaler` | suddenly cursive went crazy indenting defn and def |
| 13:33 | michaler` | anyone else experience this? |
| 13:33 | michaler` | I think it's related to the latest release which I've updated today |
| 13:34 | michaler` | cfleming: ping |
| 13:36 | KKalem | You sure you don't have an open paren above somewhere? |
| 13:39 | michaler` | KKalem: pretty sure, it's also shown like that in the preview in the settings screen |
| 13:40 | michaler` | can I downgrade to a previous version with cursive? |
| 13:46 | michaler` | ah it's in the usersguid |
| 13:46 | michaler` | guide |
| 13:51 | cljnoob | I have implemented a "frequencies" like function using reduce... I based it off the example listed on the reduce function documentation. http://pastie.org/10082946 My question is in regard to line 3: " (fn [hm char] (assoc hm char (inc (hm char 0))))". Why is 0 a second argument to the (hm char 0) function call? |
| 13:52 | justin_smith | cljnoob: ##({:a 1} :a 0) |
| 13:52 | lazybot | ⇒ 1 |
| 13:52 | justin_smith | cljnoob: ##({} :a 0) |
| 13:52 | lazybot | ⇒ 0 |
| 13:52 | justin_smith | (doc get) |
| 13:52 | clojurebot | "([map key] [map key not-found]); Returns the value mapped to key, not-found or nil if key not present." |
| 13:53 | cljnoob | ah, it's a default value. make sense |
| 13:53 | justin_smith | ,(update-in {} [\a] (fnil inc 0)) |
| 13:53 | clojurebot | {\a 1} |
| 13:53 | justin_smith | another way to express that assoc |
| 13:54 | justin_smith | though fnil should be pulled out to a binding if this is a tight loop |
| 13:54 | justin_smith | iirc |
| 13:54 | michaler` | it didn't help |
| 13:54 | michaler` | damn |
| 13:55 | cljnoob | justin_smith:i'll play around with it. Thanks! |
| 13:55 | justin_smith | michaler`: you're absolutely certain you don't have something in there that messes up the indentation? extra open parens? |
| 13:55 | justin_smith | or maybe some missing close paren |
| 13:55 | michaler` | justin_smith: nope, it happens in every file |
| 13:55 | justin_smith | weird |
| 13:56 | michaler` | maybe I accidently pressed some key combination that changed something in Intellij |
| 13:56 | justin_smith | michaler`: my attitude to IDEs in general is kind of like that ancient aliens guy "IDEs" (complete with crazy hair and waving hands) |
| 13:57 | michaler` | heh |
| 13:57 | michaler` | justin_smith: your attitude to IDEs doesn't help me solve my problem ;) |
| 13:58 | KKalem | justin_smith, you need an IDE with an attitude~ |
| 13:58 | justin_smith | clearly the IDE gods have cursed your intellij installation, and you need to delete some fetish file, or offer it a fresh dead chicken |
| 13:58 | andyf | michaler`: It does if you stop using IDEs :) |
| 14:03 | constl | Is there a way to evaluate an argument inside a string ? |
| 14:04 | justin_smith | constl: you can use (eval (read-string s)) but usually eval is the wrong thing |
| 14:04 | justin_smith | ~eval |
| 14:04 | clojurebot | eval is sometimes useful - but only sometimes |
| 14:05 | constl | Maybe "evaluate" was a wrong choice of word |
| 14:05 | constl | hmm |
| 14:06 | justin_smith | constl: what do you want done? conversion of string to integers / symbols / keywords? read-string suffices for that |
| 14:06 | constl | (let [my-name "Konstantinos"] (print "Hello my-name !) |
| 14:06 | justin_smith | well, you don't even need to covnert anything for that |
| 14:06 | justin_smith | *convert |
| 14:06 | constl | I recal something that i have to put before my-name so that it prints the value instead of the literal |
| 14:07 | justin_smith | absolutely not |
| 14:07 | constl | no? |
| 14:07 | clojurebot | no is tufflax: there was a question somewhere in there, the answer |
| 14:07 | justin_smith | ,(let [my-name "Konstantinos"] (println "hello" my-name \!)) |
| 14:07 | clojurebot | hello Konstantinos !\n |
| 14:08 | justin_smith | if you want the literal instead of the value, you can use ' |
| 14:08 | justin_smith | ,(let [my-name "Konstantinos"] (println "hello" 'my-name \!)) |
| 14:08 | clojurebot | hello my-name !\n |
| 14:08 | constl | justin_smith: Is there a way to use print with only one argument and have my-name somehow print the value? |
| 14:09 | justin_smith | you mean string interpolation? |
| 14:09 | justin_smith | we have format |
| 14:09 | justin_smith | or various templating libs I guess |
| 14:10 | justin_smith | ,(let [my-name "Konstantinos"] (println (format "hello %s" my-name))) |
| 14:10 | clojurebot | hello Konstantinos\n |
| 14:11 | justin_smith | something like eg. selmer will let you use "hello {{my-name}}" or something close to it |
| 14:11 | constl | Can you print the value by only using this form (print "Hello, <my-name-value> !") |
| 14:11 | justin_smith | constl: you'd need a templating lib for anything like that |
| 14:12 | justin_smith | not something immediately available in clojure.core |
| 14:12 | constl | I recall something like \" " or something like that |
| 14:12 | justin_smith | and no, you would not be able to do that with just print either |
| 14:12 | justin_smith | constl: that's just a way to put " in a string |
| 14:12 | justin_smith | and it still involves multiple args |
| 14:13 | justin_smith | ,(let [my-name "Konstantinos"] (println (str "hello " my-name))) |
| 14:13 | clojurebot | hello Konstantinos\n |
| 14:13 | justin_smith | there's always that, but that's not much different than just using multiple args to println |
| 14:15 | danielglauser | And multiple args to println will put spaces in there |
| 14:15 | danielglauser | ,(let [my-name "Konstantinos"] (println (str "hello " my-name))) |
| 14:15 | clojurebot | hello Konstantinos\n |
| 14:15 | danielglauser | ,(let [my-name "Konstantinos"] (println (str "hello " my-name "!"))) |
| 14:15 | clojurebot | hello Konstantinos!\n |
| 14:15 | danielglauser | Doh! Third try... |
| 14:16 | danielglauser | ,(let [my-name "Konstantinos"] (println "hello" my-name "!"))) |
| 14:16 | clojurebot | hello Konstantinos !\n |
| 14:16 | danielglauser | IMHO format is the idiomatic way to do what you are looking to do |
| 14:18 | constl | thanks for the help all |
| 14:22 | oddcully | ,(let [rep {"name" "World" "greeting" "Hello"}] (clojure.string/replace "<greeting> <name>" #"<(.*?)>" #(get rep (%1 1)))) |
| 14:22 | clojurebot | "Hello World" |
| 14:24 | justin_smith | oddcully: nice |
| 14:25 | oddcully | constl: ^^ poor mans version of what you are after; yet i'd rather go for some template engine |
| 14:28 | cfleming | michaler`: Did you get that fixed? |
| 14:43 | michaler` | cfleming: hi |
| 14:43 | michaler` | cfleming: no.. |
| 14:44 | michaler` | cfleming: I checked "default to indent only" as a temp workaround |
| 14:44 | michaler` | cfleming: do you have an idea? |
| 14:46 | cfleming | michaler`: Are you getting a lot of unresolved symbols? |
| 14:46 | michaler` | cfleming: nope |
| 14:46 | michaler` | cfleming: everything works as usual |
| 14:46 | cfleming | michaler`: Ok - are you using leiningen? |
| 14:46 | michaler` | yes |
| 14:47 | michaler` | is there another way? :) |
| 14:47 | michaler` | yes of course there is.. |
| 14:47 | cfleming | Ok, is your lein project present in your Leiningen toolwindow? |
| 14:47 | michaler` | let me check |
| 14:47 | michaler` | yes, it's there |
| 14:47 | michaler` | as usual |
| 14:47 | cfleming | Hehe, yes - I don't use lein for Cursive, although I do use it to fetch the deps |
| 14:48 | cfleming | Weird - so what's the problem that you're seeing? |
| 14:48 | michaler` | cfleming: would you like to do a remote session? |
| 14:48 | michaler` | teamviewer? |
| 14:49 | cfleming | michaler`: I'm just about to head in to the office, it would have to be in about 30-45 mins |
| 14:49 | michaler` | cfleming: the problem is that although def/defn is set to ident only, they are formated as if they are set to 1 |
| 14:49 | michaler` | cfleming: ok, cool |
| 14:51 | cfleming | michaler`: Ok, if you got to Settings->Editor->Code Style->Clojure->Form parameters, what are def and defn set to? |
| 14:51 | michaler` | cfleming: indent |
| 14:52 | cfleming | michaler`: Well that is really weird. Is this problem when you hit enter while typing the form, or when you reformat the whole file? |
| 14:52 | cfleming | michaler`: Is the code open or is it a work thing? |
| 14:52 | cfleming | michaler`: Does this happen for other projects as well? |
| 14:53 | michaler` | shit |
| 14:53 | michaler` | it's gone |
| 14:54 | michaler` | sorry |
| 14:54 | michaler` | err |
| 14:54 | cfleming | michaler`: The problem is gone? |
| 14:54 | michaler` | yes.. |
| 14:54 | cfleming | Well that's good :-) |
| 14:54 | cfleming | What I suspect has happened is that the indexes might have gotten in a funky state after the update |
| 14:54 | michaler` | i started checking if it happens only on reformat and then it's gone |
| 14:55 | cfleming | Try File->Invalidate caches and restart, which will force them to be rebuilt |
| 14:55 | michaler` | cfleming: yes, it's possible.. I also had a dirty shutdown of the coputer after which intellij complained about some corrupted files |
| 14:55 | cfleming | Just ignore the crazy guy in the corner |
| 14:55 | justin_smith | :) |
| 14:55 | michaler` | cfleming: but it happened this morning.. |
| 14:56 | cfleming | michaler`: Oh ok, I bet that was it then |
| 14:57 | michaler` | cfleming: ok, thanks |
| 14:57 | michaler` | cfleming: when can I start paying you for Cursive? :) |
| 14:58 | cfleming | michaler`: Soon, I think - sometime after Clojure/West :) |
| 14:58 | timvisher | i _should_ be able to override `:uberjar-name` in a project.clj profile right? |
| 14:59 | michaler` | cfleming: ah, ok.. then I'll patiently wait ;) |
| 15:00 | mavbozo | timvisher, yep |
| 15:00 | michaler` | justin_smith: btw, I hope you are not suggesting emacs as the cure for IDEs.. |
| 15:00 | timvisher | mavbozo: good :) |
| 15:00 | justin_smith | michaler`: oh, absolutely not |
| 15:00 | justin_smith | I'm just being a jackass :) |
| 15:00 | michaler` | heh |
| 15:01 | justin_smith | michaler`: cider has had issues that could compete with any IDE's worst |
| 15:01 | michaler` | yeah, it true.. and emacs is a nightmare on it's own.. |
| 15:02 | amalloy | justin_smith confirmed trouble-maker |
| 15:09 | andyf | I'm not recommending it to anyone that wants IDE-like features, but emacs + clojure-mode is all I use |
| 15:10 | constl | Is there a way to get the number of arguments passed in a function with variadic arity? |
| 15:11 | justin_smith | constl: ##((fn [& args] (count args)) [1 2 3]) |
| 15:11 | lazybot | ⇒ 1 |
| 15:11 | justin_smith | constl: ##((fn [& args] (count args)) 1 2 3) |
| 15:11 | lazybot | ⇒ 3 |
| 15:14 | constl | ##((fn [one two & args] (count args)) [1 2 3]) |
| 15:14 | lazybot | clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox6330/eval46602/fn--46603 |
| 15:16 | ncthom91 | hi all. Suppose I have a project wherein I define a simple value at the top of my file.. how can I override/mock that value during testing? |
| 15:17 | justin_smith | ncthom91: you can use with-redefs for that |
| 15:17 | justin_smith | ncthom91: also worth considering is writing your functions so that the concrete impl that would change at test vs. runtime is a parameter you explicitly pass in |
| 15:18 | justin_smith | and of course defining a trivial wrapper for typical usage |
| 15:18 | justin_smith | makes testing that much simpler |
| 15:19 | mavbozo | ncthom91, there are many ways of managing external dependencies for testing which you can read here http://blog.josephwilk.net/clojure/isolating-external-dependencies-in-clojure.html |
| 15:19 | justin_smith | eg. (defn printer [stream string] (.write stream string)) (def printit (partial printer *out*)) |
| 15:21 | justin_smith | (inc mavbozo) ; good link, where'd you find it? |
| 15:21 | lazybot | ⇒ 6 |
| 15:23 | mavbozo | i spent months studying ways to do dependency injection in clojure until i settle for stuart sierra's approach |
| 15:24 | mavbozo | i think a read almost blog posts |
| 15:24 | ncthom91 | hmm cool ok |
| 15:24 | mavbozo | s/a/i/ |
| 15:27 | hellofunk | if i have (map #(some-fn % (some-op foo bar)) coll) will the (some-op foo bar) run with each pass over a collection item, or does (some-op foo bar) evaluate once into the whole of the map fn? |
| 15:28 | Kowryh | what clojure resources would you guys recommend beside the obvious ones (e.g. the docs) |
| 15:28 | mavbozo | Kowryh, books |
| 15:28 | Kowryh | https://thechangelog.com/rich-hickeys-greatest-hits/ i've yet to watch these, though supposedly they're pretty good |
| 15:29 | mavbozo | Kowryh, infoq videos about clojure |
| 15:29 | justin_smith | hellofunk: easy to test ##(map #(cons % (println "check")) (range 10)) |
| 15:29 | lazybot | ⇒ (check |
| 15:29 | justin_smith | oops |
| 15:29 | justin_smith | hellofunk: easy to test ##(map #(cons % (print "check")) (range 10)) |
| 15:29 | lazybot | ⇒ (checkcheckcheckcheckcheckcheckcheckcheckcheckcheck(0) (1) (2) (3) (4) (5) (6) (7) (8) (9)) |
| 15:29 | hellofunk | lazybot is rich! it just wrote a bunch of checks |
| 15:30 | justin_smith | also, that was some terrible nil punning, before you brought the regular punning in |
| 15:30 | Kowryh | mavbozo: specifically what book(s)? |
| 15:30 | Kowryh | if I were to read only one (for a start) |
| 15:31 | Kowryh | but thanks, I'll have to check those infoq videos out |
| 15:31 | mavbozo | Kowryh, depends on your previous experience with functional programming languages |
| 15:31 | Kowryh | well it's non-existent |
| 15:31 | Kowryh | (but yeah I should have mentioned that) |
| 15:31 | mavbozo | well, clojure programming or programming clojure |
| 15:32 | Kowryh | thanks, I'll look into those |
| 15:39 | ncthom91 | what's the motivation behind putting *earmuffs* on your variable name? |
| 15:40 | sobel | ncthom91: keeps ears warm |
| 15:40 | ncthom91 | :) |
| 15:40 | justin_smith | ,(def *t* 1) |
| 15:40 | tbaldrid_ | ncthom91: that normally means that it's a dynamic var, and may be re-bound within a given scope |
| 15:40 | clojurebot | #error{:cause "denied", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6732]} {:type java.lang.SecurityException, :message "denied", :at [clojurebot.sandbox$enable_security_manager$fn__835 invoke "sandbox.clj" 69]}], :trace [[clojurebot.sandbox$enable_securit... |
| 15:41 | ncthom91 | tbaldrid_ so, convention? |
| 15:41 | sobel | also helps syntax highlighters find more important variables |
| 15:41 | sobel | ncthom91: definitely a convention |
| 15:41 | tbaldrid_ | ncthom91: yeah, it's convection |
| 15:41 | justin_smith | ncthom91: the usual message for (def *t* 1) would be "Warning: *t* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise." |
| 15:41 | ncthom91 | would people use it to identify a variable intended for a with-redefs call in a test suite? |
| 15:41 | sobel | for example, yes |
| 15:41 | justin_smith | ncthom91: well, you wouldn't need with-redefs |
| 15:41 | tbaldrid_ | althought, IIRC the compiler does warn you if you create a dynamic var without earmuffs |
| 15:41 | justin_smith | you could just use binding |
| 15:42 | sobel | or most of the with- family of fcns |
| 15:42 | justin_smith | tbaldrid_: yeah, the warning I was trying to provoke before, but I got bot weirdness instead |
| 15:42 | ncthom91 | justin_smith oh, true |
| 15:42 | sobel | it's a common/useful pattern |
| 15:42 | ncthom91 | and the ^:dynamic declaration enables binding right? |
| 15:42 | justin_smith | right, and it goes with earmuffs |
| 15:43 | sobel | i like that, earmuffs. i'm going to call the thread macro buttplug. |
| 15:43 | sobel | threadfirst |
| 15:44 | ncthom91 | sobel lol what?? how did we get from earmuffs to buttplug |
| 15:44 | sobel | 'we' didn't |
| 15:45 | ncthom91 | sorry, you :) |
| 15:46 | sobel | easily! |
| 15:54 | puredanger | tbaldrid_: doesn't it warn if you use earmuffs for a NON-dynamic var? |
| 15:55 | puredanger | ,(def *foo* 1) |
| 15:55 | clojurebot | #error{:cause "denied", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6732]} {:type java.lang.SecurityException, :message "denied", :at [clojurebot.sandbox$enable_security_manager$fn__835 invoke "sandbox.clj" 69]}], :trace [[clojurebot.sandbox$enable_securit... |
| 15:55 | justin_smith | puredanger: yeah, I tried to do that above |
| 15:55 | tbaldrid_ | yep, it's the other way around |
| 15:55 | justin_smith | clojurebot is a weirdo |
| 15:55 | puredanger | sorry :) |
| 15:55 | tbaldrid_ | puredanger: is right |
| 15:55 | tbaldrid_ | eh... puredanger is right |
| 15:56 | justin_smith | ~puredanger is right. |
| 15:56 | clojurebot | Ik begrijp |
| 15:56 | mavbozo | ~earmuffs |
| 15:56 | clojurebot | Titim gan éirí ort. |
| 16:26 | akkad | in clojure is (sleep 200) the right format? |
| 16:26 | mavbozo | ,(doc sleep) |
| 16:26 | clojurebot | excusez-moi |
| 16:27 | justin_smith | akkad: (Thread/sleep 200) |
| 16:27 | justin_smith | for jvm clojure |
| 16:27 | justin_smith | it's an interop call |
| 16:27 | akkad | thanks |
| 16:28 | dnolen | Bronsa: ping |
| 16:30 | Bronsa | dnolen: pong |
| 16:32 | dnolen | Bronsa: so any reason (def arr #?(:cljs #js [1 2 3])) might not work? |
| 16:33 | dnolen | Bronsa: nothing changed w/ how we bind *data-readers*, the above will read as (def arr [1 2 3]) |
| 16:33 | andyf | dnolen: Doesn't splicing need slightly different syntax? |
| 16:34 | dnolen | andyf: this isn't a splicing question |
| 16:35 | Bronsa | dnolen: what's not working? I just tried this and it works as expected http://sprunge.us/AZGX?clj |
| 16:35 | dnolen | Bronsa: that isn't right |
| 16:35 | Bronsa | why? |
| 16:35 | clojurebot | why is the ram gone |
| 16:35 | the-kenny | dnolen: I have a complaint: Why do you always do awesome ClojureScript releases right when I don't have any time to dive into them? |
| 16:37 | dnolen | Bronsa: I mean I should see a JSValue in ClojureScript but getting a vector instead |
| 16:37 | Bronsa | ah |
| 16:39 | Bronsa | dnolen: uh yeah there's definitely a bug there |
| 16:41 | rurumate | Is there something similar to core.logic which produces a (sequence of) random value(s), instead of a list of all values that match the conditions? This would be very useful for unit testing. |
| 16:41 | dnolen | the-kenny: :), the hard work on this one was done by other people, can't take much credit for this one. Just had to make sure .cljc files can be consumed. |
| 16:42 | justin_smith | rurumate: maybe you want generators? |
| 16:42 | rurumate | I'll check it out thanks |
| 16:42 | justin_smith | rurumate: https://github.com/clojure/test.generative this is what I meant |
| 16:43 | justin_smith | rurumate: see also test.chuck from gfredericks |
| 16:45 | mavbozo | wow! a name from a tv series |
| 16:45 | rurumate | I'm looking for something that also generates csv data and strings that match a given pattern, like Xeger |
| 16:45 | justin_smith | rurumate: test.chuck can generate strings that match a regex |
| 16:46 | rurumate | so for instance you could say, I need a list of random vectors [a, b] where a is a number 0 <= a <= 10 and b is (* a 2) |
| 16:46 | justin_smith | yes, test.check can do that |
| 16:47 | mavbozo | (inc gfredericks) |
| 16:47 | lazybot | ⇒ 135 |
| 16:52 | programisto | reatlively simple clojure problem here |
| 16:52 | programisto | https://gist.github.com/aaron-lebo/720345a76d08faad4b13 |
| 16:52 | programisto | any help appreciated |
| 16:53 | programisto | *spelling |
| 16:53 | justin_smith | programisto: looks like you want something more like mapcat |
| 16:53 | justin_smith | rather than map |
| 16:54 | justin_smith | programisto: also, it would have worked if you used "apply concat" instead of just "concat" |
| 16:54 | justin_smith | but that's what mapcat is for, so just use that |
| 16:54 | programisto | justin_smith: thank you |
| 16:54 | programisto | exactly what i needed |
| 16:54 | justin_smith | ,(apply concat (map #(vector " " %1) [1 2])) |
| 16:54 | clojurebot | (" " 1 " " 2) |
| 16:55 | justin_smith | ,(mapcat #(list " " %) [1 2])) |
| 16:55 | clojurebot | (" " 1 " " 2) |
| 16:55 | justin_smith | latter is my preferred version, of course |
| 16:55 | programisto | yep it diefnitely worked |
| 16:56 | programisto | i figured something existed, couldn't find it via google |
| 16:58 | justin_smith | programisto: conj.io is really useful for this stuff |
| 16:58 | justin_smith | http://conj.io/ |
| 17:08 | Bronsa | dnolen: should be fixed, can you try master? will release 0.9.1 once you confirm it works |
| 17:08 | dnolen | Bronsa: trying now |
| 17:15 | TimMc | justin_smith: Or just use fl-- *is hit by anvil* |
| 17:15 | justin_smith | (inc anvil) |
| 17:15 | lazybot | ⇒ 1 |
| 17:16 | justin_smith | (inc TimMc) |
| 17:16 | lazybot | ⇒ 94 |
| 17:16 | ntaylor | haah |
| 17:19 | dnolen | Bronsa: fixed |
| 17:21 | TimMc | (flatten 5) ;;= [1 1 1 1 1] |
| 17:28 | justin_smith | (flatten {:width 1 :height 1 :depth 1}) ;;= {:width 1 :height 1 :depth 0} |
| 17:30 | TimMc | (flatten "a") ;;= ? |
| 17:30 | TimMc | \_ |
| 17:33 | amalloy | TimMc: () would be my guess, but i forget |
| 17:33 | amalloy | oh i just got here, you are in some weird fantasy land |
| 17:33 | TimMc | this should be no surprise |
| 17:33 | justin_smith | haha |
| 17:34 | TimMc | ,(flatten 5) ;; actually |
| 17:34 | clojurebot | () |
| 17:37 | justin_smith | wow, even logicians have a lot of trouble with concurrency and mutability http://en.wikipedia.org/wiki/Yale_shooting_problem |
| 17:38 | dnolen | ClojureScript 0.0-3191 going out https://github.com/clojure/clojurescript/releases/tag/r3191, only change is tools.reader bump |
| 17:39 | TimMc | justin_smith: That's a terrible article. |
| 17:39 | TimMc | it should feel bad |
| 17:41 | justin_smith | TimMc: yes, it's a badly written article |
| 17:42 | justin_smith | here's another writeup http://web.stanford.edu/~laurik/fsmbook/examples/YaleShooting.html |
| 17:43 | justin_smith | I think the clojure program demonstrating the concept would be pretty short. An agent would be a decent fit. |
| 17:44 | kwladyka | on http://www.clojure-toolbox.com/ there is about 15 web frameworks... why? Are they diffrent or really almost the same? |
| 17:44 | justin_smith | kwladyka: they are not all frameworks. For example Moustache is a templating language. |
| 17:44 | justin_smith | Some of them are defunct. |
| 17:45 | justin_smith | Actually, I think most of them on that list are defunct. |
| 17:45 | kwladyka | hmm |
| 17:45 | justin_smith | clojure-toolbox should really have a "last updated" date |
| 17:46 | kwladyka | i found some atricles, but with data 2014 or older... can you give me some names of web framework what should i be interested in? |
| 17:46 | kwladyka | justin_smith yes it should :) |
| 17:46 | justin_smith | kwladyka: most clojure web devs are not using a framework. There are a number of useful libs. Most of them are compatible with or even dependent on ring. |
| 17:47 | justin_smith | ring being the underlying web-server abstraction that is by far most popular |
| 17:47 | kwladyka | hmm so are suggesting to use only ring? |
| 17:47 | justin_smith | compojure is the most popular routing lib. You can do a lot with just compojure and ring (or switch to another router if you get tired of compojure) |
| 17:48 | kwladyka | so use ring + other libs working with ring if i need them? |
| 17:48 | justin_smith | kwladyka: compojure+ring is the most frequent combo I think, but after you get the basics, there are other routing libs too (if you need reverse routing, or dynamically generated routes for example) |
| 17:48 | justin_smith | right |
| 17:48 | xemdetia | since we are talking about ring is there any neat way to get some verbose build output for lein ring uberwar that I am not seeing? |
| 17:48 | justin_smith | kwladyka: lein new compojure some-name will create a working compojure app |
| 17:49 | justin_smith | xemdetia: not that I know of, are you having some issue with what uberwar does? |
| 17:50 | dnolen | Nice https://github.com/LonoCloud/synthread/blob/master/test/lonocloud/synthread/test.cljc |
| 17:51 | xemdetia | justin_smith, I brought nrepl into my project which is a slew of dependencies but it does not seem like it is ever finishing. I am not seeing io wait or java spinning |
| 17:51 | kwladyka | justin_smith i am thinking about architecture in Clojure. I am reallny not happy with MVC. I believe app should have separated core, UI and database, but.... i am not sure how to build architecure of folders, files, namespaces etc. in Clojure but i feel Clojure will give me power for that :) Can you recommend something to read with example of architecture? |
| 17:52 | justin_smith | in clojure we tend to do things less in terms of architecture and more in terms of well known operations on simple immutible data types |
| 17:52 | kwladyka | justin_smith i can use AngularJS, Clojure, DB it will be easier but if use only Clojure and DB putting HTML into code make me a little confuse how to do that in right way |
| 17:52 | justin_smith | this is a very broad generalization of course |
| 17:52 | TimMc | dnolen: Does that achieve having a common source file for clj and cljs? |
| 17:53 | justin_smith | xemdetia: you probably do something like (def server (nrepl/start-server)) and that starts a listening server when you compile |
| 17:53 | xemdetia | that would explain it |
| 17:53 | justin_smith | xemdetia: that's a blind guess, but that's a common source of that problem |
| 17:53 | xemdetia | no the project is pretty much just that. I just want a nice way to shim my tomcats |
| 17:54 | cfleming | ping puredanger |
| 17:54 | puredanger | yo |
| 17:54 | justin_smith | xemdetia: if that is the issue, the fix is to have a delay for the nrepl server, that gets forced in -main |
| 17:54 | justin_smith | xemdetia: or a promise that gets delivered if you need parameterization or anything |
| 17:55 | xemdetia | or a dumb route get request to switch it on |
| 17:55 | puredanger | cfleming: question? |
| 17:55 | justin_smith | xemdetia: sure, sure |
| 17:55 | cfleming | puredanger: I have a reader conditional question: currently I can't see a way that "send top form to REPL" will work with them, since the REPL doesn't know the file type the form came from. |
| 17:55 | justin_smith | xemdetia: but that's compatible with a dleay |
| 17:55 | justin_smith | xemdetia: idea being it's simpler to know that there is only one thing this def could be (even if it isn't realized until later) |
| 17:56 | puredanger | cfleming: that was raised by someone on the google group |
| 17:56 | justin_smith | compare with doing def at runtime, or using a mutable datatype - much more complex |
| 17:56 | puredanger | cfleming: I talked to Rich about it briefly and we're considering some way to be able to make the repl understand that |
| 17:56 | cfleming | puredanger: It was? I didn't see that - I'll check. |
| 17:57 | puredanger | it was a response on the alpha6 release iirc |
| 17:57 | cfleming | puredanger: Currently it will work in Clojure, because I'm using a horrible load-file hack to get the line numbering right |
| 17:57 | cfleming | puredanger: But not cljs |
| 17:57 | xemdetia | true, I will have to examine that. I just was not identifying me trying to start the nrepl server as a problem when I issued the build job. I am glad I asked |
| 17:58 | puredanger | cfleming: the key of course is that repls choose how they read so making the repl more capable enables this (and other things) |
| 17:58 | cfleming | puredanger: Right, but this needs to be on a form-by-form basis |
| 17:58 | justin_smith | kwladyka: my usual solution is to have a template file (data, from the frontend guy) and a ring request (more data, from the client), and then use a rendering library (I use antlers, selmer is also good, there are other good ones) to synthesize those two data sources (plus maybe some input from clojure.java.jdbc) to make a page |
| 17:59 | puredanger | cfleming: in terms of the allowed features or just allowing read conditionals at all? |
| 17:59 | justin_smith | kwladyka: that page is put into a hash map, and returned to ring |
| 17:59 | kwladyka | justin_smith https://github.com/flyingmachine/brave-clojure-web is it good example? Do you know better? |
| 18:00 | justin_smith | kwladyka: is that even a clojure project? |
| 18:00 | cfleming | puredanger: Just allowing conditionals at all - currently they're not supposed to be allowed in clj files. |
| 18:00 | kwladyka | oh true... its about clojure but not in clojure... |
| 18:00 | kwladyka | sorry! |
| 18:00 | justin_smith | kwladyka: like I tried to mention above, if you run "lein new compojure my-app-name" that will create a working webapp from a template |
| 18:00 | justin_smith | and then you can start from there |
| 18:01 | puredanger | cfleming: you could programmatically invoke the reader based on the file type, then take the result and send that to the repl :) |
| 18:02 | kwladyka | i know but real example will help me to understand the process of code evolving :) |
| 18:02 | cfleming | puredanger: It wouldn't be the worst thing I've had to do :-) |
| 18:02 | justin_smith | kwladyka: I'd have something to share but sadly my good examples were client work, not open source |
| 18:03 | kwladyka | i understand :) |
| 18:03 | cfleming | puredanger: Like I say, this isn't a problem (for Cursive at least) for Clojure, but it is for CLJS |
| 18:04 | cfleming | puredanger: CLJS can't use the load-file hack because load-file doesn't return the result of the last evaluation |
| 18:04 | kwladyka | the worst thing in my country (Poland) Clojure is not so popular and i can't find even in one of the biggest city Poznań Clojure programmers, we don't have any meeting groups or something like that. It is really hard to improve skills :) |
| 18:05 | cfleming | puredanger: Ah yes, I did see those mails but hadn't realised why he would want what he was asking for |
| 18:05 | justin_smith | kwladyka: euroclojure was in Krakow last year iirc |
| 18:05 | kwladyka | BTW: Are you close connected with Clojure? I see you are very active. |
| 18:05 | justin_smith | kwladyka: not to say that means anyone in Poland is using Clojure of course |
| 18:06 | justin_smith | kwladyka: I try to be pretty active, yeah, I am volunteering with clojurebridge next week to teach, and I'll be going to clojure/west in a couple weeks |
| 18:07 | kwladyka | thats good, i see Clojure community is very mature :) |
| 18:10 | cfleming | justin_smith: I'll be keen to hear about your clojurebridge experience, that's cool |
| 18:10 | cfleming | justin_smith: I volunteer at our local coderdojo, teaching kids to program - mostly with code.org and Scratch |
| 18:10 | justin_smith | cfleming: thanks, I'll be happy to share |
| 18:10 | justin_smith | cool |
| 18:10 | cfleming | justin_smith: I'm really curious how people with no experience find Clojure |
| 18:11 | kwladyka | cfleming if you are asking about people with no functional programming experience i can tell you :) |
| 18:12 | justin_smith | cfleming: yeah, I think some of the women coming to clojurebridge don't even have programming experience. And my suspicion is it will be easier for them (compared to people with just a little programming experience) |
| 18:13 | maxmartin | justin_smith: don't forget to link to the event :) http://www.eventbrite.com/e/clojurebridge-workshop-for-women-in-software-tickets-16223350478 |
| 18:13 | maxmartin | Looking forward to meeting you at the teacher training on Mondayh |
| 18:13 | amalloy | justin_smith: did you read the article about how learning haskell is not made easier by having no prior programming experience? |
| 18:13 | amalloy | written by a student of a former loud member of #clojure |
| 18:14 | justin_smith | amalloy: I can guess who you mean, and no, I have not seen that |
| 18:14 | justin_smith | maxmartin: cool, see you there |
| 18:14 | kwladyka | justin_smith to be honest i feel Clojure is great, because i have even a lot business managin experience. Mayby even more then programming. In most cases i really didn't happy to put business thinking into code, but... but Clojure looks diffrent. I can use there my business thinking, thats what i need. |
| 18:14 | justin_smith | kwladyka: because it is declarative? the immutability? |
| 18:15 | cfleming | amalloy: It's probably made easier by having a math background more than anything |
| 18:15 | amalloy | justin_smith: https://superginbaby.wordpress.com/2014/11/18/learning-haskell-as-a-nonprogrammer/ |
| 18:16 | cfleming | amalloy: She had an interesting post the other day about teaching her 10-year-old Haskell |
| 18:16 | justin_smith | amalloy: in all fairness, that reminds me of my experience trying to learn haskell too |
| 18:16 | amalloy | who is "she", cfleming? |
| 18:17 | kwladyka | justin_smith i am not sure why, but i think it is writing by functions not objects. And i don't have to care about data too much because it is immutability. I want focus on goal and have super redable code. But not readable like i can read for(...){..} and i understand operations. I want read code and uderstand as fast as possible business model and understand what is happening where. |
| 18:17 | cfleming | amalloy: The author of that blog post |
| 18:17 | cfleming | amalloy: https://superginbaby.wordpress.com/2015/04/08/teaching-haskell-to-a-10-year-old-day-1/ |
| 18:18 | kwladyka | justin_smith ofcoure it is also possible to write that readable in other langauges but other languages are not really matching with that, it like forcing them to do that. |
| 18:18 | kwladyka | but i am not a standard programmer, because i have really strong business skills and thinking in another way |
| 18:19 | justin_smith | amalloy: that was a really good and informative blog post, thanks |
| 18:19 | kwladyka | Clojure looks for me like something what i was looking for years :) |
| 18:20 | justin_smith | but I think it's less about haskell and more about the common sort of haskell intro that is out there - compare to eg. some of the excellent tabula-rasa intros to scheme |
| 18:20 | cfleming | justin_smith: I think the "what do I do with this?" is the biggest stumbling block for new programmers - starting by having something you want to achieve is vital. It's why games are such a great gateway drug for programmers. |
| 18:21 | justin_smith | cfleming: heh, yeah |
| 18:21 | cfleming | justin_smith: I think this particularly applies to Haskell since so little of the introductory stuff is aimed at actually making something useful. |
| 18:21 | justin_smith | cfleming: also, show a way things can go wrong without X before introducing X |
| 18:21 | justin_smith | before introducing the concept of a function, show how bad coding without functions is |
| 18:21 | justin_smith | etc. |
| 18:21 | cfleming | justin_smith: Yeah, no doubt - there's nothing like seeing the problem it solves to make you understand it and remember it. |
| 18:22 | justin_smith | but that would mean some stuff in haskell won't be teachable in your first few years :) |
| 18:22 | amalloy | justin_smith: i can't tell if you're saying that's a bad thing to do or a good thing |
| 18:22 | justin_smith | amalloy: which thing to do? |
| 18:22 | amalloy | "show a way things can go wrong without X before introducing X" |
| 18:22 | justin_smith | amalloy: oh, I think that's very important to do |
| 18:23 | kwladyka | from my point of view the most important thing is to show how easy you can write/read business model into code. This is the clue, beucase people writing code for business :) |
| 18:27 | ncthom91 | hi all! How would I cast this ScriptObjectMirror to a normal map in clojure? http://cr.openjdk.java.net/~sundar/jdk.nashorn.api/8u40/javadoc/jdk/nashorn/api/scripting/ScriptObjectMirror.html |
| 18:29 | amalloy | there's no such thing as casting in clojure. banish it from your mind, and then you'll have room to think about what you actually need to do |
| 18:29 | justin_smith | ncthom91: (into {} (.entrySet S)) I think? |
| 18:29 | amalloy | justin_smith: i mean the thing is already a map |
| 18:29 | amalloy | you can just call get on it |
| 18:29 | justin_smith | oh yeah, sure |
| 18:29 | dnolen | ncthom91: it implements Map, you don't need to convert it |
| 18:29 | amalloy | so it depends what ncthom91 actually want to do |
| 18:29 | justin_smith | good point |
| 18:29 | amalloy | dnolen: depends. ncthom91 might want to assoc into it, for example |
| 18:30 | dnolen | amalloy: right though if you're going to interact with ScriptObjectMirror probably not going to do that |
| 18:31 | ncthom91 | amalloy justin_smith dnolen i see, thanks |
| 18:43 | ncthom91 | another question :).. so I'm trying to instantiate a new Nashorn instance for each thread responsible for a given task. I'd like to test that my thread-local binding is working, so I wrote a test to evaluate a javascript expression in the nashorn engine in several threads: http://pastie.org/10083448 |
| 18:44 | ncthom91 | `lein test` exits before that println is ever hit... Is this a lazy evaluation issue? |
| 18:44 | amalloy | ~for |
| 18:44 | clojurebot | for is a beautiful person |
| 18:44 | ncthom91 | ergh... adding a `doall` seemed to make it work |
| 18:44 | amalloy | clojurebot pls |
| 18:44 | ncthom91 | guess it was |
| 18:45 | amalloy | tell me for is not a loop |
| 18:45 | justin_smith | ncthom91: use doseq |
| 18:45 | justin_smith | ncthom91: doseq is the same as for, syntax and execution wise, but without the laziness part |
| 18:45 | hiredman | ~for |
| 18:45 | clojurebot | for is not used often enough. |
| 18:45 | ncthom91 | justin_smith cool, thanks |
| 18:45 | justin_smith | (and also it accepts arbitrary numbers of body expressions, because it's not lazy) |
| 18:50 | ncthom91 | justin_smith so I took your tip and tweaked my test to actually test instead of just println: http://pastie.org/10083462 |
| 18:51 | ncthom91 | but `lein test` yields "Ran 0 tests containing 0 assertions." |
| 18:51 | ncthom91 | can you help me with what that's about? |
| 18:51 | justin_smith | ncthom91: deftest is needed |
| 18:51 | ncthom91 | omg >_< thanks, sorry for the dumb question |
| 18:51 | justin_smith | ncthom91: clojure.test doesn't know something is a test unless it has the :test metadata |
| 18:52 | justin_smith | ncthom91: also, line 8 could be (map deref futures) |
| 18:52 | justin_smith | oh wait, those aren't futures |
| 18:52 | justin_smith | they are just named "futures" |
| 18:52 | justin_smith | hehe |
| 18:53 | ncthom91 | i borrowed that example from a blog post :P |
| 18:53 | justin_smith | no biggie |
| 18:53 | justin_smith | deref would work if they were actual futures |
| 18:53 | amalloy | justin_smith: are you sure they're not? |
| 18:53 | amalloy | .invokeAll probably returns a List<Future> |
| 18:53 | justin_smith | amalloy: oh, good point |
| 18:54 | ncthom91 | `(map deref futures)` here seems to work |
| 18:55 | amalloy | truly clojure is magic |
| 18:55 | justin_smith | awesome - amalloy was right, I forgot that this lower level syntax would return the same type as clojure's "future" would |
| 18:55 | justin_smith | (inc amalloy) |
| 18:55 | lazybot | ⇒ 256 |
| 18:55 | amalloy | overflow! i should go reset my karma to 0 |
| 18:55 | justin_smith | -256 |
| 18:55 | kwladyka | what tools for clojure continous integration? jenkins or something else? |
| 18:56 | justin_smith | kwladyka: jenkins + lein works in my experience |
| 18:56 | kwladyka | thx |
| 18:56 | justin_smith | just make sure jenkins' lein setup is aproporiate, of course |
| 18:57 | kwladyka | ok its 1 a.m., its time to go sleep :) goodnight! |
| 18:58 | akkad | are there any emacs modes to highlight a dangling ]? |
| 18:59 | justin_smith | akkad: highlight-paren-mode should make it turn red when your cursor is on it |
| 18:59 | justin_smith | I think rainbow-parens should make it ugly permanently |
| 19:00 | akkad | thanks |
| 19:00 | akkad | first commit and poof, extra ] |
| 19:01 | justin_smith | akkad: also, "lein check" is good for finding goofs like that |
| 19:02 | justin_smith | and then "lein eastwood" for the stuff lein check doesn't find |
| 19:07 | ncthom91 | if I've defined a new FixedThreadPool from the Executors class at the top of my file, is it a bad idea for threads to recursively call (.invokeAll) on that pool? The reference to the pool would be shared across the threads, so calling (.invokeAll) from within a thread's task would fill the same work queue as calling (.invokeAll) from the main thread, right? |
| 19:16 | justin_smith | ncthom91: yes |
| 19:16 | ncthom91 | justin_smith yes it's a bad idea? |
| 19:17 | justin_smith | they are all using the same pool |
| 19:17 | justin_smith | are you wanting per-thread pools? |
| 19:18 | ncthom91 | justin_smith nope. I'm building a graph recursively where I want each node assembled in a thread |
| 19:18 | ncthom91 | so the recursive call is actually putting a task back in the thread pool |
| 19:18 | ncthom91 | hmm that might be trouble because then threads are waiting on threads... |
| 19:19 | ncthom91 | in a fixed thread pool |
| 19:19 | ncthom91 | it's like a sophistocated deadlock |
| 19:19 | ncthom91 | lol |
| 19:19 | justin_smith | ncthom91: a nice way to organize this is to have each thread reading tasks off a queue |
| 19:19 | justin_smith | and then putting tasks onto the queue (but not waiting on them) |
| 19:20 | justin_smith | core.async has nice abstractions for this stuff, but you can also use clojure.lang.PersistentQueue/EMPTY |
| 19:20 | justin_smith | or even a java.util.concurrent.BlockingQueue |
| 19:20 | justin_smith | I think that's the one |
| 19:21 | ncthom91 | i'll have to find a nice way to prevent threads waiting on each other |
| 19:22 | justin_smith | ncthom91: for nested dependencies between threads, look into core.async |
| 19:22 | justin_smith | do channel writes / reads |
| 19:22 | justin_smith | it simplifies this stuff a lot |
| 19:24 | ncthom91 | justin_smith any tips on mixing core.async and the Executors framework? I definitely want a fixed thread pool where threads stay alive |
| 19:24 | justin_smith | ncthom91: let core.async handle the threads |
| 19:25 | justin_smith | it uses a fixed pool, but you don't have to worry about the details in practice |
| 19:25 | justin_smith | it has a state machine where a given block might be dropped from one thread, and picked up by another later, but all the threads are utilized efficiently |
| 19:26 | ncthom91 | justin_smith oh... it does use a fixed pool? Each of my threads needs its own Nashorn scriptengine instance to execute some javascript, and instantiating a new Nashorn engine takes like 500ms, so if threads are constantly spinning up and down i'll incur a lot of overhead |
| 19:26 | ncthom91 | that's why I was intrigued by Executors' newFixedThreadPool |
| 19:27 | justin_smith | ncthom91: instead of giving a script engine to a thread, give it to a block of code that loops and executes things as needed |
| 19:27 | justin_smith | let core.async decide which actual thread is running your code |
| 19:28 | justin_smith | the result is that none of the engines are sharable between threads (each belongs to a single localized block of code), but threads can do other work while a given block is parked on eg. IO |
| 19:28 | ncthom91 | justin_smith well the trouble is that Nashorn isn't thread safe yet, so I need to guarantee that each thread gets its own instance |
| 19:28 | ncthom91 | oh.. hmm |
| 19:28 | justin_smith | no, you don't |
| 19:28 | justin_smith | the instances would only be accessible to one thread at a time |
| 19:28 | ncthom91 | could you show me a quick example of how to do that? |
| 19:29 | justin_smith | (go-loop (let [task (<! task-chan)] (do-something task engine)) |
| 19:29 | justin_smith | assuming engine was locally bound (likely in a surroundign let block) |
| 19:30 | justin_smith | the only code using the engine is that go-loop |
| 19:30 | justin_smith | I think that code has a few issues, but at least the basic idea is there I hope |
| 19:30 | ncthom91 | and `go-loop` puts this off in a thread? |
| 19:30 | justin_smith | no |
| 19:30 | justin_smith | it creates a go block that loops |
| 19:31 | justin_smith | the go loop is run (when it is ready to be run (not parked on a channel or whatever)) |
| 19:31 | justin_smith | it's picked up by whichever thread core.async decides to put it on |
| 19:31 | justin_smith | but that's implementation, in practice that part you don't really need to think about |
| 19:32 | justin_smith | you know that engine won't be used in other threads, because it is a local bindign that you don't share with other code |
| 19:32 | justin_smith | so at any time at most one thread can use it |
| 19:33 | ncthom91 | interesting... how does core.async fan out the work then? Suppose that task queue that you <! from has like 10 tasks queued up |
| 19:33 | ncthom91 | will core.async magically fan it out onto N threads? |
| 19:33 | justin_smith | ncthom91: first to read from the queue is first to get the task |
| 19:33 | justin_smith | ncthom91: no, if you want N engines working, start N go loops |
| 19:34 | justin_smith | all reading on the same channel |
| 19:34 | justin_smith | like delivery drivers waiting for the next order that's ready to go |
| 19:34 | justin_smith | each task is guaranteed to be taken by exactly one consumer |
| 19:34 | ncthom91 | I see. So rather than bounding the thread pool I'm kind of bounding the "engine pool" |
| 19:34 | justin_smith | right |
| 19:35 | ncthom91 | and letting core.async associate whatever threads it wants to the work |
| 19:35 | justin_smith | that is kind of inside out, huh :) |
| 19:35 | justin_smith | right |
| 19:35 | justin_smith | that's the model |
| 19:35 | justin_smith | it's a formal execution model called CSP |
| 19:35 | justin_smith | very well studied and well documented |
| 19:35 | justin_smith | concurrent sequential processes iirc |
| 19:35 | justin_smith | communicating sequential processes |
| 19:35 | justin_smith | sorry |
| 19:36 | ncthom91 | So I could do something like (doseq [engine engines] (go-loop (let [task (<! queue)] (do-something task engine))) |
| 19:36 | justin_smith | exactly |
| 19:36 | ncthom91 | which would associate a go-loop with each engine |
| 19:36 | ncthom91 | interestingggg |
| 19:36 | justin_smith | I think you actually need a (recur) and a binding block in go-loop |
| 19:37 | justin_smith | but that's the idea, yeah |
| 19:37 | ncthom91 | sure |
| 19:37 | justin_smith | it works out very nicely in practice |
| 19:37 | justin_smith | clean, simple |
| 19:37 | ncthom91 | i believe it. It's totally not how I was thinking about this problem :) |
| 19:37 | justin_smith | the engines can each generate more tasks |
| 19:37 | justin_smith | without clogging the whole thing up |
| 19:38 | justin_smith | (unless they produce tasks faster than they consume them of course, nothing is going to help you with that :)) |
| 19:38 | ncthom91 | well the (do-something) function will be the one making more tasks, probably not the js engine, but I assume it's the same thing |
| 19:38 | justin_smith | right, sorry |
| 19:38 | justin_smith | sure |
| 19:38 | ncthom91 | heh, it's a finite recursive problem, so it'll end eventually |
| 19:38 | justin_smith | cool |
| 19:38 | ncthom91 | justin_smith are channels essentially queues in this model? |
| 19:38 | justin_smith | exactly |
| 19:39 | justin_smith | queues with special constraints |
| 19:39 | justin_smith | no peeking for example |
| 19:39 | ncthom91 | so I can just create new tasks with (>! queue new-task) |
| 19:39 | justin_smith | exactly |
| 19:39 | justin_smith | the only way to check if a queue has data for you is to consume it (and remove it from the queue) |
| 19:39 | justin_smith | but the extra rules actually are needed for the overall provable correctness of the setup |
| 19:41 | ncthom91 | how would just close one of those go-loops? |
| 19:41 | ncthom91 | how would you* |
| 19:41 | justin_smith | ncthom91: if you close the input queue, it will return nil when they read |
| 19:41 | justin_smith | they can check for nil and exit |
| 19:42 | ncthom91 | hm ok |
| 19:42 | justin_smith | and in fact they should :) |
| 19:42 | justin_smith | if you really needed fine grained control, you could give them individual channels, but that seems an odd choice |
| 19:42 | justin_smith | if you have to shut down one, I think it would make sense to shut them all down |
| 19:42 | ncthom91 | no, I'm thinking this should work |
| 19:42 | ncthom91 | yea |
| 19:43 | ncthom91 | the only piece I have left to solve, conceptually, is that right now each node in my graph contains a pointer to its children nodes |
| 19:43 | ncthom91 | so in constructing the graph, I need each child node before I can finish building the parent |
| 19:43 | justin_smith | ahh |
| 19:43 | ncthom91 | that's how I ended up with threads relying on threads |
| 19:43 | justin_smith | ncthom91: adjacency list! |
| 19:43 | ncthom91 | hahaha |
| 19:43 | ncthom91 | exactly my thinking |
| 19:44 | ncthom91 | it makes the traversal less fun to write, but I think that solves this problem |
| 19:44 | justin_smith | in all seriousness, when you have immutable data structures, adjacency lists are really the only sane way to do fully general graphs |
| 19:44 | justin_smith | the traversal only needs some minor adaptor code |
| 19:44 | ncthom91 | right.. i was thinking references to atoms actually |
| 19:44 | ncthom91 | but that seems unnecessarily messy |
| 19:45 | justin_smith | I'd say one atom, holding an adjacency list expressed as a hash-map |
| 19:45 | ncthom91 | and the atom part there guarantees the thread safety? |
| 19:45 | justin_smith | right |
| 19:45 | justin_smith | using swap! for all modifications |
| 19:45 | justin_smith | it will retry if there are concurrent modifications |
| 19:45 | ncthom91 | ok. This makes a lot of sense... probably a far easier approach than what I had in my head lol |
| 19:46 | justin_smith | you just need to watch out for side effects in the update function (big nono) and if you are hitting too many retries caused by concurrent updates, consider splitting it into sibling refs |
| 19:46 | ncthom91 | by update function you mean teh function I pass to swap! ? |
| 19:46 | justin_smith | ncthom91: after doing a bunch of other ways of organizing recursive tasks on fully general (potentially cyclic) graphs, this is the sane way |
| 19:47 | justin_smith | yeah |
| 19:47 | ncthom91 | what do you mean split into sibling refs? |
| 19:47 | ncthom91 | split the map into pieces contained ins eparate atoms? |
| 19:47 | justin_smith | well, refs, not atoms |
| 19:47 | justin_smith | because refs are what you want for coordinated update |
| 19:48 | justin_smith | that relies on the state of multiple objects that are updated together |
| 19:48 | justin_smith | if you can do a hash map in an atom, that's simpler, but refs are simpler than multiple atoms |
| 19:48 | ncthom91 | i see, ok |
| 19:49 | justin_smith | ncthom91: the docs on clojure.core are really good for describing the various concurrency primitives in clojure |
| 19:50 | ncthom91 | i'm going to tackle it with a single hashmap in an atom at first |
| 19:50 | justin_smith | ncthom91: the chapters here on refs, agents, and atoms http://clojure.org/documentation |
| 19:50 | justin_smith | ncthom91: yeah, that makes sense |
| 19:50 | ncthom91 | Realistically I won't hit a lot of concurrent updates unless I use a bunch of different js engines |
| 19:51 | ncthom91 | but I won't know how many engines to use until I can measure the speed increase as I tweak that number |
| 19:51 | justin_smith | cool |
| 19:51 | ncthom91 | justin_smith thanks so much. This is been immensely helpful |
| 19:51 | ncthom91 | this has* been |
| 19:52 | justin_smith | if you want to dynamically tweak the count without restarting the system, you could assign each an ordinal integer, and send a message saying "everyone with a number higher than N, shut off" |
| 19:52 | justin_smith | ncthom91: your welcome, I think this stuff is really cool |
| 19:53 | ncthom91 | justin_smith great! Cause I'm sure I'll be back with more questions soon enough hahaha |
| 19:53 | justin_smith | ncthom91: another possibility for the "sending a number" idea would be also to turn them on if the number is higher than their N |
| 20:14 | nicferrier | macros. can I read the current namespace for using inside a macro? |
| 20:14 | justin_smith | nicferrier: the ns invoking the macro is *ns* |
| 20:15 | nicferrier | so if I use *ns* I should be ok. I was using that outside macros and it was just "user" |
| 20:15 | nicferrier | of course, if I deliberately changed the namespace (like in a repl) it was correct |
| 20:15 | justin_smith | right, that's the namespace from which everything else is called |
| 20:15 | nicferrier | but then running outside the repl it was just user all the time. |
| 20:15 | justin_smith | but at expansion time, *ns* will be the ns in which the macro is expande |
| 20:16 | justin_smith | d |
| 20:16 | nicferrier | got it |
| 20:16 | nicferrier | thanks] |
| 20:17 | ncthom91 | hey justin_smith one more question :). If I throw these tasks into the queue, and the go-loops spin and pick them up and update the adjacency list... how can I know get some notification of being "done" |
| 20:17 | ncthom91 | where "done" is a state such that the queue is empty because the engines have finished all of the recursive updates to teh graph |
| 20:18 | justin_smith | oh, that's an interesting one |
| 20:18 | ncthom91 | :) |
| 20:19 | ncthom91 | hmm i suppose I could solve this problem differently |
| 20:20 | justin_smith | ncthom91: one possibility is an agent, that gets incremented for each task (including your initial tasks) and decremented when each one is fully processed (including queueing any follow up tasks), and use add-watch to do a special thing when the agent hits 0 |
| 20:21 | justin_smith | because it can't hit 0 until there is truly no work remaining |
| 20:21 | justin_smith | since the number can't go up again if no task is still in progress |
| 20:21 | ncthom91 | that's a cool idea |
| 20:21 | justin_smith | and it can't hit zero unless none are in progress |
| 20:22 | ncthom91 | so my go-loop body could just `send` an `inc` call at the beginning and a `dec` call at the end yea? I'm going to read up on add-watch |
| 20:22 | justin_smith | ncthom91: I use a similar concept for testing task-pool abstractions, where I track the max value it hits, and also ensure that it gets back to 0 |
| 20:22 | justin_smith | that showing the total max concurrency |
| 20:23 | justin_smith | ncthom91: yeah, that sounds right |
| 20:23 | justin_smith | I suggested an agent specifically because that won't retry (with retries it could hit weird states, better to not have to think about it) |
| 20:24 | ncthom91 | justin_smith yea this sounds good, I like the approach |
| 20:26 | ncthom91 | thanks! |
| 20:29 | darthdeus | if I have a map of vectors/sets, is there a simple way to add/remove items from a vector/set at a given key? |
| 20:30 | justin_smith | darthdeus: dissoc and assoc, but these don't replace your collection, they make a new one |
| 20:30 | darthdeus | justin_smith: yeah, but those work on the map |
| 20:30 | justin_smith | darthdeus: ahh, I mean update-in |
| 20:30 | darthdeus | oh cool, thanks :) |
| 20:31 | justin_smith | ,(update-in {:a [1 2 3]} [:a] pop) |
| 20:31 | clojurebot | {:a [1 2]} |
| 20:31 | justin_smith | ,(update-in {:a [1 2 3]} [:a] conj 42) |
| 20:31 | clojurebot | {:a [1 2 3 42]} |
| 20:31 | darthdeus | ,(update-in {} [:a] conj 42) |
| 20:31 | clojurebot | {:a (42)} |
| 20:31 | darthdeus | hmm |
| 20:32 | justin_smith | ,(update-in {} [:a] (fnil conj []) 42) |
| 20:32 | clojurebot | {:a [42]} |
| 20:32 | justin_smith | fnil there will act like conj if it exists, create a vector and then conj if it doesn't |
| 20:32 | darthdeus | interesting |
| 20:33 | darthdeus | still not sure if I like this about clojure, that modifying collections is so easy |
| 20:33 | justin_smith | darthdeus: nothing got modified |
| 20:34 | justin_smith | ,(let [a {:a 0}] (assoc a :b 1) a) |
| 20:34 | clojurebot | {:a 0} |
| 20:34 | justin_smith | you have to use the return value |
| 20:34 | darthdeus | yeah I know about persistent data structures |
| 20:34 | darthdeus | what I meant is that the APIs kinda make me want to use raw data strucutres |
| 20:34 | justin_smith | that's a good thing |
| 20:34 | justin_smith | that's the right way to do it in clojure |
| 20:34 | darthdeus | that depends ... coming from haskell it's very unnatural |
| 20:34 | justin_smith | darthdeus: clojure isn't haskell |
| 20:35 | darthdeus | I know, that's why I'm trying to do it this way and not the haskell way :) |
| 20:35 | justin_smith | also, you can use defrecord - it supports all hash-map ops, but is also a custom type |
| 20:35 | darthdeus | but it twists my brain a bit |
| 20:35 | justin_smith | right |
| 20:35 | justin_smith | defrecord is a great in between, where you get all the standard utility functions and power, but also get to paramaterize on type |
| 20:35 | justin_smith | for eg. protocols |
| 20:36 | darthdeus | hmm |
| 20:37 | darthdeus | I feel like I can hack together a lot of things fast ... which seems good ... though not really sure how this will work out long term |
| 20:37 | darthdeus | but hey, at least I'm getting work done :D |
| 20:37 | justin_smith | darthdeus: that is the clojure / haskell trade off in my experience |
| 20:38 | justin_smith | in clojure you get things done fast - but then might discover that you backed yourself into a corner by building so fast |
| 20:38 | justin_smith | with haskell, you don't know if you are making progress at all until ... BOOM it's done |
| 20:38 | justin_smith | as a vast overgeneralization of both languages, of course :) |
| 20:38 | darthdeus | indeed ... though true |
| 20:39 | darthdeus | at least from my very minor clojure experience |
| 20:39 | darthdeus | it feels that I almost don't have to know anything and it kinda works |
| 20:39 | darthdeus | like javascript, except a little better |
| 20:39 | justin_smith | only a little? :P |
| 20:39 | amalloy | clojurebot: clojure is like javascript, except a little better |
| 20:39 | clojurebot | Ack. Ack. |
| 20:39 | justin_smith | haha |
| 20:39 | darthdeus | well, maybe a lot better :D but still feels a lot like javascript at times |
| 20:40 | justin_smith | darthdeus: I think this heralds back partially to the javascript / scheme connection |
| 20:42 | darthdeus | might be |
| 20:43 | justin_smith | brendan eich: I was recruited to Netscape with the promise of “doing Scheme” in the browser... I’m happy that I chose Scheme-ish first-class functions and Self-ish (albeit singular) prototypes as the main ingredients. |
| 20:44 | justin_smith | "Whether that language should be Scheme was an open question, but Scheme was the bait I went for in joining Netscape." |
| 20:46 | justin_smith | interesting - if it weren't for the "looks like java" requirement, perl, python, tcl, and scheme would have been in the running |
| 20:46 | justin_smith | https://brendaneich.com/2008/04/popularity/ |
| 20:48 | darthdeus | hehe |
| 20:48 | darthdeus | btw am I blind or are there no API docs for http-kit? http://www.http-kit.org/ I just can't find them anywhere in the repo or on the site |
| 20:50 | arrubin | darthdeus: Did you click Server or Client? Or did you want something more? |
| 20:50 | darthdeus | arrubin: well those only have examples, not exactly a description of all the functions and params etc |
| 20:52 | arrubin | I do not see anything else, so you might not be blind. |
| 20:52 | arrubin | Or we might both be. |
| 20:59 | justin_smith | darthdeus: it's actually not a huge lib, the most concise docomentation is probably the code and doc strings in the github repo |
| 21:00 | justin_smith | darthdeus: I think these three files have all the info you might want https://github.com/http-kit/http-kit/tree/master/src/org/httpkit |
| 21:00 | justin_smith | and the impl details are hidden in the java source |
| 21:01 | justin_smith | https://github.com/http-kit/http-kit/tree/master/src/java/org/httpkit |
| 21:02 | darthdeus | cool, thanks |
| 21:14 | nuwanda_ | ok, I think I'm going a little crazy. Is there a reason a repl would be able to load a ns with (require 'ns-name) but apparently fail to do (in-ns 'ns-name)? |
| 21:15 | justin_smith | nuwanda_: no, it's the opposite |
| 21:15 | justin_smith | require can fail if your ns has errors |
| 21:15 | justin_smith | in-ns doesn't really have a failure case |
| 21:15 | justin_smith | in-ns won't load your code though |
| 21:16 | nuwanda_ | well, it doesn't actually fail, it just behaves as if the ns wasn't found |
| 21:16 | nuwanda_ | yeah, exactly, it doesn't load my code, while require seems to have no problem with it |
| 21:16 | justin_smith | nuwanda_: all in-ns is change the active ns, and optionally create a totally empty ns if it didn't exist |
| 21:16 | justin_smith | in-ns is not intended to load code |
| 21:16 | justin_smith | all it does is change which ns is active |
| 21:16 | justin_smith | it doesn't look for files or anything |
| 21:17 | justin_smith | even if you have a file implementing ns-name, it just creates an empty ns, ignoring that file |
| 21:21 | darthdeus | btw probably a dumb question, but can I expect things like sockets to behave properly if I put them in a Set? |
| 21:22 | justin_smith | darthdeus: if I understand you correctly, that would be yes, since they use object identity for equality |
| 21:42 | nuwanda_ | (inc justin_smith) |
| 21:42 | lazybot | ⇒ 236 |
| 21:42 | Shayanjm | So I've got something I need to run via a remote repl on a powerful server. It's going to take a long time, and obviously I don't want to lose the results in case something happens to the session |
| 21:43 | Shayanjm | are there any 'clojure best practices' for dealing with this? |
| 21:43 | Shayanjm | Or is it more or less the same sort of trouble shooting i.e: capture everything into a file? |
| 21:49 | sattvik | Shayanjm: It depends on what you need. You could perform the work in a future and stuff the result into a var somewhere (as an atom or a ref). If it needs to persist across JVM restarts, then, yes, you should store that somewhere designed for persistent storage. |
| 21:50 | Shayanjm | sattvik: if I run something in a remote repl and my ssh session dies (connection or something) in the middle |
| 21:50 | Shayanjm | does the repl session persist? |
| 21:50 | Shayanjm | No, right? |
| 21:53 | sattvik | No, it doesn't. |
| 21:53 | Shayanjm | Yeah so that's really my problem |
| 21:53 | Shayanjm | Can't reasonably expect my session to stay live that long |
| 21:55 | sattvik | However, if you do something in a future, it will happen in a thread that's independent from the REPL. As such, you could save the future in a namespace somewhere so that you can later reconnect to your server and look it up. |
| 21:55 | Shayanjm | hmm interesting |
| 22:04 | Shayanjm | sattvik: doesn't a future only exist for as long as a REPL session is active? |
| 22:05 | Shayanjm | i.e: If I ssh into remote server, lein repl -> Run some stuff (in a future) that processes a ton of data and writes to a file |
| 22:05 | xphillyx | Hey all. Is there a way to memoize on a 2 argument function but say to only "key" on one of the arguments? |
| 22:06 | Shayanjm | and after I run that stuff the session dies. Wouldn't the REPL session die as well - meaning the future is no longer active & therefore stops running? |
| 22:07 | Shayanjm | sattvik: or even more simply taking u |
| 22:07 | sattvik | No, the future runs a seperate thread. You do have to save it somewhere where you can look it up later, otherwise it will get garbage collected. |
| 22:07 | Shayanjm | sattvik: or even more simply taking out the write-to-file capability* |
| 22:07 | Shayanjm | sattvik: Okay, so what if the future just returns a value. If I ssh back into the server & lein repl again, would the future still be referencable? |
| 22:08 | Shayanjm | Despite the session ending before the future could return? |
| 22:08 | sattvik | So you can (def my-long-tasks (atom {})). In your REPL, you can (swap! my-long-tasks assoc :my-key (future (long-running-fn))) |
| 22:08 | sattvik | Later, you can (:my-key @my-long-tasks). |
| 22:09 | Shayanjm | sattvik: but that would only work for as long as the REPL is active |
| 22:09 | Shayanjm | the moment the ssh session dies, the repl would also die -- meaning my-long-tasks would start with a fresh empty value after lein repl is run again |
| 22:10 | sattvik | Nope. It's completely independent. |
| 22:10 | Shayanjm | Seriously? That doesn't seem right |
| 22:10 | sattvik | Well, if you do it in the user namespace, yes that may be the case. |
| 22:10 | sattvik | Well, even then, the user namespace persists. |
| 22:10 | Shayanjm | sattvik: my set up is: I have core.clj running some long running processes inside of some clj project |
| 22:11 | Shayanjm | but the namespace only persists for as long as the repl is active - and I thought it dies the moment the ssh session dies? |
| 22:11 | Shayanjm | Hang on, there's an easy way to test this I think |
| 22:11 | justin_smith | Shayanjm: if you restart the vm, yes, all things you do in the repl are lost |
| 22:12 | Shayanjm | justin_smith: Not restarting the vm. If the ssh session dies (due to connectivity drop or hibernation or something) |
| 22:12 | Shayanjm | would the remote repl session still persist? |
| 22:13 | Shayanjm | or would it die with the ssh session? The machine is still live/running, the only thing that happened was that my laptop dc'd from the server |
| 22:13 | justin_smith | Shayanjm: it depends on what the OS decided to do. If you used nohup for example, it would not exit. Otherwise it gets an EOF, and a signal, and if you don't handle that signal, it will be shut down. |
| 22:13 | Shayanjm | Ah, so this is more an OS thing than anything else |
| 22:13 | Shayanjm | any suggestions for how best to handle this on a remote Ubuntu machine? |
| 22:13 | justin_smith | yeah, the OS decides what happens when a remote user disconnects without shutting a program down |
| 22:13 | sattvik | The REPL session doesn't persist as such, but the namespaces don't just unload themselves. (Although the proposed new socket REPL works a bit differently) |
| 22:14 | justin_smith | Shayanjm: if you want the repl to stay running, use nohup |
| 22:14 | justin_smith | this is handy because it also make a log file |
| 22:18 | Shayanjm | hmm interesting |
| 22:20 | Shayanjm | justin_smith: If I use nohup, run the process, and want to check on the value after x hours |
| 22:20 | Shayanjm | how would I reconnect to that repl instance? |
| 22:21 | justin_smith | Shayanjm: lein repl :connect port |
| 22:22 | justin_smith | or any other repl client you like |
| 22:22 | justin_smith | in fact you can use the -L arg to create an ssh tunnel, and use your editor or ide repl client |
| 22:22 | Shayanjm | justin_smith: Oh so just standard lein repl :connect port? |
| 22:23 | justin_smith | yeah, or if you have a tunnel, you can even run the repl on your local box |
| 22:23 | justin_smith | with your preferred tools |
| 22:23 | justin_smith | and the jvm and actual repl instance are on the other host accepting connections |
| 22:23 | Shayanjm | ooh |
| 22:23 | Shayanjm | and I can disconnect/reconnect at any time? |
| 22:23 | justin_smith | right, nrepl is nice like that |
| 22:24 | ncthom91 | hey justin_smith if you're around, quick question: http://pastie.org/10083752 |
| 22:24 | Shayanjm | game changer. How would I set this up on emacs cider? |
| 22:24 | ncthom91 | this is a test for verifying the graph that we were talking about earlier gets updated properly |
| 22:24 | justin_smith | Shayanjm: instead of cider-jack-in just use cider |
| 22:24 | justin_smith | it will ask for a port |
| 22:24 | Shayanjm | oic |
| 22:24 | Shayanjm | and point it to the remote IP + port? |
| 22:24 | ncthom91 | but the tests inside the add-watch callback don't get run, it looks like |
| 22:24 | ncthom91 | or at least they don't contribute to the test reporting |
| 22:24 | justin_smith | Shayanjm: no, since it's a tunnel, just the port suffices |
| 22:25 | Shayanjm | oh right because -L |
| 22:26 | justin_smith | Shayanjm: I think at this point even cider has options for making the remote connection, but I think it makes more sense to create the tunnel myself with ssh |
| 22:26 | justin_smith | maybe because I am old fashioned |
| 22:26 | Shayanjm | justin_smith: so workflow here would be: ssh with -L, run nohup lein repl, connect via cider, run stuff, disconnect (also disconnect tunnel?) -- reconnect at some later point via ssh tunnel & cider and check values? |
| 22:26 | justin_smith | yup |
| 22:27 | Shayanjm | That sounds fantastic |
| 22:27 | justin_smith | you can disconnect the tunnel if you like if you are not using it |
| 22:27 | Shayanjm | and I'm assuming I can just kill the repl with a standard (exit) despite nohup, yeah? |
| 22:27 | justin_smith | Shayanjm: it makes debugging prod so much easier |
| 22:27 | justin_smith | Shayanjm: from within the repl you can use (System/exit 0) |
| 22:27 | Shayanjm | is (exit) the same thing? |
| 22:27 | justin_smith | or any handy cider tool that does that for you, I guess |
| 22:27 | justin_smith | I have no idea what (exit) is |
| 22:27 | Shayanjm | Weird, my repl always starts and prompts me to use (exit) to exit lol |
| 22:28 | Shayanjm | might've been some config magic when I first set up lein |
| 22:28 | justin_smith | Shayanjm: it's probably some nice feature I just never use |
| 22:28 | justin_smith | I just tried typing in exit (no parens) in my repl and it disconnected me |
| 22:28 | justin_smith | probably nrepl magic |
| 22:28 | justin_smith | haha |
| 22:29 | Shayanjm | hahaha that sounds about right |
| 22:29 | Shayanjm | cool thanks a lot justin_smith, gonna try this |
| 22:30 | justin_smith | ncthom91: well, the test/is calls are not tests |
| 22:30 | justin_smith | they are assertions within a test |
| 22:31 | justin_smith | I don't think they do the right thing if they execute in another thread |
| 22:31 | justin_smith | usually what I do is create a "logging atom" and use swap! to poke that atom inside the async code |
| 22:31 | justin_smith | then I make assertions about the data in that atom |
| 22:32 | kevinwebster | Im trying to find out why Clojure has yet to support regex named capture groups. I dont see any discussion in JIRA or google groups about it. Anyone know why that is? |
| 22:32 | justin_smith | eg. have a cycle count, or a concurrency count that tracks its max value so far, etc. |
| 22:32 | justin_smith | kevinwebster: if java supports them, clojure does |
| 22:32 | ncthom91 | justin_smith but how do you know when to make the assertions? |
| 22:33 | aperiodic | in om, when I have multiple om/build calls in the body of my om/IRender render implementation, it seems like only the last one is actually called |
| 22:33 | justin_smith | ncthom91: when the processes are done, at the end of that test |
| 22:33 | aperiodic | does anyone know why that happens? |
| 22:35 | justin_smith | kevinwebster: clojure directly uses java regexes, including the extended syntax http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html |
| 22:35 | justin_smith | kevinwebster: the docs there explicitly mention named capture groups |
| 22:36 | justin_smith | #"foo" is equivalent to Pattern.compile("foo") |
| 22:39 | ncthom91 | justin_smith not sure what you mean. By the time i've hit the end of my test, the async code hasn't necessarily finished |
| 22:40 | justin_smith | ncthom91: then make sure you wait for it |
| 22:40 | justin_smith | ncthom91: each go loop returns a channel when constructed, when that channel returns a value on read, that means the loop has exited |
| 22:40 | justin_smith | yes, testing async things is weird |
| 22:42 | Shayanjm | justin_smith: nohup doesn't seem to be working, or I'm ignorant of how to even use it |
| 22:43 | Shayanjm | on remote machine: nohup lein repl |
| 22:43 | justin_smith | yes |
| 22:43 | Shayanjm | No output, looks like it runs without failing |
| 22:43 | Shayanjm | so A) I don't know the nrepl port |
| 22:43 | Shayanjm | and B) If I try looking for a java process I don't see one |
| 22:43 | Shayanjm | ps aux | grep java |
| 22:43 | justin_smith | Shayanjm: it creates a log file |
| 22:43 | justin_smith | nohup.out |
| 22:43 | justin_smith | if it is exiting, that's likely an issue |
| 22:44 | justin_smith | it should just sit there, not printing but also not ending |
| 22:44 | justin_smith | you can bg it safely |
| 22:44 | Shayanjm | oh gotcha |
| 22:44 | justin_smith | (Control-Z, bg, in most shells) |
| 22:44 | Shayanjm | does nohup.out get updated live? |
| 22:44 | Shayanjm | or only on exit? |
| 22:44 | justin_smith | live |
| 22:44 | justin_smith | you can tail it |
| 22:44 | justin_smith | or whatever |
| 22:44 | Shayanjm | Okay, yeah there was an error running with nohup |
| 22:44 | Shayanjm | but not regular lein repl |
| 22:45 | justin_smith | what was the error? |
| 22:45 | justin_smith | I usually am using lein run, and then starting a repl server from my -main |
| 22:45 | justin_smith | so maybe lein is being dumb about the tty here |
| 22:45 | Shayanjm | https://gist.github.com/shayanjm/15fad6a7c27c9127c461 |
| 22:46 | justin_smith | yeah, lein is trying to do stuff with stdio that doesn't work in nohup |
| 22:46 | justin_smith | you're better off making an uberjar and using lein run anyway |
| 22:46 | justin_smith | err, not lein run |
| 22:46 | justin_smith | I mean java -jar, or you can use lein run instead of lein repl |
| 22:46 | justin_smith | and manually connect |
| 22:47 | justin_smith | Shayanjm: starting an nrepl server is a oneliner, example is in the readme https://github.com/clojure/tools.nrepl#embedding-nrepl-starting-a-server |
| 22:47 | Shayanjm | sweet, looking |
| 22:49 | Shayanjm | justin_smith: what if instead of the repl, I just make -main execute everything that needs to be executed and prints to stdout? |
| 22:49 | Shayanjm | uberjar that, nohup java -jar |
| 22:49 | justin_smith | Shayanjm: if that's all you need, sure, then you can just open up nohup.out |
| 22:50 | Shayanjm | yeah |
| 22:50 | justin_smith | or make a proper log file |
| 22:50 | justin_smith | if that's all you need, even better :) |
| 22:50 | Shayanjm | Yeah now that I think about it I don't really need to live-debug |
| 22:50 | Shayanjm | because these are long running processes, they don't fail fast. |
| 22:50 | justin_smith | though sometimes being able to get into prod can be a lifesaver |
| 22:50 | Shayanjm | Yeah definitely |
| 22:50 | justin_smith | for figuring out a weird state interactively |
| 22:50 | Shayanjm | if I see that that's a benefit I'll definitely spin up a repl instance inside main |
| 22:51 | Shayanjm | but this is mostly a data project |
| 22:51 | justin_smith | fair enough |
| 22:51 | Shayanjm | so there isn't a whole lot of state that needs to be managed |
| 22:51 | justin_smith | nice, sounds like you found the simple solution then |
| 22:51 | Shayanjm | this has been very enlightening though, I didn't know you could embed repl instances inside your applications |
| 22:51 | Shayanjm | I could see that definitely coming in handy |
| 22:52 | justin_smith | yeah - definitely be careful though, an nrepl connection means full access to your program (and your program's user on that host) |
| 22:52 | Shayanjm | ah right |
| 22:52 | justin_smith | which is why it only accepts connections on localhost by default |
| 22:52 | justin_smith | which is mostly safe enough, since nobody uses multi user machines any more |
| 22:53 | Shayanjm | Right, so the 'actual' workflow for that would be to ssh in to the remote machine ahead of time |
| 22:53 | Shayanjm | and run the repl with nohup |
| 22:53 | justin_smith | Shayanjm: right, like I was mentioning the ssh tunnel |
| 22:53 | Shayanjm | Yeah, and then ssh tunnel afterwards |
| 22:53 | Shayanjm | with -L you can't run anything on the machine during that session, right? |
| 22:53 | justin_smith | no, it's a normal shell |
| 22:54 | Shayanjm | seriously? |
| 22:54 | Shayanjm | gonna try 1 min |
| 22:54 | justin_smith | which is why I just make creating the tunnel part of the command when I ssh in |
| 22:54 | Shayanjm | so what's the syntax? somelocalport:remotehost:22? or localport:remotehost:remotereplport? |
| 22:55 | justin_smith | ssh -L localport:127.0.0.1:remoteport |
| 22:55 | justin_smith | since it's a thing that only listens on 127.0.0.1 |
| 22:55 | justin_smith | or localhost whatever |
| 22:55 | justin_smith | my habit is using that "magic" ip |
| 22:56 | justin_smith | so you could optionally make a "hop" by connecting to yet another host (proxy tunnel) - ssh is very flexible |
| 23:07 | Shayanjm | justin_smith: I guess my confusion is: the remote port, should that be some random port or the nrepl port? |
| 23:07 | Shayanjm | if it's the nrepl port, I would have to specify the port in the code -- I wouldn't be able to let lein generate that for me randomly |
| 23:08 | justin_smith | Shayanjm: the nrepl port. You can specify a specific port to nrepl |
| 23:08 | Shayanjm | you can? |
| 23:08 | justin_smith | right |
| 23:08 | Shayanjm | TIL |
| 23:08 | Shayanjm | Oh |
| 23:08 | Shayanjm | you mean when you spin it up inside main |
| 23:08 | justin_smith | there's a project.clj option |
| 23:08 | Shayanjm | ooh |
| 23:08 | justin_smith | :repl-options https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L354 |
| 23:09 | Shayanjm | awesome -- thanks for letting me pick your brain justin_smith |
| 23:09 | justin_smith | but yes, it's also easy in your own code, since it's a one liner |
| 23:09 | justin_smith | np |
| 23:09 | justin_smith | I know how many days one can waste on this stuff the first time |
| 23:09 | justin_smith | not because of not being capable, just not having a decent lead on what works |