2016-05-01
| 12:20 | jonathanj | hmm, what the heck does this mean in the grand scheme of things: java.lang.ClassNotFoundException: clojure.java.shell, compiling:(documint/pdf.clj:53:10) |
| 12:21 | jonathanj | this only seems to happen when trying to build the uberjar |
| 12:22 | jonathanj | i'm calling (clojure.java.shell/sh ,,,) |
| 12:22 | jonathanj | do i need to (require) it first or something weird? |
| 12:23 | justin_smith | jonathanj: there's nothing weird here - no namespace is available that somebody hasn't required |
| 12:23 | justin_smith | jonathanj: and best practice is of course to require it in each ns where you use it (even though you could technically use it if anyone has required it if you use the full name) |
| 12:24 | jonathanj | okay, i guess that makes sense i just never paid attention when doing stuff like clojure.core/something or clojure.string/something but i guess something probably does require those already |
| 12:25 | justin_smith | right, in a bare repl not even clojure.string or clojure.set are available |
| 12:25 | justin_smith | though clojure.core is the one exception - without that you couldn't even require :) |
| 12:25 | jonathanj | is there a linter (or such) that could have caught this? |
| 12:25 | justin_smith | yes, eastwood |
| 12:25 | justin_smith | get it? linter eastwood |
| 12:26 | justin_smith | haha |
| 12:26 | justin_smith | I've tried quite a few, ://github.com/jonase/eastwood |
| 12:26 | justin_smith | err, bad paste |
| 12:26 | justin_smith | https://github.com/jonase/eastwood |
| 12:29 | jonathanj | thanks |
| 12:29 | justin_smith | even "lein check" might catch that (but might not) |
| 12:29 | jonathanj | yeah, in retrospect it's kind of obvious that this wouldn't have worked but i guess lein or boot must've been requiring it already so it didn't break in development |
| 12:30 | justin_smith | lein check just turns on reflection warnings then compiles every clj file |
| 12:30 | jonathanj | what's bad about reflection? |
| 12:31 | jonathanj | (lein check emits a ton of warnings for me) |
| 12:31 | justin_smith | jonathanj: makes code 100-1000x slower |
| 12:31 | jonathanj | mmm |
| 12:31 | justin_smith | (well, maybe only 10x slower sometimes, but it's pretty bad for perf) |
| 12:32 | jonathanj | good to know |
| 12:33 | _maddy | how do I get just the keys from a map? |
| 12:33 | justin_smith | _maddy: you're gonna laugh |
| 12:33 | justin_smith | ,(keys {:a 0 :b 1}) |
| 12:33 | _maddy | no |
| 12:33 | clojurebot | (:a :b) |
| 12:34 | justin_smith | OK, you don't have to laugh |
| 12:34 | _maddy | thanks, seems to do the trick |
| 12:35 | kwladyka | _maddy keep always open http://clojure.org/api/cheatsheet - it is really treasure for knowledge |
| 12:35 | _maddy | now lets say I have a map {}, I need to "add" stuff to it, which I guess means to make a new one, but then the map-function returns something else, so do I always need to do (into {} ? |
| 12:35 | justin_smith | or use a function that knows how to return a hash-map, sure |
| 12:36 | justin_smith | (eg. reduce-kv) |
| 12:36 | kwladyka | _maddy try to use this cheatsheet, really, in long term condition you will be happy with that. Just read all function in map section |
| 12:37 | _maddy | kwladyka: thanks, bookmarked it |
| 12:37 | kwladyka | _maddy you will discover many interesting things |
| 12:37 | justin_smith | ,(reduce-kv (fn [m k v] (assoc m k (inc v))) {} {:a 0 :b 2 :c 42}) |
| 12:37 | clojurebot | {:a 1, :b 3, :c 43} |
| 12:37 | justin_smith | matt_d: for third party libs, there is also specter |
| 12:37 | justin_smith | err |
| 12:38 | justin_smith | _maddy: ^ |
| 12:40 | _maddy | justin_smith: I am adding a new key though, not altering the old ones, is that different? |
| 12:40 | luma | ,(assoc {:foo 1} :bar 2) |
| 12:40 | clojurebot | {:foo 1, :bar 2} |
| 12:40 | justin_smith | _maddy: shouldn't be - as long as the info to add keys is somewhere in the input |
| 12:41 | justin_smith | _maddy: since you mentioned mapping I thought you were traversing the hash-map |
| 12:41 | justin_smith | (which is what reduce-kv is designed for) |
| 12:41 | _maddy | not traversing really, just adding a key |
| 12:41 | justin_smith | oh, then yeah, just assoc is all you need |
| 12:42 | justin_smith | assoc is var-args too |
| 12:42 | justin_smith | ,(assoc {:a 0} :b 1 :c 2) |
| 12:42 | clojurebot | {:a 0, :b 1, :c 2} |
| 12:47 | kwladyka | is it possible to write in schema https://github.com/plumatic/schema map has to have :id or :code or both? |
| 12:48 | kwladyka | or maybe i am using not the right tool? |
| 12:48 | justin_smith | kwladyka: you mean it needs one of the two, and can optionally have one of the others? |
| 12:48 | kwladyka | i want prepare schema for data tapes and also required data |
| 12:49 | kwladyka | justin_smith {:id 1 :code "fsadfasd"} or {:id 1} or {:code "fdsfdsafads"} |
| 12:49 | _maddy | the problem is that I have a two-dimensional map, I need to add something to the inner maps (can't really understand how reduce-kv works) |
| 12:49 | kwladyka | perhaps i should use bouncer and schema together |
| 12:50 | justin_smith | (s/conditional :id {:id Number Keyword s/Any} :code {:code String Keyword s/Any}) |
| 12:50 | _maddy | I know how normal reduce works |
| 12:51 | justin_smith | _maddy: reduce-kv is just like reduce, except it is optimized for hash-maps, and hands you the key and value as separate args |
| 12:51 | justin_smith | _maddy: maybe you can just use update-in or assoc-in ? |
| 12:51 | justin_smith | also, reduce is a lot more flexible than people take it for at first glance (as is reduce-kv) |
| 12:52 | _maddy | yeah, I usually think of reduce as reducing a collection to single value |
| 12:52 | justin_smith | _maddy: a hash-map is a single value :) |
| 12:52 | _maddy | sure |
| 12:52 | justin_smith | thanks to easy to use collections, a reduce can build up any structure you like |
| 12:53 | _maddy | but building up stuff feels contradictory to the name |
| 12:53 | justin_smith | yeah, I like the function, but the name (which is very historical) can be misleading |
| 12:53 | kwladyka | justin_smith the intention is not readable here but it should work |
| 12:54 | justin_smith | kwladyka: there could be a more idiomatic way to express it... |
| 12:54 | justin_smith | but the semantics are right at least |
| 12:54 | justin_smith | or should be close to it |
| 12:54 | kwladyka | i guess i will need some variants also, when X is present i also need Y and Z. Always complete. Not sure yet. |
| 12:54 | justin_smith | kwladyka: you could us s/conditional and then use functions that determine if a given variant is present |
| 12:55 | justin_smith | kwladyka: best option is stop using so many variant things! |
| 12:55 | kwladyka | not really sure what will be the end of requirements :) I am trying to write some schema for data like order, client, product, address to be consistent in whole system |
| 12:56 | justin_smith | kwladyka: one thing I like about regular schemas is that in the repl you can pprint them to remind yourself what the data here should look like |
| 12:56 | kwladyka | justin_smith i read about that, it should be helpful |
| 12:57 | kwladyka | anyway did you hear about some ready data schema for things like i describe? |
| 12:57 | kwladyka | maybe somebody did this work? |
| 12:57 | kwladyka | even in table in english which i can rewrite to clojure |
| 12:57 | kwladyka | it is hard work to design right schema |
| 12:57 | justin_smith | I have no idea... a library of common off the shelf schemas could be interesting |
| 12:58 | justin_smith | kwladyka: recently I did a massive refactor that would likely have been impossible without prismatic/schema - I captured the values the functions were getting from clients, then I wrote the strictest schemas I could that passed all those values, then wrote my new functions against those schemas |
| 12:59 | justin_smith | so much easier than trial and error when the data gets complex |
| 12:59 | justin_smith | and more accurate as documentation than any comments could be |
| 13:00 | kwladyka | schema looks cool, i think it will be very useful tool |
| 13:01 | kwladyka | especially for REST API |
| 13:03 | justin_smith | kwladyka: you might be interested in ring-swagger for this https://github.com/metosin/ring-swagger |
| 13:03 | kwladyka | justin_smith cool thx |
| 13:08 | jonathanj | so how do i fix reflection warnings for code that is something like: (defn [reason] (if (instance? Exception reason) a b))? |
| 13:09 | alex-weej | is there an os.path.join equivalent in clojure? |
| 13:09 | justin_smith | jonathanj: that's a tricky one |
| 13:09 | justin_smith | alex-weej: what is os.path.join |
| 13:09 | jonathanj | it joins several OS path components together with the OS-specific separator |
| 13:10 | alex-weej | and also deals with segments starting with a / so jumping back to the root |
| 13:10 | kwladyka | jonathanj http://clojure.wladyka.eu/posts-output/2015-08-24-how-to-improve-algorithm-speed.html#avoid_reflections |
| 13:10 | alex-weej | os.path.join(“foo”, “bar”, “/baz”) == “/baz” |
| 13:10 | alex-weej | assuming pathsep is / |
| 13:11 | _maddy | ok, I am not getting it, lets say I have map of maps: { "A" { :key 1 } }, how do I add new key/value to the inner maps? And by calculating that, I need the key of the inner map |
| 13:11 | kwladyka | jonathanj and there you have ready solution https://www.refheap.com/8bff42793e9abbeb9af803b23 |
| 13:12 | kwladyka | to not throw an exception if you don't have class loaded |
| 13:12 | kwladyka | this one is hard one to solve :) |
| 13:14 | justin_smith | ,(java.nio.file.Paths/get "foo" (into-array ["bar" "baz" "quux"])) ; alex-weej this is ugly, but it works |
| 13:14 | clojurebot | #object[sun.nio.fs.UnixPath 0xfe5389 "foo/bar/baz/quux"] |
| 13:15 | justin_smith | if you call str on it you get the path as a string |
| 13:15 | justin_smith | alex-weej: https://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html |
| 13:15 | jonathanj | kwladyka: that's not what the code does |
| 13:16 | alex-weej | is there some project to wrap java APIs in more clojure-friendly terms btw? |
| 13:16 | kwladyka | jonathanj ? |
| 13:16 | jonathanj | kwladyka: the code does a if the object is an instance of an exception and b if it's not an instance of exception |
| 13:16 | alex-weej | would be cool to collect some of the more “obvious” bindings |
| 13:16 | justin_smith | alex-weej: there are N+1 projects |
| 13:16 | jonathanj | kwladyka: whether the class is loaded or not is not really important, unless i'm missing something |
| 13:16 | justin_smith | alex-weej: clojure is a java library, it's all accessible, and sometimes people want to add a friendly layer on top |
| 13:16 | kwladyka | jonathanj ok maybe i mentioned about that unnecessary |
| 13:17 | kwladyka | jonathanj did you look on http://clojure.wladyka.eu/posts-output/2015-08-24-how-to-improve-algorithm-speed.html#avoid_reflections ? |
| 13:17 | alex-weej | justin_smith: sure, i’m just wondering if i can pull-request a library of wrappers for things like java.nio.file |
| 13:17 | jonathanj | kwladyka: not yet |
| 13:17 | alex-weej | this doesn’t work anyway, user=> (str (java.nio.file.Paths/get "foo" (into-array ["bar" "baz" "/quux"]))) |
| 13:17 | alex-weej | "foo/bar/baz/quux" |
| 13:18 | kwladyka | jonathanj it should explain how to solve your problem |
| 13:19 | shiranaihito | ,(str (java.nio.file.Paths/get "foo" (into-array ["bar" "baz" "/quux"]))) |
| 13:19 | clojurebot | "foo/bar/baz/quux" |
| 13:19 | shiranaihito | what's wrong with that? :) |
| 13:19 | justin_smith | also, that's super easy to wrap in a vararg string function |
| 13:20 | bacon198` | alex-weej: a good number of projects are trying to making the java libraries more friendly |
| 13:20 | jonathanj | kwladyka: i don't actually understand how it solves my problem |
| 13:20 | bacon198` | which is great, because you get tried and tested libraries being wrapped nicely |
| 13:20 | jonathanj | kwladyka: the problem is that i cannot provide a type hint to a value that has a dynamic type |
| 13:20 | shiranaihito | bacon198` i sure hope they're not wrapping some goddamn commons-turdnuggets from 1998 or something |
| 13:20 | alex-weej | In [2]: os.path.join("foo", "bar", "/baz") |
| 13:20 | alex-weej | Out[2]: '/baz' |
| 13:21 | shiranaihito | ah.. Python :P |
| 13:21 | jonathanj | i think i'm going to have to change the calling code to convert Exception so that i don't need the test |
| 13:21 | shiranaihito | alex-weej what do you mean with that though? does python just ignore the first two elements? is that what you want? |
| 13:22 | TimMc | alex-weej: I believe that reducing over the segments with the File constructor does what you want, if no one has mentioned that... |
| 13:22 | justin_smith | TimMc: not with the example he gave |
| 13:23 | TimMc | Hmm, lemme find the code of mine that does this... |
| 13:24 | TimMc | Ah, yeah, I see I ran into that problem as well. |
| 13:25 | TimMc | https://gist.github.com/timmc/de9251eb5343bcc72ef20347ef24026c |
| 13:25 | TimMc | Needs cleanup, since I wrote it quite a while ago. :-) |
| 13:25 | justin_smith | TimMc: yeah, line 6 should be 3 lines, but it's not super bad |
| 13:26 | kwladyka | jonathanj maybe i miss something but what you pasted here doesn't throw reflection wartning |
| 13:26 | kwladyka | jonathanj are you sure where is the source of this warning? |
| 13:26 | TimMc | justin_smith: I also don't need to capture f2, I can just use it and discard it in the conditional. |
| 13:26 | kwladyka | (defn foo [x] (instance? Exception foo)) is really free of this warning |
| 13:27 | kwladyka | i mean (defn foo [x] (instance? Exception x)) |
| 13:28 | justin_smith | kwladyka: I was skeptical so I double checked, you're right |
| 13:28 | kwladyka | jonathanj so i pasted you my article to help you find the right place which makes this warnings |
| 13:29 | shiranaihito | alex-weej or you can join some strings and give them to File |
| 13:29 | shiranaihito | ,(str (java.io.File. (clojure.string/join "/" ["foo" "bar" "baz"]))) |
| 13:29 | clojurebot | "foo/bar/baz" |
| 13:30 | kwladyka | justin_smith i checked that too twice :) |
| 13:30 | justin_smith | shiranaihito: fails on alex-weej 's example though |
| 13:30 | alex-weej | doesn’t work when one of the segments is an absolute path e.g. my example |
| 13:30 | shiranaihito | ok |
| 13:30 | shiranaihito | ,(str (java.io.File. "/foo" (clojure.string/join "/" ["bar" "baz"]))) |
| 13:30 | clojurebot | "/foo/bar/baz" |
| 13:31 | justin_smith | that isn't any better |
| 13:32 | shiranaihito | well it does start with an absolute part :P |
| 13:33 | shiranaihito | if one of the elements denotes an absolute path, it probably goes in first anyway |
| 13:38 | justin_smith | also, platforms are allowed to use separators other than "/" |
| 13:40 | TEttinger | J:☃Users☃Justin☃Code☃ |
| 13:41 | shiranaihito | justin_smith and that means my little snippet was bad? :P |
| 13:41 | justin_smith | shiranaihito: it's a second way it doesn't address the initial question |
| 13:42 | justin_smith | which explicitly mentioned using the system's native separator |
| 13:42 | shiranaihito | chill :) |
| 13:42 | kwladyka | shiranaihito i believe i saw some ready solution for that in the past.... maybe |
| 13:43 | shiranaihito | ,(str (java.io.File. (str java.io.File.separator "foo") (clojure.string/join java.io.File.separator ["bar" "baz"]))) |
| 13:43 | kwladyka | but it can be my imagination |
| 13:43 | clojurebot | #error {\n :cause "java.io.File.separator"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: java.io.File.separator, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.ClassNotFoundException\n :message "java.io.File.separator"\n :at [java.net.URLClassLoader$1 run "URLClassLoade... |
| 13:43 | shiranaihito | alright.. something like that anyway :P |
| 13:43 | shiranaihito | kwladyka solution for what? the file path stuff? |
| 13:43 | justin_smith | ,java.io.File/separator |
| 13:43 | clojurebot | "/" |
| 13:43 | shiranaihito | yeah, just realized |
| 13:44 | kwladyka | shiranaihito some library to do that or Java function.... i don't really remember. Some solution to make the right path |
| 13:44 | shiranaihito | yeah, it's not that complicated |
| 13:44 | shiranaihito | i figured joining strings and then just handing them to File would be "neater" |
| 13:44 | shiranaihito | or simpler (etc whatevs) than reducing with Files |
| 13:45 | kwladyka | i believe anyway you miss many not obviously things, like for example different systems |
| 13:45 | kwladyka | path in the windows for example can looks like c:/foo/bar |
| 13:45 | shiranaihito | sure, but that's what further development is for :p |
| 13:45 | shiranaihito | we're just swapping snippets to help people |
| 13:50 | _maddy | my god, after all this work I have a data structure which looks really cumbersome.. |
| 13:54 | alex-weej | is there some popular or built in library for running subprocesses and dealing with their events (e.g. stdin/stderr output, process exit) via an event loop or something? |
| 13:56 | shiranaihito | alex-weej: Java *kind of* has support for that |
| 13:56 | shiranaihito | look at ProcessBuilder for example |
| 13:56 | justin_smith | there's ProcessBuilder and also conch which wraps ProcessBuilder / Process |
| 13:56 | shiranaihito | but for whatever it's worth, i couldn't get communicating with subprocesses to work when i tried |
| 13:57 | justin_smith | shiranaihito: each Process object has two inputstreams and an outputstream |
| 13:57 | shiranaihito | yeah |
| 13:57 | shiranaihito | as far as i know, i was using it right.. not 100% sure ofc |
| 13:58 | justin_smith | I've done it before, it worked fine |
| 13:58 | shiranaihito | but something was wrong when trying to do input/output with processes |
| 13:59 | alex-weej | conch looks interesting thanks - wondering if i should try to shoehorn something into core.async |
| 14:00 | alex-weej | i want to have a bunch of subprocesses running at any one time and just select on their events |
| 14:04 | justin_smith | alex-weej: you could have regular threads that glock on read from the inputStream of the processes |
| 14:05 | justin_smith | alex-weej: don't do that in go blocks, go blocks are not for blocking operations |
| 14:05 | alex-weej | one per process? |
| 14:05 | justin_smith | yeah, and a single go block reading the results they put on the channel |
| 14:05 | alex-weej | sounds simple enough - is it actually reasonable straightforward to start threads in clojure? |
| 14:06 | kwladyka | alex-weej what exactly do you want to achieve? maybe you want just share state? |
| 14:06 | alex-weej | i just want to run a set of subprocesses and then multiplex their events in a loop |
| 14:07 | alex-weej | events are like - ready for read on stderr, ready for read on stdout, ready for write on stdin, process terminated with exit code N |
| 14:08 | justin_smith | alex-weej: shiranaihito: simple repl example of i/o with a process in the repl (in a real example you would read to a byte-array, not read a byte at a time, of course) |
| 14:08 | justin_smith | https://gist.github.com/noisesmith/f2ca73a0a6b0e5d686487c6084196a97 |
| 14:08 | alex-weej | if this was low level linux i would fork and exec and do some fd sharing, and just epoll the fds without the use of any threads |
| 14:08 | justin_smith | alex-weej: the api doesn' |
| 14:08 | justin_smith | t expose "ready for" anything, sadly |
| 14:09 | justin_smith | which is why I mentioned threads doing blocking reads/writes |
| 14:10 | shiranaihito | justin_smith thanks :) i think my main problem was taking stuff from one process and handing it into another, but i just scrapped what i was doing and went with Python instead |
| 14:10 | shiranaihito | .. and Python did exactly what i wanted with like a couple of lines of code :) |
| 14:11 | justin_smith | shiranaihito: the biggest gotcha is needing to do the .flush method iirc |
| 14:11 | shiranaihito | i'm pretty sure i flushed stuff too.. i've used Java for a long time |
| 14:12 | justin_smith | the problem with system stuff in java is it is committed to the lowest common denominator, and there are some really low targets it had to hit in the past (Win9x etc.) |
| 14:12 | justin_smith | shiranaihito: oh, OK |
| 14:12 | justin_smith | shiranaihito: I built a crazy system that piped the contents of a 16 channel sound card to 16 separate programs in clojure - which was amazing and also a pain in the ass |
| 14:12 | justin_smith | but it worked! |
| 14:12 | shiranaihito | basically i was trying to: start a process, feed it input, wait for it to complete (working on the input), and then hoping to take out whatever it produced.. and hand it off to another process |
| 14:13 | justin_smith | shiranaihito: see, the people who wrote the software spec assumed there was a "read one channel of a sound card" api - which of course doesn't exist anywhere |
| 14:13 | shiranaihito | wow, sounds hard-core |
| 14:13 | justin_smith | I didn't really grok core.async until I completed that project :) |
| 14:13 | shiranaihito | :) |
| 14:13 | shiranaihito | i haven't even tried using it yet |
| 14:14 | jonathanj | can i add a type hint to a parameter inline? |
| 14:14 | jonathanj | `(.someMethod obj ^long value)` for example |
| 14:15 | justin_smith | alex-weej: a lot of the stuff you are trying to do is easier in pixie, which is still kind of experimental, but it's a clojure implemented using rpython's compiler (but there is no python available at runtime mind you) |
| 14:15 | shiranaihito | "inline"? |
| 14:15 | justin_smith | jonathanj: yeah, that should work |
| 14:15 | kwladyka | jonathanj why not in the definition of function? |
| 14:16 | kwladyka | i mean in the parameters |
| 14:16 | jonathanj | kwladyka: because it's just a minor intermediate result |
| 14:18 | kwladyka | jonathanj i guess more readable it will be when you use ^long somewhere when this result comes, i don't know what you use, let or something |
| 14:22 | _maddy | how do I configure cider repl so that I have to use ns in front of functions (I want to have functions of same name in 2 files) |
| 14:23 | kwladyka | _maddy just use namespaces when call this functions |
| 14:24 | kwladyka | foo/f and bar/f |
| 14:24 | hodwik | If I want to send a header param as part of a post with clojure-http, do I just make a map {:headers {:API_KEY |
| 14:24 | hodwik | "APIKEY"}} |
| 14:24 | hodwik | and send that as part of the post? |
| 14:28 | alex-weej | is there a common idiom or builtin for combining let with if? e.g. (let-if [x y] then else) -> (let [x y] (if x then else)) - to avoid repeating x |
| 14:29 | ridcully_ | hodwik: that's how it works in clj-http. did you mean this or the clojure-http-client lib? |
| 14:30 | hodwik | @ridcully sorry, that's what I meant |
| 14:33 | jonathanj | the type hints from protocols are disregarded in defrecord implementations? |
| 14:33 | kwladyka | alex-weej if-let still you don't try use cheatsheet, just click there ctrl+f in your browser |
| 14:34 | hiredman | they don't exist |
| 14:35 | hiredman | e.g. you can attach metadata to the parameters in a protocol, but it doesn't do anything |
| 14:35 | alex-weej | kwladyka: i see it’s spelled if-let, that makes more sense actually! |
| 14:35 | alex-weej | thanks |
| 14:36 | hodwik | Could anyone with clj-http experience tell me why this: http://pastebin.com/8nwSeqVA is spitting out:Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to [B, compiling:(stfr_bot/core.clj:74:1) |
| 14:36 | hodwik | the variables are all def'd before that section |
| 14:38 | ridcully_ | hodwik: i think it has to be :json there. also i doubt it will deal with the json conversion anyway |
| 14:40 | ridcully_ | hodwik: something like this: https://github.com/christoph-frick/rest-repl/blob/master/src/rest/public.clj#L56-L59 |
| 14:41 | TEttinger | [B is that wacky stacktrace-speak for byte array |
| 14:45 | justin_smith | ,(class (.getBytes "foo")) |
| 14:45 | clojurebot | [B |
| 14:46 | hodwik | ridcully: Awesome! Thanks so much. I was trying to use Cheshire to encode my json, but just doing it with clj-http was much easier |
| 14:49 | _maddy | how do I pass-through variable arguments to another function? I can create optional args with &, but they are set to nil (and sent as nil to the next func, which is a problem) |
| 14:49 | justin_smith | _maddy: if you use arity overloading instead of &, then it's much easier to provide defaults |
| 14:50 | justin_smith | ,((fn foo ([] (foo |
| 14:50 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 14:50 | justin_smith | err |
| 14:50 | justin_smith | ,((fn foo ([] (foo "hi")) ([message] message))) |
| 14:50 | clojurebot | "hi" |
| 14:51 | _maddy | I could use arity overloading, but it looks like then I have to repeat the function body multiple times |
| 14:51 | _maddy | which is not nice |
| 14:51 | justin_smith | _maddy: no, that's never needed |
| 14:51 | justin_smith | _maddy: look at my example, no repitition |
| 14:52 | justin_smith | ,((fn f ([] (f 2)) ([x] (* x x x))) |
| 14:52 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 14:52 | _maddy | oh, but the problem is that I don't want to define defaults here, they are defined in the inner function which I am calling |
| 14:52 | justin_smith | ,((fn f ([] (f 2)) ([x] (* x x x)))) |
| 14:52 | clojurebot | 8 |
| 14:52 | _maddy | where I already have arity overloading pattern |
| 14:53 | _maddy | I think I am too tired, have to continue on another day :) |
| 14:53 | _maddy | really liking clojure now that I am slowly starting to understand it |
| 16:05 | beaky | i love clojure too |
| 16:23 | jonathanj | if i have a protocol method defined like (foo [this ^SomeObj x]) and i have the implementation (on defrecord, for example) like (foo [this ^SomeObj x]) then i get a compile error like: Can't find matching method: foo, leave off hints for auto match. |
| 16:24 | jonathanj | if i omit the type hint for the implementation then it compiles but `x` is not type hinted |
| 16:29 | TimMc | Could it be that you need to throw more type hints at it? I haven't worked with protocols recently, but I wonder if "this" or the return value need hinting (seems like overkill though). |
| 16:33 | amalloy | protocol functions don't support type hinting anyway |
| 16:44 | jonathanj | how do i unambiguously import two java classes with the same name? |
| 16:44 | clojurebot | excusez-moi |
| 16:47 | amalloy | the same way you do it in java: only import one of them, and refer to the other fully-qualified |
| 16:49 | jonathanj | i don't recall ever having to do this in java, so i wasn't aware if there was another way |
| 16:49 | TimMc | There's another option, which is .importClass... |
| 16:49 | jonathanj | C# has some way to alias stuff, iinm |
| 16:51 | TimMc | If you don't mind potentially messing up some automated tooling and IDEs, you can do (.importClass *ns* 'RLN foo.bar.ReallyLongName) |
| 16:51 | TimMc | stick that right after your ns block and say two Hail Marys |
| 16:52 | jonathanj | haha, i'll just go with the fully qualified option |
| 16:57 | TimMc | I've done this once and never had a problem with it, just... you know, fair warning. |
| 17:02 | jonathanj | like that guy who puts his hand into the crocodile's mouth and doesn't get bitten, then he calls his friends over to see his neat trik |
| 17:08 | TimMc | jonathanj: There are two risks: 1) It might go away (binary .importClass is not used anywhere I can see in 1.7.0), and 2) tools might expect all imports and requires to be parseable from the ns block. |
| 17:08 | TimMc | So: Possibly annoying, but it's not like the program will behave incorrectly if it runs at all. |
| 17:24 | fikgol | why storm used maven instead of leiningen after 0.9 ? |
| 17:25 | TEttinger | fikgol: I might be thinking of a different storm |
| 17:34 | TEttinger | fikgol, ah https://github.com/apache/storm/pull/14 |
| 17:34 | TEttinger | apparently their build process is complex |
| 18:03 | vermiculus | i've got an algorithm challenge if anyone fancies a crack at it |
| 18:03 | vermiculus | it's a recursive question involving maps |
| 18:06 | TEttinger | me crack |
| 18:07 | vermiculus | TEttinger: :) |
| 18:07 | vermiculus | Say you have a structure like {1 {:parent :root, :slug "lovely"}, 2 {:parent 1, :slug "lovelier"}, 3 {:parent 1, :slug "loveliest"}, 4 {:parent :root, :slug "cool"}} |
| 18:08 | vermiculus | Notice that this is pretty much a tree of slugs |
| 18:08 | vermiculus | I'd like to get the structure {1 "/lovely" 2 "/lovely/lovelier" 3 "/lovely/loveliest" 4 "/cool"} |
| 18:08 | justin_smith | oh, nice, a graph |
| 18:09 | vermiculus | :-) |
| 18:10 | justin_smith | vermiculus: what would you want if something had :parent 3? |
| 18:10 | justin_smith | what if 5 had :parent 6 and 6 had :parent 5? what would print then? |
| 18:10 | vermiculus | justin_smith: I'd say behavior is undefined in those cases. |
| 18:10 | vermiculus | Probably throw some sort of error. |
| 18:11 | justin_smith | so you have a representation that can do arbitrary graphs, but behavior is only defined for tree (directed and acyclic) |
| 18:11 | vermiculus | justin_smith: correct |
| 18:11 | vermiculus | turning the starting structure into a tree is, of course, a valid approach |
| 18:16 | TEttinger | ,(let [structure {1 {:parent :root, :slug "lovely"}, 2 {:parent 1, :slug "lovelier"}, 3 {:parent 1, :slug "loveliest"}, 4 {:parent :root, :slug "cool"}}] (into {} (map (fn [[k {:keys [parent slug]}]] [k (str (get-in structure [parent :slug] "") "/" slug)]) structure))) ; not yet ready |
| 18:16 | clojurebot | {1 "/lovely", 2 "lovely/lovelier", 3 "lovely/loveliest", 4 "/cool"} |
| 18:17 | TEttinger | this only handles one level, which is the first problem |
| 18:17 | TEttinger | the lesser problem is not getting the opening / right |
| 18:18 | justin_smith | (get-in structure [parent :slug] "/") |
| 18:18 | justin_smith | shoud work! |
| 18:19 | justin_smith | oh, wait |
| 18:19 | justin_smith | never mind, your thing is good, you just need to make it recursive |
| 18:34 | vermiculus | I have a solution now, but it's pretty ugly :) |
| 18:35 | vermiculus | It's also a little cheat-y IMHO |
| 18:35 | vermiculus | https://gist.github.com/vermiculus/c8a531a86a0a65cdb9af4a466ed0721f |
| 18:38 | vermiculus | ,(defn get-topic-children [topics topic-id] (map first (filter #(= topic-id (:parent (second %))) topics))) |
| 18:38 | clojurebot | #'sandbox/get-topic-children |
| 18:39 | vermiculus | ,(defn get-routes [topics topic-id & [slug-so-far]] (let [children (get-topic-children topics topic-id) newslug (if (= topic-id :root) "" (str slug-so-far "/" (:slug (get topics topic-id))))] (if children (into (if (= topic-id :root) {} {topic-id newslug}) (map (fn [child-id] (if child-id (get-routes topics child-id newslug))) children)) {topic-id newslug}))) |
| 18:39 | clojurebot | #'sandbox/get-routes |
| 18:39 | vermiculus | ,(get-routes {1 {:parent :root, :slug "lovely"}, 2 {:parent 1, :slug "lovelier"}, 3 {:parent 1, :slug "loveliest"}, 4 {:parent :root, :slug "cool"}} :root) |
| 18:39 | clojurebot | {1 "/lovely", 2 "/lovely/lovelier", 3 "/lovely/loveliest", 4 "/cool"} |
| 19:03 | vermiculus | TEttinger: Feel free to ping me on twitter if you find a cleaner solution :-) (same username: @vermiculus) |
| 20:02 | asdf12z_ | (defroutes app (GET "/ws" request (ws-handler request))) can someone explain to me how does "request" work here? this is compojure |
| 20:02 | asdf12z_ | how is request even defined? |
| 20:02 | asdf12z_ | like how is it possible to pass `GET` the result of (ws-handler request) when request isn't defined yet? |
| 20:03 | asdf12z_ | i'm guessing its part of the macro magic |
| 20:03 | justin_smith | asdf12z_: defroutes is a macro, and it's binding the client's request object to the symbol 'request |
| 20:03 | justin_smith | asdf12z_: in normal clojure macros, request would be in a vector (eg let or defn) |
| 20:04 | justin_smith | I guess they decided compojure does not need a vector, because your handler is guaranteed to receive exactly one argument? not sure |
| 20:05 | asdf12z_ | i guess i'm just confused as to how the code is evaluated and executed, so everything in defroutes doesn't actually eval yet, it's all fed in, and the macro then fills in for all the argument stuff like request |
| 20:05 | asdf12z_ | is that about right? |
| 20:05 | justin_smith | well macros are allowed to do anything they want to their input - take it as is, evaluate it in the lexical environment, whatever |
| 20:06 | justin_smith | macroexpand might be informative here |
| 20:08 | asdf12z_ | ok thanks justin_smith |