2013-08-09
| 00:02 | axle_512 | does anyone know if "network channels" for core.async are being developed? Rich hinted at it in his blog post when he introduced core.async. |
| 00:05 | xeqi | axle_512: they've been thinking over some different ideas. In the mean time lynaghk has some interesting projects at https://github.com/lynaghk/zmq-async and https://github.com/lynaghk/jetty7-websockets-async |
| 00:06 | axle_512 | xeqi: thanks |
| 00:06 | xeqi | neither of them general "network channels" but possibly useful |
| 00:13 | axle_512 | xeqi: if I understand correctly, lynaghk's websocket impl lets you use go routines with websocket IO? |
| 00:13 | axle_512 | xeqi: if so, that's pretty freakin cool |
| 00:14 | xeqi | I think so, but I only saw it earlier and know very little about websockets |
| 00:15 | axle_512 | I may tinker with it to see if I can understand it better. thanks fro the links. |
| 00:19 | Apage43 | ooh |
| 00:19 | clojurebot | Huh? |
| 00:20 | Apage43 | I have some aleph/websocket stuff I might see about converting.. though it's really so simple it might not be that helpful |
| 00:23 | ToBeReplaced | ,((fn select-by |
| 00:23 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 00:23 | ToBeReplaced | [f & seqs] |
| 00:23 | ToBeReplaced | (when-let [non-empty-seqs (seq (remove empty? seqs))] |
| 00:23 | ToBeReplaced | (let [[[x & more] & others] (sort-by (comp f first) non-empty-seqs)] |
| 00:23 | ToBeReplaced | (lazy-seq (cons x (apply select-by f more others)))))) |
| 00:23 | ToBeReplaced | identity [1 3 5] [6 7 9] [2 4 8]) |
| 00:23 | ToBeReplaced | ,((fn select-by [f & seqs] (when-let [non-empty-seqs (seq (remove empty? seqs))] (let [[[x & more] & others] (sort-by (comp f first) non-empty-seqs)] (lazy-seq (cons x (apply select-by f more others)))))) identity [1 3 5] [6 7 9] [2 4 8]) |
| 00:23 | clojurebot | (1 2 3 4 5 ...) |
| 00:45 | puredanger | axle_512: re network channels for core.async, Tim B has been working on approaches for that |
| 00:46 | axle_512 | puredanger: thanks |
| 00:50 | puredanger | axle_512: it is very challenging (maybe impossible) to match existing async channel semantics when the network and unreliability is in the mix, so the question then becomes what semantics are useful and how do they interact. |
| 00:52 | axle_512 | puredanger: Does the 'go' language support network channels? |
| 00:53 | axle_512 | puredanger: I imagine it's pretty difficult macro coding to get it right. |
| 00:53 | axle_512 | puredanger: on the clojure side, that is. |
| 00:53 | bbloom | axle_512: they had one at some point, but they cut it |
| 00:54 | puredanger | axle_512: the coding is the easy part. understanding what to code in the first part is the hard part. |
| 00:54 | puredanger | s/part/place/ |
| 00:54 | axle_512 | so pretty bleeding edge stuff then. Thanks for the info. |
| 01:00 | puredanger | surely |
| 01:05 | egghead | bbloom: thanks for the help w/ the core.async stuff, it cleared up a lot |
| 01:05 | bbloom | egghead: my pleasure. explaining helps me too! |
| 01:12 | ambrosebs | bbloom: have you looked at turning js* nodes in CLJS into AST trees? |
| 01:12 | bbloom | ambrosebs: i have a pretty old proof-of-concept branch: https://github.com/brandonbloom/clojurescript/tree/js-ast |
| 01:14 | ambrosebs | bbloom: nice |
| 01:15 | bbloom | ambrosebs: yeah, i liked it :-) basically just search "js/" in compiler.clj |
| 01:15 | ambrosebs | bbloom: I need this done, I will continue your work. |
| 01:15 | bbloom | ambrosebs: was dramatically slower, unfortunately |
| 01:15 | ambrosebs | ah |
| 01:15 | bbloom | in theory, it could be made faster by piping the data structures directly into closure compiler |
| 01:16 | bbloom | but the internal AST for gclosure is an implementation detail & i had to call a bunch of private APIs via reflection |
| 01:16 | bbloom | see also https://github.com/brandonbloom/clojurescript/blob/js-ast/src/clj/cljs/js.clj for the "dsl" of sorts |
| 01:17 | ambrosebs | Do you think it's a good idea to convert js* nodes to AST's post-analsis? ie. just before I type check it? |
| 01:17 | bbloom | well, parsing JS fragments is a whole-nother problem |
| 01:17 | ambrosebs | I figured. |
| 01:17 | bbloom | i punted on that & just rewrote usages of js* to work w/ the js ast dsl i made |
| 01:18 | bbloom | very macro-like |
| 01:19 | bbloom | dnolen said that it was ok to break js* though, since it's an impl detail |
| 01:20 | bbloom | i eliminated several uncessary usages of js* in core.clj{,s} but i'm not sure which of them made it back to master |
| 01:20 | bbloom | for example: https://github.com/brandonbloom/clojurescript/commit/3f95b2abbc4294bcbeb46a996becbb08dd21f453 |
| 01:21 | bbloom | my first few commits on that branch are illustraitive |
| 01:22 | bbloom | ambrosebs: let me know if there's anything i can do to help! pure functions > printing side effects :-) |
| 01:23 | ambrosebs | bbloom: ok, I'll dive in. |
| 01:23 | bbloom | the branch is pretty old, lots of stuff has chnaged |
| 01:24 | ambrosebs | would you advise starting again with the same approach on top of master? |
| 01:24 | bbloom | yeah, i think a manual rebase is probably a reasonable approach |
| 01:24 | ambrosebs | ok |
| 01:25 | bbloom | my work is in lots of small commits, so you could probably just follow the pattern |
| 01:25 | bbloom | it also hints at how to do the work piecemeal, which was the hard part |
| 01:26 | ambrosebs | good |
| 01:27 | ambrosebs | do you think it will take long? |
| 01:27 | bbloom | ambrosebs: gclosure's IR.java library provides a sensible api for building an AST. realistically, there is no need to use the gclosure ast, it was just the shortest path to getting a printer too |
| 01:27 | ambrosebs | is that where the reflection comes from? |
| 01:28 | bbloom | yeah |
| 01:28 | ambrosebs | great |
| 01:28 | bbloom | in theory, if we could bipass the printer, then the might be FASTER, but i couldn't figure out how to do that precisely |
| 01:29 | bbloom | also, the gclosure optimizer expects very particularly shaped ASTs |
| 01:29 | bbloom | they have a validator you can run, but i didn't bother b/c the printer seems to be much more permissive than the verifier & optimizer passes |
| 01:29 | bbloom | bypass* |
| 01:29 | bbloom | looks like i worked on it for one long weekend :-P |
| 01:30 | ambrosebs | yea, that's promising :) |
| 01:30 | bbloom | oh now i remember the bigger issue with bypassing the parser: creating type annotations |
| 01:30 | bbloom | https://groups.google.com/forum/#!topic/closure-compiler-discuss/OEwLWkw4Kug |
| 01:42 | bbloom | ambrosebs: what do you need it for? |
| 01:42 | ambrosebs | bbloom: Typed CLJS |
| 01:43 | bbloom | glorious. |
| 01:43 | bbloom | the js* form is fucking you up, huh? |
| 01:43 | ambrosebs | royally |
| 01:43 | ambrosebs | I am stuck |
| 01:44 | bbloom | could you maybe just add a type paramter to js* ? |
| 01:44 | bbloom | (js* Number "(~{} + ~{})" x y) |
| 01:44 | bbloom | something like that |
| 01:45 | ambrosebs | I still want to know what operation is happening |
| 01:45 | ambrosebs | I might as well break js* properly. |
| 01:45 | bbloom | ambrosebs: why does the operation matter? |
| 01:46 | ambrosebs | bbloom: things like typeof give extra information |
| 01:47 | bbloom | ambrosebs: ah. makes sense |
| 01:47 | bbloom | i think eliminating js* is easier than switching to a JS ast |
| 01:48 | bbloom | check out this trick: https://github.com/brandonbloom/clojurescript/commit/335d3e589bf175ff77d31acc36c6174bb54ce567 |
| 01:48 | ambrosebs | Ok. I've never used js before, so I'm glad you're telling. |
| 01:49 | bbloom | basically, that makes js/whatever work like a special form if the whatever is in a list of operators |
| 01:49 | bbloom | only ~ and ^ required special treatment, which i punted on too lol |
| 01:49 | ambrosebs | cool! |
| 01:50 | ambrosebs | do you know how I can get a nice view of all the things you've changed? |
| 01:51 | bbloom | learn to git n00b! :-) |
| 01:51 | bbloom | git log `git merge-base master js-ast`..js-ast |
| 01:52 | ambrosebs | xD |
| 01:53 | bbloom | s/log/diff or difftool, of course too |
| 01:53 | ambrosebs | yes of course >.> |
| 01:54 | bbloom | so since ~ and ^ were invalid syntax, and js/<< seemed odd given the name clojure.core/bitwise-shift-left.... |
| 01:54 | bbloom | i figured that a more robust approach would be to create a js* namespace |
| 01:54 | bbloom | basically a virtual namespace bootstrapped by the compiler which was just a mapping of clojure-friendly-names to operator special forms |
| 01:56 | ambrosebs | ok. and you'd have vars like <<, ~ ^ etc? |
| 01:57 | bbloom | well yeah, so that commit i just linked you to has a set of vars like that, but since ^ and ~ are invalid identifiers, it would be more like a map '{bitwise-left-shift "<<" bitwise-not "~" …} |
| 01:58 | ambrosebs | oh ok, that's your virtual namespace, just a map. |
| 01:58 | bbloom | yeah |
| 01:59 | bbloom | anyway, i'm off to bed. good luck & let me know how it goes |
| 01:59 | ambrosebs | cya! |
| 02:44 | devn | hello all |
| 03:22 | callen | devn: hi |
| 03:26 | devn | callen: good morning |
| 03:26 | devn | callen: what dost thou computeth? |
| 03:29 | callen | devn: ring middleware |
| 03:29 | callen | nothing interesting |
| 04:08 | clj_new_2345 | I need to reinsatll ubuntu. I'm at the grub prompt. Is there a way to force grub to boot from the cdrom? |
| 04:08 | clgv | clj_new_2345: wrong channel? |
| 04:08 | clj_new_2345 | yes |
| 04:08 | clj_new_2345 | sorry |
| 04:09 | clj_new_2345 | habit of auto joining #clojure |
| 04:09 | ordnungswidrig | /join #clojure.de |
| 04:37 | muhoo | this looks like the long/wrong way: (defn name-to-fn [s] (var-get (resolve (symbol s)))) |
| 04:40 | clgv | muhoo: vars can be used as functions as well. |
| 04:40 | clgv | ,((resolve (symbol "inc")) 0) |
| 04:40 | clojurebot | 1 |
| 04:41 | muhoo | oh cool, better thanks |
| 04:52 | Hail_Spacecake | I'm trying to install leiningen with the shell script method |
| 04:52 | Hail_Spacecake | but it seems broken on my system |
| 04:52 | Hail_Spacecake | does it expect HTTP_CLIENT to already be defined? |
| 04:54 | callen | jesus christ that nick |
| 04:55 | Hail_Spacecake | like, this script is really broken |
| 04:55 | Hail_Spacecake | it's trying to call download_failed_messsage before it's defined |
| 04:55 | Hail_Spacecake | which I don't think you can do in bash |
| 04:55 | callen | Hail_Spacecake: ...man, what's with the name? |
| 04:55 | Hail_Spacecake | callen what about it? |
| 04:55 | callen | Hail_Spacecake: futile? |
| 04:56 | Hail_Spacecake | anyway this is the stable version of the script, I can't be the only one with this problem |
| 04:56 | Hail_Spacecake | futile? not sure what you mean |
| 04:58 | schmir | technomancy: installation of the latest leiningen fails for me: /home/tt/bin/lein: line 57: /home/tt/.lein/self-installs/leiningen-2.3.0-standalone.jar.pending: No such file or directory |
| 04:58 | schmir | is this a known problem? |
| 04:58 | callen | Hail_Spacecake: have you tried using refheap to post an error message? |
| 04:58 | callen | Also this is the first I've seen of this. |
| 04:59 | callen | not that I am an authority or anything, but I lurk enough. |
| 04:59 | Hail_Spacecake | I just asked in #leiningen, apparently this just broke |
| 04:59 | Hail_Spacecake | ah, yeah, there's a commit fixing it |
| 04:59 | Hail_Spacecake | that is the latest commit |
| 04:59 | Hail_Spacecake | and an hour old |
| 05:01 | hyPiRion | schmir: yes |
| 05:01 | hyPiRion | I'm working on a temporary fix as we speak |
| 05:01 | schmir | ok. thanks! |
| 05:02 | hyPiRion | (just need to ensure it works everywhere) |
| 05:55 | hyPiRion | temp fix: https://github.com/technomancy/leiningen/issues/1279#issuecomment-22384614 |
| 05:55 | hyPiRion | (for Leiningen 2.3.0) |
| 06:02 | wei | what's the best way to diff two clojure data structures? |
| 06:14 | samrat | wei: you might want to look at clojure.data/diff |
| 06:27 | gavri | what's the simplest way to get an instance of the ratio type representing 1/1 ? |
| 06:28 | wei | samrat: thanks |
| 06:28 | gavri | (rationalize 1) doesn't do it |
| 06:28 | gavri | neither does (rationalize 1.0) |
| 06:28 | gavri | but it works for (rationalize 1.5) |
| 06:28 | llasram | gavri: Why do you want a Ratio of 1/1 instead of just the (big)integer 1? |
| 06:29 | H4ns | is there something better than slime for clojure when one is an emacs user? |
| 06:29 | gavri | I've written a recursive method to generate the haromonic series |
| 06:29 | gavri | I'd like to call (numerator) on the argument to the function |
| 06:29 | llasram | H4ns: nrepl.el is the current standard |
| 06:29 | gavri | and I'd like to start from 1/1 |
| 06:29 | H4ns | llasram: thanks |
| 06:29 | gavri | and then move to 1/2, 1/3 etc |
| 06:30 | gavri | it works fine if I start from 1/2 |
| 06:30 | gavri | but I don't know how to start it off from 1/1 |
| 06:30 | llasram | gavri: You probably want to wrap this in your own function, but: ##(clojure.lang.Ratio. (biginteger 1) (biginteger 1)) |
| 06:30 | lazybot | ⇒ 1/1 |
| 06:31 | llasram | Although writing your own wrapper for `numerator` which handles integers is probably ceaner |
| 06:31 | llasram | cleaner even |
| 06:33 | gavri | this breaks too: (numerator (* 2 (rationalize 1.5))) |
| 06:33 | gavri | doesn't this mean that a lot of code would break quite often? |
| 06:34 | gavri | if ratios end up with a denominator of 1 in intermediate results of calculations? |
| 06:34 | gavri | what am I missing here? :-? |
| 06:34 | llasram | I honestly don't think people use ratios very often :-) |
| 06:34 | llasram | It does seem like `numerator` should be identity integers |
| 06:35 | gavri | or not at all, it seems :/ |
| 06:35 | gavri | wouldn't it be better if ratios never reduce to integers unless explicitly cast? |
| 06:35 | gavri | if not, there'll have to be special cases everywhere |
| 06:36 | llasram | Just in the arithmetic functions |
| 06:36 | llasram | Just like `/` on integers results in ratios for non-integral results |
| 06:37 | gavri | that's not as bad though, because ratios have more general capabilities than integers, right? |
| 06:37 | llasram | Well, except that ratios are much, much heavier-weight on the JVM |
| 06:37 | gavri | oh ok, got it |
| 06:38 | gavri | there has to be a way for the programmer to indicate that they want to work exclusively on ratios though |
| 06:38 | gavri | so that clojure isn't enthusiastic about converting them back to integers |
| 06:38 | llasram | You can reach into the Ratio class directly |
| 06:38 | llasram | But I really think the solution is that `numerator` should work on integers |
| 06:38 | gavri | a more general way than changing #numerator, I mean |
| 06:38 | H4ns | i need to write a simple web server that serves statically defined clojure data structures (literals) as json. nrepl.el, http-kit, now i need a json library. any recommendations? it'd be nice if i could generate json in a streaming fashion as i will eventually have to create the json from java instances. |
| 06:38 | llasram | gavri: Why more general? |
| 06:38 | gavri | ok, thanks, llasram |
| 06:39 | gavri | for example, what about denominator? |
| 06:39 | llasram | H4ns: cheshire is th de facto standard |
| 06:39 | H4ns | llasram: thanks again |
| 06:39 | gavri | and any functions that get added for ratios in the future |
| 06:39 | llasram | gavri: Well, ditto it should return `1` on integers :-) |
| 06:42 | llasram | Sure. |
| 06:42 | gavri | hmm, okay, I'm new to clojure and really have no clue about the philosophies (if that's the right word) of the language |
| 06:43 | gavri | for now, I'll add custom numerator/denominator functions |
| 06:52 | gavri | thanks, llasram |
| 07:51 | dark_element | cemerick I am using custom repl connect in cljs with austin. https://www.refheap.com/17381 and Also making sure browser-connected-repl-js uses the same repl https://www.refheap.com/17431 I am doing this to send "Browser connected" status from cljs to server. But repl-print is not working with austin. It did work fine with piggieback. |
| 09:20 | ToBeReplaced | interleave-by, from last night: https://gist.github.com/ToBeReplaced/6193452 |
| 09:20 | ToBeReplaced | also how do you get gist to show syntax? |
| 09:22 | Anderkent | ToBeReplaced: there's a dropdown saying 'language' when you create a gist |
| 09:22 | Anderkent | it also tries to autodetect based on what you type |
| 09:22 | Anderkent | (or maybe only based on file extension) |
| 09:23 | ToBeReplaced | Anderkent: yeah it wasn't taking, had to change file extension. |
| 09:39 | clgv | humm, spotted another asymmetry. why is there no mapv-kv similar to reduce-kv ... |
| 09:40 | hyPiRion | clgv: what is mapv-kv supposed to do? |
| 09:41 | clgv | hyPiRion: same as mapv but with the optimization of reduce-kv not to create intermediate seqs. well, seems it could be built on top of reduce-kv ^^ |
| 09:41 | hyPiRion | ah, alright |
| 09:42 | clgv | probably thats the reason. |
| 09:43 | clgv | (defn mapv-kv [f m] (persistent! (reduce-kv (fn [r k v] (conj! r (f k v))) (transient []) m))) |
| 09:43 | clgv | ah well, a bit typing would be saved ^^ |
| 09:49 | H4ns | so, as a new clojure user, in order to start some experiments with http-kit and chesire, i create a leiningen project? |
| 09:50 | ToBeReplaced | H4ns: sounds good |
| 09:50 | H4ns | ToBeReplaced: thanks for the confirmation :) |
| 10:12 | abp | technomancy: https://leiningen.s3.amazonaws.com/downloads/leiningen-2.3.0-standalone.jar currently gives Access Denied :/ |
| 10:12 | clgv | how can I tell leiningen to aot everything for an uberjar? since the jar is started thousands of times I'd want to omit compiling every time |
| 10:18 | hyPiRion | abp: https://github.com/technomancy/leiningen/issues/1279 has some workarounds for now |
| 10:22 | Anderkent | clgv: doesn't :aot :all work? |
| 10:22 | clgv | Anderkent: only for the namespaces of the project |
| 10:23 | Anderkent | hm, but that should compile everything referenced by the project |
| 10:23 | Anderkent | unless you load libs dynamically, I guess |
| 10:24 | clgv | I get no info about the depency namespaces on stdout... |
| 10:24 | hyPiRion | Anderkent: It would only make sense for uberjars |
| 10:24 | hyPiRion | to compile deps aot, I mean. |
| 10:24 | Anderkent | look at the classes dir - usually compiling a namespace builds class files for anything reachable from that namespace |
| 10:24 | abp | hyPiRion: Thanks! |
| 10:24 | Anderkent | hyPiRion: I know, and it's a problem that you can't non-transitively compile |
| 10:25 | Anderkent | see http://dev.clojure.org/display/design/Transitive+AOT+Compilation |
| 10:26 | clgv | humm interesting. there are a lot of class files in the uberjar in dependency namespaces |
| 10:27 | hyPiRion | clgv: yeah, the dependencies themselves may be compiled aot and bundled in a jar. |
| 10:27 | clojurebot | clojars deployment is described by _ato in http://groups.google.com/group/clojars-maintainers/msg/4c66317ac3ecd9bb |
| 10:27 | clgv | hyPiRion: I just check one dep jar to verify |
| 10:28 | clgv | hyPiRion: ok. the original dep jar has no classes in it |
| 10:28 | clgv | so it seems to work with :aot :all |
| 10:28 | hyPiRion | clgv: oh, dang, I just opened an issue |
| 10:30 | clgv | hyPiRion: well not too bad, since someone with insider knowledge can now confirm that it works like expected... |
| 10:31 | Anderkent | Clearly we should go and laugh at you in the issue description for not trying it first. :P |
| 10:32 | hyPiRion | Anderkent: This is possibly my third time I've posted a feature request where it was a documentation issue :p |
| 10:32 | hyPiRion | I'm a bit trigger happy when it comes to issues. |
| 10:35 | ambrosebs | Bronsa: hows CinC coming? |
| 10:38 | Anderkent | Why doesn't `add-watch` tell you what the current reference state was? There seems to be no way to reliably watch a ref for changes |
| 10:40 | Anderkent | say you know what @ref is, and you want to watch for changes. if you (let [known-state @ref] (add-watch ref :key check-change) (check-change :key ref known-state @ref)) you might call check-change twice for the same change, if you do it in reverse order you might miss changes that happened between check-change and add-watch |
| 11:04 | shiranaihito | i'm trying to make a custom lein template, but when i use it i get an error saying: "IllegalArgumentException: No method in multimethod 'do-copy' for dispatch value: [nil java.io.File]" .. any idea what's going on? (i'm new to clojure) |
| 11:05 | shiranaihito | ( the directory for the new project gets created, along with the first source file ) |
| 11:05 | upwardindex | I'm reading 2 bytes from a RandomAccessFile in 1 call to .read, however the JVM makes two one byte call to linux, any idea how to make it make only 1 call? |
| 11:07 | Anderkent | upwardindex: do you know if jvm is explicitly telling linux to read one byte, or if linux is just returning after reading 1? |
| 11:08 | upwardindex | Anderkent: It is explicitly telling linux to read one byte |
| 11:08 | Anderkent | shiranaihito: it seems you're using clojure.java.io/copy with a wrong set of args.. can you refheap your code? |
| 11:09 | shiranaihito | Anderkent: well.. i'm just trying to follow the instructions here: http://yogthos.net/blog/34-Creating+Leiningen+Templates .. but with not much luck |
| 11:09 | shiranaihito | and as mentioned, i'm new to clojure.. "refheaping" my code, whatever that means, is out of my reach for now :P |
| 11:09 | hyPiRion | ~refheap |
| 11:10 | hyPiRion | aah, clojurebot |
| 11:10 | llasram | Come on, clojurebot -- step up |
| 11:10 | hyPiRion | https://www.refheap.com |
| 11:10 | shiranaihito | :P |
| 11:10 | shiranaihito | ah.. |
| 11:10 | hyPiRion | clojurebot: refheap is<reply>https://www.refheap.com/ |
| 11:10 | shiranaihito | well, there isn't any code outside of what happens in that blog post |
| 11:10 | hyPiRion | Oh, clojurebot has died :( |
| 11:10 | llasram | Or does it just need a space? |
| 11:11 | llasram | clojurebot: ping |
| 11:11 | hyPiRion | ,(+ 1 2) |
| 11:11 | llasram | Oh, dead. |
| 11:11 | hyPiRion | boo |
| 11:11 | shiranaihito | it's probably because of MongoDB.. :p |
| 11:12 | hyPiRion | shiranaihito: I wouldn't be surprised actually :p |
| 11:12 | futile | flu time |
| 11:12 | shiranaihito | :P |
| 11:12 | shiranaihito | hyPiRion: yeah.. i'm convinced Mongo shouldn't be used, at least for now :) |
| 11:12 | Anderkent | shiranaihito: what lein version are you using? |
| 11:12 | llasram | shiranaihito: Even if your code is almost just copy-pasted from that blog post, it can still help to post it |
| 11:12 | shiranaihito | 2.2.0, apparently |
| 11:12 | llasram | Don't be shy! refheap right up! |
| 11:13 | shiranaihito | :p |
| 11:15 | Anderkent | shiranaihito: I'd start with `lein new template my-lein-template` and see if the default thing works. Then try adjusting it to do what you want and see when it breaks |
| 11:15 | shiranaihito | well, i've just been trying to list directories etc that would get created in a fresh project: https://www.refheap.com/b4ea0ef266f47f1ac9adc9b4c |
| 11:15 | hyPiRion | shiranaihito: There are some working ones here: https://github.com/stuartsierra/reloaded/blob/master/src/leiningen/new/reloaded.clj and https://github.com/hyPiRion/pirlib/blob/master/src/leiningen/new/pirlib.clj |
| 11:16 | shiranaihito | ah, i'll take a look at the working ones |
| 11:16 | silasdavis | is there a nicer way to write (map #(% m) [:a :e :c]) |
| 11:16 | silasdavis | where m is a map |
| 11:16 | silasdavis | ? |
| 11:16 | llasram | shiranaihito: I think I see your problem -- I believe your one-element vectors need to be just the bare strings |
| 11:16 | shiranaihito | oh? |
| 11:16 | hyPiRion | shiranaihito: the ["string"] must either be "string" (which will create a directory) or a ["string" (render "string")] |
| 11:17 | hyPiRion | yeah, the ->files function is a bit weird |
| 11:17 | hyPiRion | silasdavis: (map m [:a :e :c]) ? |
| 11:17 | shiranaihito | hyPiRion: well, i have no idea what's going on there :p just copying that blog post :p |
| 11:18 | shiranaihito | what does "->" in front of a func name signify? |
| 11:18 | shiranaihito | hyPiRion: ["string" (render "string")] <-- what would happen here? |
| 11:20 | Anderkent | the -> is just part of the function name |
| 11:20 | shiranaihito | Anderkent: yes but is it a convention to signify something? like python's "__whatever" for something that's private |
| 11:20 | hyPiRion | shiranaihito: actually, it's not that hard to grok. ["string" "file contents"] would create a file named "string" and put "file contents" in it |
| 11:21 | Anderkent | it's usually used to imply threading something through a list of calls or conversion into something |
| 11:21 | shiranaihito | hyPiRion: ok but how would i know that will happen? :) |
| 11:21 | shiranaihito | Anderkent: oh, ok |
| 11:23 | hyPiRion | shiranaihito: (render "string") takes the file "string" and uses the moustache renderer to work with the contents |
| 11:23 | hyPiRion | and it returns the contents of the rendering afterwards |
| 11:24 | hyPiRion | There's a bit more on it here: https://github.com/technomancy/leiningen/blob/master/doc/TEMPLATES.md |
| 11:24 | silasdavis | hyPiRion, who'd have thought a map was a function... yeah thanks I knew there was something wrong with that |
| 11:24 | hyPiRion | But I wish I could've written more, unfortunately time is not what I have the most of in the world. |
| 11:27 | shiranaihito | is mustache considered some kind of standard choice for a templating library for use with clojure? |
| 11:27 | shiranaihito | or is there something "better"? |
| 11:27 | shiranaihito | hm.. i think i already asked about this at some poitn |
| 11:27 | shiranaihito | sakdjds :p |
| 11:28 | yazirian | shiranaihito: ->Foo style fn names are typically constructors |
| 11:28 | yazirian | defrecord automatically generates them |
| 11:28 | hyPiRion | shiranaihito: It's not better or anything, it's just what the leiningen template system uses. |
| 11:28 | shiranaihito | yazirian: constructors? as in, for classes? |
| 11:28 | yazirian | i.e. (defrecord Foo [bar]) will cause (->Foo "baz") to work automagically |
| 11:28 | yazirian | that's the convention |
| 11:29 | llasram | But to be clear, that's not what `->files` is here |
| 11:29 | yazirian | a defrecord? no. a constructor? yes |
| 11:29 | llasram | Errr |
| 11:29 | yazirian | i.e. from the docstring "Generate a file with content." |
| 11:29 | llasram | It instantiates files on disk. It doesn't create file objects. I can see whare you're going, but it's kind of a stretch |
| 11:30 | shiranaihito | llasram: you were right btw, thanks! :p |
| 11:30 | llasram | See -- always share the code :-) |
| 11:30 | shiranaihito | :P |
| 11:30 | shiranaihito | yeah |
| 11:31 | silasdavis | shiranaihito, I like laser |
| 11:32 | silasdavis | https://github.com/Raynes/laser |
| 11:32 | shiranaihito | silasdavis: ah yes, i believe i heard of that last time |
| 11:32 | Anderkent | upwardindex: after some investigations, http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/fdd0d43ba0f9/src/share/native/java/io/io_util.c is where the magic happens I think. Can't find where IO_Read is coming from, but it doesn't seem like there's any flag you could set to make it request the 2 bytes |
| 11:34 | llasram | Anderkent: But it looks like the readBytes() function will try to read up to `len` bytes at a time |
| 11:35 | Anderkent | yes, but he said he asks for 2 bytes there. |
| 11:35 | llasram | Right? |
| 11:35 | Anderkent | and was investigating why it ends up being two system calls each asking for 1 bytes |
| 11:35 | Anderkent | *byte |
| 11:35 | Anderkent | (which I assume he knows from strace) |
| 11:37 | upwardindex | Well simpler than that I just printk in my character device :) |
| 11:38 | Anderkent | ah, then it might be the OS that's asking for 1 byte from you, not java asking linux for 1 byte? |
| 11:40 | upwardindex | I'm not aware of any layer that would make that kind of decision, what are you referring to as "the OS"? |
| 11:40 | Anderkent | well, I don't know much about how linux implements `read`. It's not unimaginable to me that it doesnt do block reads from character devices ... |
| 11:41 | Anderkent | in fact isnt the point of a character device that it only returns a byte at a time? |
| 11:41 | nDuff | Anderkent: those details are below the syscall layer. |
| 11:41 | Anderkent | where does printk sit? |
| 11:41 | Anderkent | I thought it was in the driver |
| 11:41 | nDuff | Ahh. |
| 11:42 | nDuff | I wasn't following very closely. |
| 11:42 | Anderkent | so did I initially, but then he says printk in his char device |
| 11:43 | rasmusto | an aside: early_printk rules |
| 11:46 | upwardindex | Maybe SeekableByteChannel.read is the culprit here |
| 11:47 | Anderkent | well, all the java bits should be very easy to debug |
| 11:47 | Anderkent | and you can see what the syscall arguments are with dtrace (or strace if you must) |
| 11:48 | Anderkent | that should tell you where to look for the issue |
| 11:49 | upwardindex | Anderkent: the java bits are easy to debug when you know java ;) anyways, I'll use a workaround for now I don't have the bandwidth, taking notes of all your pointers in the issue, thanks a lot for your help |
| 11:49 | Anderkent | you should be able to just attach eclipse or whatever to your process, put a breakpoint in the random access file and watch the arguments |
| 11:50 | Anderkent | oh well, good luck :) |
| 11:51 | silasdavis | what's the most elegant way to move from a 'maybe nil or [x,y,z]' to a '[] or [x,y,z]'? |
| 11:52 | silasdavis | i.e. convert nil to empty list, but otherwise keep list |
| 11:52 | Anderkent | list or vector? |
| 11:52 | TimMc | or |
| 11:52 | Anderkent | nil is an empty list |
| 11:52 | llasram | silasdavis: Most functions slet you treat `nil` as an empty sequence. Why do you find you need to? |
| 11:52 | llasram | Anderkent: Well, not quite: ##(= nil ()) |
| 11:52 | lazybot | ⇒ false |
| 11:52 | Anderkent | that just means = is broken :) |
| 11:53 | TimMc | silasdavis: (or foo []) |
| 11:53 | upwardindex | silasdavis: (or mystuff []) |
| 11:53 | llasram | Anderkent: Why do you say that? |
| 11:53 | TimMc | No, the seq abstraction is broken. |
| 11:54 | Anderkent | i'm half kidding, I find nil punning very annoying most of the time. But it seems it's here to stay, so let's pretend it's consistent |
| 11:54 | TimMc | () should always be the empty seq; nil-punning is cute but problematic. |
| 11:54 | abp | always sequing for nil |
| 11:55 | Anderkent | ##(seq? (seq nil)) |
| 11:55 | lazybot | ⇒ false |
| 11:55 | Anderkent | #thiscljlife |
| 11:55 | silasdavis | I sort of want a cons or a conj that will treat nil as an empty sequence |
| 11:56 | Anderkent | huh? |
| 11:56 | Anderkent | ##(cons 1 nil) |
| 11:56 | lazybot | ⇒ (1) |
| 11:56 | Anderkent | oh you mean you want to keep it |
| 11:57 | silasdavis | ##(cons nil [3]) |
| 11:57 | lazybot | ⇒ (nil 3) |
| 11:57 | silasdavis | ##(cons [3] nil) |
| 11:57 | lazybot | ⇒ ([3]) |
| 11:57 | Anderkent | well cons takes the thing to add first and the sequence second, that all seems reasonable to me |
| 11:58 | silasdavis | so I need the former to give me (3) |
| 11:58 | Anderkent | huh? |
| 11:58 | Anderkent | cons is not concat :P |
| 11:58 | silasdavis | ##(conj [] [3]) |
| 11:58 | lazybot | ⇒ [[3]] |
| 11:58 | silasdavis | ##(concat [] [3]) |
| 11:58 | lazybot | ⇒ (3) |
| 11:58 | silasdavis | ##(concat nil [3]) |
| 11:58 | lazybot | ⇒ (3) |
| 11:58 | silasdavis | Anderkent, concat.. thanks |
| 12:04 | silasdavis | Is there a nice way to move from a 'maybe x or [x]' to '[x]'? |
| 12:05 | silasdavis | i.e. treat a single element as a singleton.. |
| 12:06 | silasdavis | in ruby you might do something like [val].flatten |
| 12:07 | Anderkent | uh, it's doable but I wouldn't recommend it. Leads to really weird behaviour when someone passes a list as x for example |
| 12:07 | silasdavis | but that is less acceptable here |
| 12:07 | silasdavis | yes |
| 12:08 | Anderkent | better have a separate function that only takes a single arg and wraps it in a list then calls the main function that always takes a list |
| 12:08 | Anderkent | then your api is cleaner |
| 12:09 | silasdavis | so nothing better than #(if (coll? %) % [%]) |
| 12:10 | Anderkent | Not sure if coll? is the right predicate there |
| 12:11 | silasdavis | hm no it's not, because it's true for a map |
| 12:11 | silasdavis | what can I use that will get all list types... |
| 12:12 | Anderkent | you'll have a problem with strings too |
| 12:12 | mattmoss | seq? or sequential? |
| 12:13 | Anderkent | sequential? does it I guess ... But I still think it's a bad idea :) |
| 12:13 | mattmoss | ##(seq {:a 1 :b 2}) |
| 12:13 | lazybot | ⇒ ([:a 1] [:b 2]) |
| 12:13 | silasdavis | that looks like it's about right |
| 12:13 | silasdavis | Anderkent, why? |
| 12:14 | Anderkent | (defn do-foos [foos] ...) (defn do-foo [foo] (do-foos [foo])) is just much cleaner |
| 12:14 | Anderkent | as I said |
| 12:14 | Anderkent | invariably leads to confusion |
| 12:14 | Anderkent | like -> does it |
| 12:14 | silasdavis | you might be right |
| 12:14 | Anderkent | and it always sucks |
| 12:14 | silasdavis | -> ? |
| 12:15 | Anderkent | the threading macro ->. At least for it the allowed syntax is very restricted and the automagic list wrapping only happens for a single symbol... But still a pain and common source of confusion |
| 12:16 | mattmoss | ##(seq nil) |
| 12:16 | lazybot | ⇒ nil |
| 12:16 | mattmoss | nope |
| 12:16 | rasmusto | and -> leads to ->> leads to -<>-> or w/e |
| 12:20 | silasdavis | where does the confusion come from? |
| 12:21 | justin_smith | (-> foo bar) is the same as (-> foo (bar)) |
| 12:21 | Anderkent | but different from (-> foo ((bar))) :P |
| 12:21 | justin_smith | but (-> foo ((bar))) is a different thing altogether |
| 12:21 | justin_smith | jynx |
| 12:21 | Anderkent | ninja |
| 12:21 | justin_smith | and they you have to do things like (-> foo (#(bar nil %))) |
| 12:22 | justin_smith | just to change argument ordering |
| 12:22 | justin_smith | and the extra paren wrapping is odd |
| 12:22 | justin_smith | since #(bar nil %) is not necceessarily returning a function of no args, and that returned value is not being called |
| 12:22 | justin_smith | inconsistent |
| 12:24 | gfredericks | (as-> x <> ...) |
| 12:25 | Anderkent | (<<- ...) is amazing too |
| 12:27 | silasdavis | so would you completely avoid them? |
| 12:30 | Anderkent | When designing a function I'd avoid taking a 'list-or-single-element', instead offer two functions one taking a list and the other taking a single element |
| 12:31 | Anderkent | the caller will always know which one it wants to call anyway |
| 12:33 | TimMc | duck-wrapping |
| 12:43 | Anderkent | if it doesn't quack, wrap it in a duck? Gross imagery. |
| 12:44 | Raynes | Anderkent: lol |
| 12:45 | Chousuke | there's usually no reason to even provide the 1-item function unless it's the 90% use case or something :P |
| 12:45 | Anderkent | indeed. And even then, if it's only one sequence, consider varargs |
| 12:46 | Anderkent | hm actually that might not work for longer sequences, nvm that |
| 12:46 | Chousuke | at least in a language where the difference between a sequence and a single element is two characters. |
| 12:51 | silasdavis | yeah I've ditched the single item thing |
| 12:52 | silasdavis | whats the best way to go from [x y z] to {x (f x) y (f y) z (f z)}? |
| 12:53 | Raynes | (into {} (for [[k v] a-map] [k (f v)])) |
| 12:53 | Anderkent | what |
| 12:53 | Anderkent | no |
| 12:53 | Raynes | Oh, that was unrelated. |
| 12:53 | Raynes | Sorry. |
| 12:53 | Anderkent | (into {} (map (juxt identity f) my-vector)) |
| 12:53 | Raynes | You're a bad person. |
| 12:53 | Anderkent | xP |
| 12:53 | Anderkent | sorry, that came out harsher than I intended |
| 12:54 | justin_smith | for extra win, (def identity id) |
| 12:54 | Raynes | (mapcat (juxt identity f) l) |
| 12:54 | Raynes | silasdavis: ^ |
| 12:55 | justin_smith | Raynes: I think the into {} version was actually right |
| 12:55 | Raynes | You didn't seem to want a map. |
| 12:56 | Raynes | If so, then indeed. |
| 12:56 | Anderkent | (into {} ) always looks strange to me |
| 12:56 | Anderkent | there should be an easier way of converting a maplike seq back into a map |
| 12:59 | justin_smith | (def as-hash (partial into {})) |
| 12:59 | silasdavis | thanks |
| 13:00 | silasdavis | why do functions in clojure core tend to get defined for 0, 1, 2, 3 arguments before being defined for arbirtrary args? |
| 13:00 | silasdavis | (such as juxt) |
| 13:00 | justin_smith | I would hazard a guess it is for performance reasons |
| 13:01 | Raynes | It is. |
| 13:01 | hyPiRion | yup, most likely perf reasons |
| 13:01 | silasdavis | I assumed that must be the case |
| 13:01 | silasdavis | do you understand why? |
| 13:01 | Raynes | It is definitely performance reasons, for I know this for a fact. |
| 13:03 | Anderkent | silasdavis: I'd guess if the compiler can count the arg number and find the right implementation statically it saves a layer of indirection on runtime |
| 13:03 | Raynes | In a lot of cases it's faster to take and work with a specific argument count than to seq them up and then unroll them, etc. |
| 13:03 | justin_smith | is it about avoiding the overhead of implicitly creating the sequence for the varargs, only to immediately destructure them? |
| 13:03 | justin_smith | answered my question just before I asked it, thanks |
| 13:03 | Anderkent | yeah that sounds reasonable too |
| 13:04 | justin_smith | technically creating a seq and then destructuring it is a layer of indirection over the arguments, so you were on the right track |
| 13:05 | silasdavis | Anderkent, your first reason is a bit circular; the only reason there are multiple implmentations is give essentially identical implementations of lower arity |
| 13:06 | silasdavis | or do you mean the functions are possibly called from that have meaningfully different implementations |
| 13:07 | silasdavis | anyway the seq thing makes sense |
| 13:07 | Anderkent | silasdavis: for functions where the low arity version does not call the high arity version I was guessing that calling a 2-arg function is cheaper than calling a var-arg function |
| 13:08 | Anderkent | does that address your point or am i misunderstanding/ |
| 13:09 | Anderkent | afaik calling a vararg funciton is done by a wrapper that basically does (switch (count args) (case 1 (call-arity args[0])) (case 2 (call-2-arity arg[0] arg[1])) etc. |
| 13:09 | Anderkent | which is why there's a max count to varargs |
| 13:10 | squidz | cemerick: I am using your nice austin library and wondering how you normally restart your jetty server while developing. May be more of a compojure question. |
| 13:10 | cemerick | squidz: I don't |
| 13:10 | cemerick | Why do you need to restart jetty? |
| 13:10 | justin_smith | Anderkent: I thought it created a seq, which is why kargs work with varargs |
| 13:11 | squidz | because I am making changes to my static resource and need it to be reloaded which it seems not to be doing |
| 13:11 | squidz | my index.html |
| 13:11 | justin_smith | you just reload the resource |
| 13:11 | Anderkent | justin_smith: yeah you're right, it's a switch on the count of a seq then ifn.invoke(arglist.first(), arglist.next().first ...) |
| 13:11 | justin_smith | no need to restart the server |
| 13:11 | Raynes | cemerick: http://cdn.memegenerator.co/instances/600x/40437985.jpg |
| 13:11 | Anderkent | and of course I ment max arity of function, not max count of varargs |
| 13:12 | squidz | so how do I reload it then? |
| 13:12 | Anderkent | wait, (merge a-map b-map) is the same as (conj a-map b-map) |
| 13:12 | Anderkent | how come? |
| 13:12 | justin_smith | squidz: use a middleware that notices when a resource changes, or at dev time you can just uconditionally load from disk it on every request |
| 13:12 | Anderkent | weird. |
| 13:13 | cemerick | squidz: what route do you have for serving your static resources? |
| 13:13 | cemerick | Raynes: s/always/ever need to/g |
| 13:14 | squidz | cemerick: here is what it looks like. Very simple https://www.refheap.com/17437 |
| 13:14 | cemerick | squidz: yeah, that should never be a problem. Maybe your browser is caching? Shift-reload? |
| 13:14 | xeqi | squidz: is page the same as in the sample app? |
| 13:14 | squidz | where page was the enlive template that you provided in your documentation |
| 13:15 | cemerick | squidz: oh, there you go; you need to load the clojure namespace where the template is loaded by enlive |
| 13:16 | xeqi | I switched mine to laser to avoid the template caching |
| 13:16 | squidz | after reavaling the whole core.clj with the enlive template inclueded, it should work |
| 13:17 | squidz | but it doesnt |
| 13:18 | squidz | here is the whole core.clj https://www.refheap.com/17438 |
| 13:22 | squidz | okay nvm I had several nrepl sessions open and I was eval'ing in the wrong session |
| 13:23 | cemerick | squidz: :-D sorry, man |
| 13:23 | squidz | yeah sorry for the silly question thanks anyways for the help |
| 13:24 | tieTYT | can you guys help me with something? I couldn't figure out how to implement step 4 of this answer in a functional way. How would you do that? http://gamedev.stackexchange.com/a/6045/31177 |
| 13:25 | tieTYT | it's a simple for loop that goes: R = (some random int); T = 0; for o in os (T = T + o.w; if T > R then return o) |
| 13:25 | Anderkent | well, you can do it with (loop) obviosuly, but that's not very nice |
| 13:25 | tieTYT | right I wanted to know how to implement this functionally |
| 13:25 | tieTYT | using map and reduce, etc. |
| 13:26 | justin_smith | for that sort of short circuiting, you could use iterate and drop-while the end condition is not met, then take the element that meets the condition |
| 13:27 | Anderkent | justin_smith: the problem is that the condition is modified in every loop iteration |
| 13:27 | justin_smith | then you make iterate return the variables which create the condition |
| 13:27 | Anderkent | right |
| 13:27 | Anderkent | yeah that makes sense |
| 13:28 | tieTYT | but won't drop while give me the number? I'm trying to get the object |
| 13:28 | justin_smith | ((comp :answer first) (drop-while (comp not :done) (iterate (fn []) {:done false :conditions [] :answer nil}))) |
| 13:28 | justin_smith | something like that |
| 13:29 | justin_smith | basically everything that would be a variable in the mutable version is a key in a map passed through iterate |
| 13:29 | Anderkent | yeah but that's not very nice either |
| 13:29 | justin_smith | but it is functional |
| 13:30 | tieTYT | sounds like that algorithm is tough to do in fp |
| 13:31 | justin_smith | nah, not hard, just ugly |
| 13:31 | Anderkent | well that particular algorithm is very iterative |
| 13:31 | Anderkent | I'm trying to think of a prettier one that would do the same |
| 13:31 | justin_smith | isn't there a form of reduce that can just short circuit at some step? |
| 13:32 | hiredman | iterate + take-while |
| 13:33 | ToBeReplaced | is there anything I should know about using Thread/sleep inside of clojure.test? |
| 13:33 | tieTYT | see the problem I think with reduce is |
| 13:33 | hiredman | justin_smith: reduce can short circuit, it is new feature |
| 13:33 | justin_smith | ahh, that is the clean way to do it then, if you can use the new clojure |
| 13:33 | justin_smith | where are the docs on that? |
| 13:34 | tieTYT | actually nm, I don't know. Where I got stuck is, "this is easy to figure out when to stop using a reduce, but I want to return the o type and the memo would need to be an int before that. I must be doing something wrong" |
| 13:34 | tieTYT | i'm not sure if that thought process was clear |
| 13:36 | tieTYT | anyway I'm really using JS and underscore.js to write this code. underscore doesn't have an iterate |
| 13:36 | tieTYT | so I just did it iteratively :T |
| 13:41 | noonian | its easy to implement recursively :P |
| 13:42 | xeqi | ,*clojure-version* |
| 13:42 | xeqi | clojurebot: are you broken? |
| 13:44 | xeqi | &*clojure-version* |
| 13:44 | lazybot | ⇒ {:major 1, :minor 4, :incremental 0, :qualifier nil} |
| 13:45 | tieTYT | noonian: can you show me? |
| 13:45 | xeqi | surprised hes still on 1.4 |
| 13:46 | justin_smith | xeqi - I think it is intentional that clojurebot and lazybot are the two most recent versions |
| 13:46 | xeqi | tieTYT: (let [r 7] (reduce (fn [t [i w]] (let [t (+ t w)] (if (< r t) (reduced i) t))) 0 [[0 1] [1 2] [2 3] [3 4] [5 6]])) will work in 1.5 |
| 13:47 | justin_smith | ahh, that is how to get the short curcuit |
| 13:47 | xeqi | justin_smith: ^ (doc reduced) is all I can find about the "short circuit" |
| 13:47 | justin_smith | I tried to google and found nothing |
| 13:47 | justin_smith | yeah, but how was I to know reduced was the thing to look for? |
| 13:47 | tieTYT | cool I'll have to check that out |
| 13:47 | tieTYT | why DO you need to short circuit? Couldn't you just leave the memo as it is for the rest of the reduce? |
| 13:48 | xeqi | unfortuantly.. wait for the irc collective? |
| 13:48 | justin_smith | seems silly |
| 13:48 | justin_smith | that is, reducing on the rest of the collection when you already have the asnwer seems silly |
| 13:48 | justin_smith | also, what if you wanted to reduce on an infinite lazy list? |
| 13:49 | tieTYT | fair points |
| 13:49 | xeqi | tieTYT: the memo is t until the condition, then switches to i. The rest of the computation needs to know not to treat it as t then |
| 13:49 | xeqi | which can be done by using memo of [t i] or a map or such |
| 13:49 | tieTYT | ok yeah. See that wouldn't conceptually be an option in haskell then |
| 13:49 | tieTYT | you couldn't even consider this as an approach, right? |
| 13:50 | tieTYT | sorry, brb |
| 13:50 | noonian | tieTYT: in JS? or clojure? |
| 13:51 | noonian | ,(doc reduced) |
| 13:51 | clojurebot | "([x]); Wraps x in a way such that a reduce will terminate with the value x" |
| 13:51 | noonian | huh, thats seems very useful |
| 14:04 | mdrogalis | Hey sritchie. :) |
| 14:04 | sritchie | yo |
| 14:22 | tieTYT | noonian: either. I could probably understand the JS better though |
| 14:29 | callen | why does ritz only support breakpoints for slime? |
| 14:31 | mthvedt | is it safe to write code that relies on the #= reader macro |
| 14:31 | nifff | hello room:) ,how slower are immutable data stractures?i made a program that has a lot of large vector and maps changes and its slow,maybe its my implementation or it is because of immutable data structures? |
| 14:32 | nifff | i love clojure,just worrying if its slow... |
| 14:32 | noonian | tieTYT: here's a recursive version, it uses underscore and is untested |
| 14:32 | noonian | tieTYT: http://pastebin.com/k0wxW3Ja |
| 14:32 | TimMc | mthvedt: Safe as in security or safe as in future-proof-ness? |
| 14:33 | noonian | nifff: are you sure its not just slow to startup because of the jvm startup time? they should be pretty efficient in general |
| 14:33 | TimMc | mthvedt: And is it your code, or data you are reading? |
| 14:33 | mthvedt | TimMc: future-proof-ness |
| 14:34 | noonian | tieTYT: oops, I had 0.w in there instead of o.w but you get the gist |
| 14:37 | nifff | i am thinking that maybe the garbage collector make my program slower,because i use heavy data stractures |
| 14:37 | gfredericks2 | dericks |
| 14:37 | noonian | nifff: is it still slow if you call your function from the repl? |
| 14:38 | nifff | yes i use the repl, |
| 14:38 | nifff | the similar program in javascript its 10x fastewr |
| 14:38 | noonian | what does the #= reader macro do? |
| 14:38 | noonian | ,#=(println "test") |
| 14:38 | clojurebot | #<RuntimeException java.lang.RuntimeException: EvalReader not allowed when *read-eval* is false.> |
| 14:38 | noonian | ,#=17 |
| 14:38 | clojurebot | #<RuntimeException java.lang.RuntimeException: EvalReader not allowed when *read-eval* is false.> |
| 14:38 | gfredericks | noonian: it evals the contents at read-time |
| 14:39 | noonian | gfredericks: ah, thanks |
| 14:41 | tieTYT | noonian: ah ok, I like that. Thanks |
| 14:41 | tieTYT | noonian: you might want to answer that here: http://stackoverflow.com/questions/18152343/how-can-this-imperative-code-be-rewritten-to-be-more-functional |
| 14:41 | noonian | tieTYT: no problem, be careful if you have a lot of objects though because you could potentially blow out the stack |
| 14:41 | nifff | does anyone know how much slower are persistent data structures?my programa is 8x slower than a javascript one,can this caused by the data structures being immutable? |
| 14:42 | noonian | nifff: can you post a code example of what you are doing thats slow? |
| 14:42 | nifff | i use large vectors and hash maps,and i assoc values |
| 14:42 | nifff | all the time |
| 14:43 | dnolen | nifff: it just depends, you may be able to use transients in hot spots. Still if performance is critical, you can write CLJS so that it maps directly to the JS you would write. |
| 14:46 | dnolen | nifff: if you want specific performance advice you will probably need to paste your code somewhere |
| 14:53 | [1]nifff | - |
| 14:56 | nifff | https://www.refheap.com/17443 |
| 14:56 | nifff | if anyone have a llok |
| 14:59 | dnolen | nifff: oh oops, I thought this was CLJS, but not matter, that's pretty unidiomatic looking code. |
| 14:59 | dnolen | s/not matter/no matter |
| 15:00 | dnolen | nifff: atoms won't make it any faster, paste your version sans atoms |
| 15:00 | callen | dnolen: you can write Fortran in any language. |
| 15:01 | dnolen | nifff: also are you using leiningen? |
| 15:01 | nifff | yes i use counterclockwise |
| 15:02 | dnolen | nifff: you may need to set explicit server settings in your project.clj since Lein uses bad defaults |
| 15:02 | dnolen | or used to (not sure about 2.3.0) |
| 15:02 | xeqi | for some value of "bad" |
| 15:02 | dnolen | xeqi: bad for benchmarking |
| 15:02 | dnolen | xeqi: or profiling |
| 15:03 | nifff | https://www.refheap.com/17444 |
| 15:03 | dnolen | nifff: that code also looks like it needs work :) |
| 15:04 | nifff | its a freak :) |
| 15:04 | technomancy | .| |
| 15:04 | dnolen | nifff: make sure JVM -server settings is enabled |
| 15:04 | nifff | how to change this? |
| 15:04 | technomancy | dnolen: -server is actually impossible to turn off these days |
| 15:04 | technomancy | unless you're running a 32-bit JVM |
| 15:04 | dnolen | technomancy: not on OS X |
| 15:05 | technomancy | wow, they still haven't made the jump yet? |
| 15:06 | nifff | the question i have is it the persistent data or my code?how slower are persistent data? 2x 4x 8x :) |
| 15:06 | dnolen | technomancy: all I know is that I need to enable -server explicitly in Lein now |
| 15:07 | dnolen | nifff: there's too much code to tell, but different data structures have different profiles - you can benchmark different cases yourself :) |
| 15:07 | noonian | nifff: I would guess it's the code, but I can't really read the code so I'm not sure |
| 15:07 | nifff | thanks people for trying,when you have a large data structure with a lot of assocs what you use? |
| 15:08 | nifff | i used vectors and maps |
| 15:08 | noonian | well, you can use a single assoc to put multiple keys in at the same time |
| 15:08 | noonian | I'm not sure what you mean lots of assocs |
| 15:08 | dnolen | nifff: vectors and maps, but it looks like you're trying to do Binary Decisions Diagrams with persistent data structures? |
| 15:09 | nifff | yes thats i am doing binary decision diagrams |
| 15:09 | nifff | i made the program its ready but slow |
| 15:09 | TimMc | mthvedt: I think #= will probably stick around for a while, but I'd bet it is undocumented so that people won't use it... |
| 15:09 | dnolen | nifff: I don't really the benefit of immutable data here when speed is the goal usually with BDDs |
| 15:10 | nifff | what data structure to use? |
| 15:10 | dnolen | nifff: I'm assuming you're using arrays in Java? |
| 15:10 | dnolen | nifff: use them in Clojure |
| 15:11 | nifff | ok i will use java arrays,and i will compare the perfomance,thanks |
| 15:11 | nifff | bye room:) |
| 15:11 | dnolen | nifff: make sure to use (set! *warn-on-reflection* true) |
| 15:11 | dnolen | nifff: w/ arrays you have to be careful w/ type hinting |
| 15:11 | nifff | ok but i dont know what that means :) |
| 15:12 | nifff | i will read java interop first |
| 15:12 | dnolen | nifff: bingo :) |
| 15:21 | jcromartie | Is Aleph (still) the best way to write a simple TCP server in Clojure? |
| 15:21 | jcromartie | I feel like it's gotta be |
| 15:22 | ztellman | arguably just using java sockets could be simpler, for some definition of simple |
| 15:22 | ztellman | but aleph is more idiomatic |
| 15:23 | futile_ | pst ztellman what OS you on |
| 15:23 | ztellman | os x |
| 15:23 | futile_ | ztellman: use any window manager? |
| 15:23 | ztellman | nope |
| 15:23 | futile_ | oh wait this is off topic |
| 15:24 | technomancy | jcromartie: there's no one right answer; it depends on the shape of your problem. |
| 15:24 | jcromartie | technomancy: I know you've got a lib |
| 15:25 | futile_ | anyone used Instaparse? |
| 15:25 | technomancy | not really |
| 15:26 | technomancy | jcromartie: if you're mostly just shuffling bytes around you'd be better served with Aleph. if your connections end up doing substantial work on the same node, (so that each node can't service more than a couple thousand connections at a time) use raw sockets. |
| 15:27 | technomancy | s/just //; didn't mean to trivialize it |
| 15:27 | ToBeReplaced | jcromartie: i use (cl)jzmq for persistent tcp |
| 15:27 | ztellman | feeling very trivialized over here :) |
| 15:27 | clojurebot | No entiendo |
| 15:27 | jcromartie | ztellman vs technomancy: FIGHT |
| 15:27 | TimMc | clojurebot: You *wouldn't* entiendo. |
| 15:27 | clojurebot | I don't understand. |
| 15:28 | technomancy | jcromartie: honestly if you need it to be fast you should just use node.js, duh |
| 15:28 | callen | apparently my entire career has been just shuffling bytes around |
| 15:28 | callen | TIL |
| 15:28 | TimMc | "Chris Allen: Electron pusher" |
| 15:28 | technomancy | http://p.hagelb.org/async.jpg |
| 15:28 | jcromartie | technomancy: I don't need web scale or big data |
| 15:28 | TimMc | That's your business card right there. |
| 15:28 | jcromartie | :| |
| 15:28 | jcromartie | :P |
| 15:30 | technomancy | jcromartie: I spun the server-socket lib out of old monolithic-contrib but don't really have any intention of using or maintaining it |
| 15:30 | jcromartie | yeah |
| 15:30 | technomancy | should probably mention that in the readme |
| 15:30 | jcromartie | I see that. It's just there, which is fine. I'm glad it's that simple. |
| 15:31 | jcromartie | but let's say you wanted to write a MUD |
| 15:31 | jcromartie | (I'm trying it right now, with Aleph) |
| 15:32 | technomancy | an excellent! ideahttps://github.com/technomancy/mire |
| 15:32 | jcromartie | everybody loves MUDs |
| 15:32 | technomancy | err--an excellent idea |
| 15:45 | jcromartie | ztellman: so do you see Lamina being built on core.async in the future, or do you see core.async taking the place of Lamina in projects like Aleph |
| 15:45 | jcromartie | ztellman: also, are you completely sick of this question yet? |
| 15:45 | ztellman | jcromartie: I see Aleph being equal-opportunity w.r.t. stream representation |
| 15:47 | ztellman | probably by default the channels will be core.async, since that's where the momentum seems to be, but Lamina and core.async are different enough in their goals/implementations that they can coexist |
| 15:50 | ToBeReplaced | ztellman: how are their goals different? |
| 15:51 | ztellman | ToBeReplaced: see the comments at the bottom of http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html |
| 15:51 | ToBeReplaced | thanks |
| 15:53 | ztellman | it may turn out that Lamina's unique qualities only matter to me and a few other people, but they help with my day-to-day job, so I think I'll keep it around for a bit longer |
| 15:55 | ToBeReplaced | i haven't had the pleasure to work with Lamina yet -- i do have the need to treat queues as streams often though |
| 15:56 | ztellman | ToBeReplaced: I find it to be a nice way to think about/process streams of data |
| 15:56 | ztellman | but it's kind of a sprawling mess of functionality right now |
| 15:57 | ztellman | I'm in the process of trying to extract functionality that doesn't need to be coupled to its particular stream representation |
| 15:57 | ztellman | see https://github.com/ztellman/narrator among others |
| 15:58 | ToBeReplaced | interesting; i'm interested in the stream operators over channels for times where blocking is acceptable |
| 15:59 | ToBeReplaced | map* etc. over channels being populated elsewhere -- that sort of thing is really clunky over BlockingQueues |
| 16:00 | ztellman | yeah, also bifurcation of queues |
| 16:05 | pbostrom | +1 to lamina, nice library, even if it was crappy, the viz stuff would make up for any short comings |
| 16:06 | ztellman | pbostrom: thanks, the viz stuff is in its own library too, now :) |
| 16:06 | ToBeReplaced | splitting a lazy-seq is weird too though |
| 16:07 | ztellman | ToBeReplaced: splitting a lazy-seq is risky, the consumers may go at different rates and cause a memory leak as a result |
| 16:07 | ztellman | you want the consumers to be coupled |
| 16:07 | ztellman | or at least aware of each other |
| 16:08 | ToBeReplaced | you have related problems splitting off of queues though if one queue gets filled up |
| 16:09 | ToBeReplaced | i think splitting is necessarily hard -- no matter how you do it you need to deal with the different consumers |
| 16:12 | ztellman | ToBeReplaced: that's because the topology of the queues is implicit; there's no way to know when a given message has cleared your dataflow |
| 16:12 | ToBeReplaced | i take it back -- you can at least handle a memory leak b/c you can block at the site of the split and prevent A from getting any more action until B does its job |
| 16:13 | ztellman | yes, though that has the TCP bufferbloat issue of waiting for all the queues to fill up before you get any backpressure |
| 16:13 | ToBeReplaced | yeah, generates thunder hard and fast |
| 16:14 | ztellman | an interesting property in Lamina is that if a message lands in a queue, it returns a promise representing the consumption of the message |
| 16:15 | ztellman | if it travels through multiple queues, it yields a promise that yields a promise that yields... |
| 16:15 | ztellman | but this allows you to actually know when a message has actually cleared the topology, including actually clearing the TCP write buffer, etc. |
| 16:16 | ztellman | so you know exactly how much is in flight at any given time |
| 16:19 | ToBeReplaced | when would you travel through multiple queues without coming off? i would have assumed that coming off would cause the promise to yield |
| 16:20 | ToBeReplaced | trying to understand how that's different from asking a queue "hey what's your size, and how many you got?" |
| 16:22 | ztellman | ToBeReplaced: when you have multiple queues pipelined together |
| 16:22 | ztellman | which happens reasonably often, when it's easy to compose operators together |
| 16:22 | ztellman | so there's a difference between clearing the queue(s) closest to you, and clearing the entire topology |
| 16:23 | ztellman | to be fair, this may not be significantly better than just using blocking queue semantics |
| 16:23 | ztellman | but it's an interesting space to experiment in |
| 16:23 | ToBeReplaced | ah, so it's the operators responsibility to relay the messages back? |
| 16:24 | ztellman | kinda, it's mostly implicit |
| 16:24 | ztellman | all channels have queues, which are bypassed if there's something downstream |
| 16:25 | ztellman | if you're doing something clever like batching or flattening streams messages, you need to correctly handle the return values you get from propagating them downstream, but the provided operators do that for you |
| 16:26 | ToBeReplaced | okay |
| 16:37 | qed | I want to make a function that is called like: (foobar :a 1 :b 2) -- how do people typically write the definition so the args can be treated like a map? |
| 16:38 | llasram | qed: ##((fn [& {:as args}] args) :a 1 :b 2) |
| 16:38 | lazybot | ⇒ {:a 1, :b 2} |
| 16:38 | qed | thanks llasram |
| 16:49 | upwardindex | Is there any other way to write foo/bar ? |
| 16:50 | upwardindex | I mean (foo/bar) |
| 16:50 | TimMc | qed: You don't. |
| 16:50 | TimMc | It's really irritating to call such functions, especially if you want to apply args to them. |
| 16:51 | TimMc | Instead, what you want is (fn [foo bar & [{:keys [a b]}] ...), which is called with an optional final map argument. |
| 16:52 | llasram | upwardindex: In what sense? |
| 16:53 | upwardindex | llasram: trying to do something like this https://www.refheap.com/17447 |
| 16:54 | upwardindex | but ~module/initialize is trying to ~ "module/initialize" instead of only "module" |
| 16:54 | llasram | upwardindex: Huh. Well, you can do `~(symbol (name module) "initialize")` |
| 16:55 | llasram | I'm not sure how advisable that is though -- definitely not a common pattern |
| 16:57 | upwardindex | llasram: yes I see, there might be something else i can do if I approach the problem differently |
| 17:03 | upwardindex | How could I make a function that receives a list of namespaces and calls the foo method in each one |
| 17:05 | llasram | upwardindex: Well, exactly the same way as ^^ |
| 17:05 | llasram | It's the idea of having the particular name of a function embedded in a macro which isn't a common idiom |
| 17:06 | noonian | hmm, just going off the docs of in-ns, I might try something like (binding [*ns* namespace] (foo)), but I haven't had a use case for that and not sure how that'd work |
| 17:06 | noonian | ,(doc in-ns) |
| 17:06 | clojurebot | "([name]); Sets *ns* to the namespace named by the symbol, creating it if needed." |
| 17:06 | llasram | upwardindex: Oh, you said a *function* |
| 17:06 | llasram | in-ns won't do what you want, because of how dynamic vars interact with compliation |
| 17:07 | llasram | `resolve` is the thing to look at if you can't be disuaded |
| 17:07 | noonian | yeah, in-ns seems to rebind the var at the top level, but a local binding might work using binding |
| 17:07 | noonian | ,(doc resolve) |
| 17:07 | clojurebot | "([sym] [env sym]); same as (ns-resolve *ns* symbol) or (ns-resolve *ns* &env symbol)" |
| 17:07 | llasram | Oh, `ns-resolve` right |
| 17:07 | noonian | :D there you go |
| 17:08 | upwardindex | noonian: thank you! |
| 17:08 | upwardindex | I guess the cleaner way would be to define an interface? |
| 17:09 | llasram | Or just let users pass in a function to call? |
| 17:09 | noonian | np |
| 17:10 | noonian | yeah, a list of functions (from w/e namespace) instead of a list of namespaces is how I would go about it |
| 17:11 | upwardindex | llasram: I might be over-refactoring it's just that the code is quite redundant |
| 17:11 | upwardindex | I'll medicate on that, thanks guys! |
| 17:12 | llasram | nice |
| 17:13 | ToBeReplaced | in Leiningen, can dev profiles specify environment variables? |
| 17:15 | llasram | ToBeReplaced: If you're referring to https://github.com/weavejester/environ and lein-environ, then yes |
| 17:16 | llasram | Leiningen has no builtin to set arbitrary environment variables via project.clj |
| 17:16 | llasram | s,builtin,built-in way, |
| 17:18 | ToBeReplaced | llasram: what about jvm-opts? i want that "lein test" runs with something, anything, different from "lein run" |
| 17:18 | qed | Can I programatically call methods like: (for [meth '(.fooBar .barBaz)] (meth "ABC"))? |
| 17:18 | ToBeReplaced | preferably lein run != lein repl != lein test |
| 17:19 | llasram | ToBeReplaced: You can set JVM properties via `:jvm-opts`, if that's what you actually need. People use them similarly to environment variables, but they aren't the same thing :-) |
| 17:19 | ToBeReplaced | qed: you'd have to create anon functions aroud them (for [meth [#(.fooBar %) #(.barBaz %)] (meth "ABC")) |
| 17:19 | technomancy | ToBeReplaced: the repl and test tasks both check for profiles named :repl and :test respectively |
| 17:19 | qed | ToBeReplaced: Sounds like a job for a macro |
| 17:20 | ToBeReplaced | jvm-opt would work for me; i don't grok leiningen profiles -- can i specify jvm-opts within a profile, and it'll get merged with the top level jvm-opts? |
| 17:20 | llasram | quackv4: Not really, actually. There's `memfn` from the olden-days, but the #(...) syntax is shorter, more flexible, and allows you to provide type hints |
| 17:20 | qed | i think you meant me llasram |
| 17:21 | llasram | hah! |
| 17:21 | llasram | You are correct |
| 17:21 | technomancy | ToBeReplaced: :jvm-opts from profiles will get appended to :jvm-opts in defproject top-level |
| 17:21 | ToBeReplaced | llasram: technomancy: thanks, sorted |
| 17:21 | technomancy | ToBeReplaced: it won't be "merged" in a key-value sense, but it will be combined |
| 17:21 | ToBeReplaced | right |
| 17:21 | tbaldridge | dnolen: JIRA is giving me problems atm, but that set! async bug is fixed. |
| 17:22 | qed | llasram: you say memfn from the olden days like it's a bad thing |
| 17:22 | dnolen | tbaldridge: excellent! |
| 17:22 | llasram | qed: It's unofficially deprecated. It probably wouldn't have existed if the #(...) had appeared earlier |
| 17:23 | llasram | (is my understanding, anyway) |
| 17:23 | dobry-den | i'm writing simple ring middleware to redirect `/hello` -> `/hello/` but not `/hello.jpg` -> `/hello.jpg/`. Would it be sufficiently robust to just look for a trailing extension to see if i don't need to redirect? |
| 17:23 | technomancy | I like memfn =( |
| 17:23 | technomancy | qed: rich doesn't like it though |
| 17:23 | llasram | I bet you also like kittens! And sunshine! Ugh. What kind of monster are you? |
| 17:23 | technomancy | rawr |
| 17:24 | technomancy | I'm not totally clear why bare .methodCall symbols couldn't be implicitly memfn'd |
| 17:24 | callen | I'm puzzled by memfn when we have nice function literals. |
| 17:24 | bbloom | technomancy: has to do with overload resolution |
| 17:25 | technomancy | bbloom: and probably because you wouldn't want that when it's in the call position |
| 17:25 | llasram | What about #.method as reader syntax for memfn? |
| 17:25 | technomancy | and caring about call position is tacky |
| 17:25 | technomancy | callen: fewer tokens |
| 17:25 | bbloom | just like how you can't take the value of a macro without applying it to forms, you can't take the value of a method call without applying it to argument types |
| 17:25 | callen | technomancy: what's the matter, don't like #(%)!@@@@@ ? |
| 17:26 | technomancy | callen: aren't you CL types supposed to complain about all the extra syntax clojure has? =) |
| 17:26 | qed | llasram: so what i want to do is take a seq of java methods, all of which take 1 argument. I want to generate fn names like "foo-bar?" from "isFooBar". Is that doable? |
| 17:26 | callen | technomancy: one would almost think you like Lisps. |
| 17:26 | callen | technomancy: yes, that's what I'm lampooning. |
| 17:26 | callen | technomancy: I prefer words and parens and little else, although vectors have won me over. |
| 17:26 | technomancy | binding: it's not the same as calling. |
| 17:26 | technomancy | #truefacts |
| 17:27 | llasram | qed: That's more usefully-doable, because you can do all the mangling at macro-expansion-time and even provide sane type-hints |
| 17:27 | ToBeReplaced | qed: yeah, macro-it-up |
| 17:28 | ToBeReplaced | harder to get the method names though |
| 17:28 | bbloom | technomancy: but to fully clear up the auto memfn-ification of .methodCalls: it's doable if the compiler was defunctionalizing |
| 17:28 | bbloom | technomancy: that is, all higher order operations would be inlined |
| 17:28 | ToBeReplaced | at least, hard to do it sensibly (and do all the right things around overloading) |
| 17:28 | bbloom | technomancy: but since functions are reified into IFn instances, then we can't do it, except as a potential optimization |
| 17:29 | technomancy | bbloom: yeah, I'm OK with "it would introduce a bunch of special cases resulting in unpredictable behaviour" I gueeeeeeess |
| 17:29 | qed | llasram: how do I pass in '(.fooBar)? |
| 17:29 | bbloom | i don't think it's a special case or unpredictable behavior. it just requires a smarter compiler |
| 17:30 | technomancy | callen: my favourite part is how people complaining about square brackets seem to be oblivious to the fact that they sound *just* like the "too many parens lol" crowd |
| 17:30 | qed | llasram: (so it's callable later) |
| 17:30 | llasram | bbloom, technomancy: As continue to think about it, do you know if anyone has proposed #.method as reader syntax for auto-memfn'ing? Inside my head at least it seems really convenient |
| 17:30 | technomancy | llasram: could you experiment with it in user space using data_readers or whatever? |
| 17:31 | llasram | Oh! Yes |
| 17:31 | bbloom | llasram: it would require the compiler to use either reflection (slow) or to perform inlining & then would either need to A) fallback to reflection or B) error out for dynamic function use |
| 17:31 | llasram | bbloom: Oh, I was totes envisioning reflection |
| 17:31 | llasram | Maybe some invoke-dynamic love in the future |
| 17:32 | bbloom | *shrug* i think making it harder to use reflection is a good thing |
| 17:32 | callen | technomancy: that's largely why I don't complain, the syntax doesn't bother me. That having been said, there's something pleasantly and quietly conversational about Lisp. |
| 17:32 | bbloom | technomancy: the thing about the "extra" syntax in clojure is that scheme etc *already has special syntax for lists*. In fact, scheme has a binary infix operator for creating pairs & the parens are shorthand for that |
| 17:33 | llasram | qed: You'd write a macro which too the bare symbol names for the methods: (defmethodfns SomeType isFooBar isBazQuux) |
| 17:33 | bbloom | technomancy: in theory, the pair dot operator is a concrete constructor & you could have polymorphic implementations of lists |
| 17:33 | llasram | s,which too,which took, |
| 17:33 | bbloom | technomancy: extending that idea to maps & other data types is a NO BRAINER |
| 17:33 | bbloom | (now that i've used with clojure) |
| 17:33 | llasram | bbloom: I mostly agree with you, but think making it easier to use Clojure is a good thing :-) |
| 17:33 | callen | bbloom: Lispers didn't like the dot either. |
| 17:33 | callen | just fyi |
| 17:34 | bbloom | callen: but the dot is actually the opposite problem. it's going from something abstract (list notation) to something concrete (pair notation) |
| 17:34 | technomancy | bbloom: from what I can tell other lisps don't bother with maps |
| 17:34 | bbloom | technomancy: which blows my mind |
| 17:34 | callen | it's not really complicated |
| 17:34 | callen | most maps as they are used in most languages don't need to be actual maps |
| 17:35 | callen | just associative pairs |
| 17:35 | bbloom | sure, we've got association lists too, but we call them PAM |
| 17:35 | bbloom | choosing to use a concrete representation is a bad plan |
| 17:35 | callen | I know there's a concrete impl that is similar |
| 17:35 | callen | there's a *reason* I use Clojure after all |
| 17:35 | callen | I'm just making the point that Lispers were accustomed to picking and choosing the bits they wanted. |
| 17:36 | callen | whether that be an assoc list or hash-table |
| 17:36 | technomancy | I get the feeling in scheme hash-tables are only used if you don't know the possible keys up-front. |
| 17:36 | bbloom | you can think of clojure's syntax as being a pre-macro compiler pass which evaluates forms corresponding to abstract data types |
| 17:36 | technomancy | which is why it doesn't bother people that they don't have usable literal syntax, as far as I can tell |
| 17:37 | callen | I'm not saying I mind Clojure syntax, I'm saying it took me time to stop being grumpy about it and I understand why others might be. |
| 17:37 | callen | technomancy: thanks again for limit-break :P |
| 17:37 | technomancy | but stuff like update-in seems more onerous with hash-tables or alists or whatever |
| 17:38 | bbloom | update-in is glorious. |
| 17:38 | technomancy | callen: cool; at least someone is using it |
| 17:38 | bbloom | it's like 90% of lenses without a phd :-) |
| 17:38 | callen | technomancy: Ritz is too baroque, I have to use it. |
| 17:38 | tomjack | 90%?? |
| 17:38 | lazybot | tomjack: What are you, crazy? Of course not! |
| 17:39 | callen | bbloom: you've insulted tomjack's hobbies. |
| 17:39 | bbloom | tomjack: ok 20%, whatever. go give me the other 80% as simply as keywords & vectors work w/ update-in :-) |
| 17:41 | tomjack | it's one point in a whole space, I'd say 0% :) |
| 17:41 | bbloom | nope, i'm going with the 80/20 rule :-P |
| 17:41 | callen | but for the rest of us, it's 80% |
| 17:43 | callen | new rule, if I can't grep around for what the JIRA ticket is referencing and nobody answers my question on the JIRA task, it's not getting done. |
| 17:43 | technomancy | what's wrong with the old rule of "if it's on JIRA, it's probably not getting done"? |
| 17:43 | bbloom | so the nice thing about update-in & friends is that you get something lens-like without having to A) create an entirely separate set of objects or B) use data with quoting/unquoting wrapper objects |
| 17:43 | tomjack | bbloom: yeah 80/20 probably applies :) |
| 17:47 | callen | technomancy: I like to try. |
| 17:47 | callen | I also like a clean JIRA panel so that I can do other things. |
| 17:53 | leif-p | Hey everybody. Can anyone point me to some design docs for core.async and/or suggestions of non-trivial applications to hack on to learn it? tbaldridge, I'm looking in your direction. |
| 17:56 | tbaldridge | leif-p: there's this, but like you said, it's trivial https://github.com/clojure/core.async/blob/master/examples/walkthrough.clj |
| 17:56 | tbaldridge | besides that and the golang talks/tutorials, I don't really have much else. |
| 17:57 | leif-p | tbaldridge: what about design docs? Did you work off of any papers / implementations when composing that gnarly macro / compiler? |
| 17:58 | bhauman | leif-p: I'm assuming your aware of this https://github.com/swannodette/async-tests |
| 17:58 | tbaldridge | leif-p: I got the ideas from https://github.com/scala/async#how-it-works , but the actual code/design is my own work. |
| 17:59 | tbaldridge | leif-p: it's one of those things where C#, and Scala both do similar transforms, but from what I've been able to find, haven't really published how they do it. |
| 18:00 | tbaldridge | There's also this, that might help a bit: http://hueypetersen.com/posts/2013/08/02/the-state-machines-of-core-async/ |
| 18:00 | bbloom | tbaldridge: scala's approach uses shift/reset (delimited continuations) & is documented here: |
| 18:01 | bbloom | http://infoscience.epfl.ch/record/149136/files/icfp113-rompf.pdf |
| 18:02 | tbaldridge | bbloom: you're thinking of Scala's CPS transform, the code I linked to is from the async implementation, https://github.com/scala/async#comparison-with-cps-plugin |
| 18:02 | bhauman | leif-p: there's also this: examples from Hoare's paper rewritten in core.async https://github.com/nodename/async-plgd |
| 18:02 | tbaldridge | Leave it to scala to implement two ways of doing the same thing |
| 18:03 | leif-p | tbaldridge: Yeah, I saw async-tests, and it seemed UI-focused, but it *will* probably help me get my head around the programming model. The docs you and bbloom just sent will probably be enough for me to muddle through (and keep me busy for a long while). Thanks, all! |
| 18:03 | bbloom | ah, my misunderstanding. thanks for the correction |
| 18:05 | bbloom | oh interesting, they are doing local state machines too. cool |
| 18:17 | devn | http://www.flipscript.com/data/AMBICBar_K1W1M0G1b2363X1,1-207,50;G0c4c95X1,51-207,100;G231b61X1,101-207,150;G512c16X1,151-207,200;S2G917341X1,201-207,250;S2Gff96ffX1,251-207,300;S2Gfbefa3X1,301-207,350;S2Ge2e2e2X1,351-207,400;G323232X1,401-207,450.pngx?dv=0&cq=99&tn=0&rg=1&gs=2&ff=3&w1=clojure&w2=&ff=3&pk=369970934 |
| 18:17 | devn | yeesh, sorry about that URL |
| 18:33 | mikerod | n00b question probably, but how do I change the value of a Var without re'defing it? I am getting this "IllegalStateException Can't change/establish root binding of: my-var with set clojure.lang.Var.set (Var.java:233)" using set! . I know that I can use alter-var-root, but is that my only option? |
| 18:33 | mikerod | I'm not wanting to just dynamically rebind it either. |
| 18:34 | Raynes | Don't. |
| 18:34 | bbloom | yeah, what Raynes said |
| 18:34 | bbloom | but also, you can use alter-root-var with constantly |
| 18:34 | Raynes | But don't. |
| 18:34 | bbloom | yeah, what Raynes said again |
| 18:35 | mikerod | Raynes: bbloom this is only for a testing scenario with code I'm not keeping around |
| 18:35 | Raynes | If you really need state, use an atom or something. |
| 18:35 | mikerod | more of an interactive thing |
| 18:35 | bbloom | mikerod: in that case, use with-redefs |
| 18:35 | mikerod | bbloom: Ok, so what is a use-case of set! and var-set? Just out of curiousity. |
| 18:35 | mikerod | curiosity* |
| 18:36 | bbloom | mikerod: dyhnamic bindings are mutable |
| 18:36 | bbloom | like if you need a thread local atom or something, you can just var-set inside a binding form |
| 18:36 | bbloom | but it's pretty rare / often a bad plan |
| 18:39 | mikerod | bbloom: Ok, that makes sense. |
| 18:39 | bbloom | https://groups.google.com/forum/#!topic/clojure/PCKzXweeDeY |
| 18:39 | bbloom | that post actually explains it pretty clearly |
| 18:39 | bbloom | the reason mutable vars is OK is b/c they have dynamic extent, so they can't escape via a closure |
| 18:39 | bbloom | which means you can't break thread safety |
| 18:40 | mikerod | That makes sense. Thanks for the link, reading through it. |
| 18:41 | mikerod | So *warn-on-reflection* is an example of a dynamic Var. I see it is defined in RT. It seems I can do a (set! *warn-on-reflectoin* true) from within the REPL. |
| 18:41 | bbloom | and if you use bound-fn, you're essentially cloning (part of) the execution environment, so mutating a dynamic var in your extent won't affect bound-fns which can modify the dynamic vars in their isolated dynamic extents |
| 18:43 | bbloom | mikerod: looks like RT.java calls push-thread-bindings on startup |
| 18:43 | bbloom | basically, warn-on-reflection is bound in the dynamic extent of main |
| 18:44 | bbloom | oh no, more accurately: |
| 18:44 | bbloom | there is a try/push/finally/pop in there, which is akin to the binding macro |
| 18:44 | bbloom | and it wraps the file loading process |
| 18:44 | mikerod | Ah, that makes sense. |
| 18:45 | mikerod | That's what initially threw me off that I couldn't def a Var similarly and use set! on it. Makes sense now that it fits into being bound in the dynamic extent. |
| 18:46 | bbloom | unfortunately (or thankfully?), clojure's module loading logic is not pluggable in anyway, otherwise you could do the same trick. in theory, you could imagine registering a hook that gets passed the loading thunk & you could wrap a binder around that |
| 18:46 | bbloom | but clojure doesn't offer such a feature |
| 18:51 | mikerod | Yeah, I guess that doesn't upset me too much really since I haven't really ran into wanting to do this much before anyways. |
| 18:52 | bbloom | use with-redefs :-) |
| 18:53 | mikerod | Now that I look again, I see this same binding mechanism is used in clojure.main. Thanks for helping me understand that. Enlightening. with-redefs is workable. |
| 18:57 | cromney | anybody run into an issue where InetAddress/getByName works, but InetAddress/getAllByName fails to resolve the same hostname? |
| 19:00 | akurilin | Quick style question: is it reasonable to place argument checks into a do block, assuming they either do nothing or throw an exception? |
| 19:00 | bbloom | mikerod: this also reminds me of something i was wondering a few months ago: I wonder if performance is the *only* reason why lazy-seq & friends don't use bound-fn. i suspect so |
| 19:01 | hiredman | I imagine the other reason is binding conveyance is just gross |
| 19:01 | bbloom | hiredman: you think that even for thunks? |
| 19:02 | hiredman | yes, which doesn't mean I don't do it, because it is useful |
| 19:02 | hiredman | but it can cause all kinds of edge cases which I wish just weren't there |
| 19:03 | bbloom | which edge cases are you thinking about in particular? |
| 19:03 | hiredman | for example what does the clojure predicate thread-bound? mean? |
| 19:03 | bbloom | i spend a lot of time thinking about dynamic extent, effects, and context. since they seem to be kinda the unsolved "hard" problems in the functional world |
| 19:03 | hiredman | (I think it is thread-bound?) |
| 19:04 | bbloom | (doc thread-bound?) |
| 19:04 | clojurebot | "([& vars]); Returns true if all of the vars provided as arguments have thread-local bindings. Implies that set!'ing the provided vars will succeed. Returns true if no vars are provided." |
| 19:04 | cromney | akurilin: have you looked at pre-conditions? |
| 19:04 | bbloom | hm, i've never felt the need for such a predicate, i couldn't imagine what i need it for.... |
| 19:04 | bbloom | what have you used it for? |
| 19:04 | hiredman | does it mean that the var was bound in this thread, or that the binding was conveyed, and if I have a macro that tries to establish a thread local binding, and only one binding |
| 19:06 | hiredman | doing binding conveyance in lazy-seqs brings even more edges |
| 19:07 | bbloom | so part of the issue is the "full" capture of bindings |
| 19:07 | bbloom | instead of a delimited capture |
| 19:07 | hiredman | miles of edges |
| 19:07 | bbloom | like if i have a *current-thread-id* and it's set to 5 |
| 19:07 | bbloom | then i bound-fn, and then run that on another thread, i'm fucked |
| 19:07 | hiredman | assuredly |
| 19:08 | bbloom | there is a need for delimiters: http://okmij.org/ftp/Computation/dynamic-binding.html#DDBinding |
| 19:08 | hiredman | which, future and agent sends now helpfully do for you :( |
| 19:08 | bbloom | bound-fn is akin to a full, non-composable continuation :-/ |
| 19:09 | hiredman | so, you know, leave it out, if I need to capture the dynamic environment I can capture it lexically and rebuild it myself |
| 19:10 | bbloom | yeah, ok, you've prompted me to think about it and caused me to sell myself what you're offering :-) |
| 19:10 | hiredman | but rich maybe has some idea for building a conditional system using them or something |
| 19:10 | hiredman | he mentioned something like that at his conj keynote where he said binding conveyance was going to happen |
| 19:12 | bbloom | seems like core.async greatly diminishes the pressure to do something like that |
| 19:12 | bbloom | b/c you can establish dynamic bindings in "forked" sub processes |
| 19:12 | bbloom | and then you just parameterize both of them with a channel |
| 19:12 | bbloom | the same channel, i mean |
| 19:13 | bbloom | if java & javascript had fast, restartable exceptions, it might be a different story |
| 19:13 | noonian | what is a good place to point people at who are interested in learning Clojure but don't have much (or any) background in cs and/or programming? |
| 19:15 | hiredman | noonian: the best place to start is with some problem you want to try and solve |
| 19:15 | bbloom | hiredman: on a related note. i wish there were explicit dynamic parameters, and implicit static parameters. right now, we've got 2 diagonal corners of that 2x2 grid & the other 2 corners are lonely |
| 19:15 | bbloom | actually, hm. i guess passing around atoms cover the explicit dynamic parameters thing, to some extent |
| 19:16 | noonian | hiredman: thanks, but I would like a good starting resource to point someone at when the other options they are considering are learning python or ruby and the like from somewhere like code academy or udacity |
| 19:18 | cromney | noonian: O'Reilly has some great videos that Neal Ford and Stu Halloway recorded called Clojure Inside Out |
| 19:18 | cromney | not free, but worth the investment imho |
| 19:19 | cromney | noonian: codeschool has some free Clojure vids iirc |
| 19:19 | hiredman | noonian: let them go there, the closest thing to those kind of classes are maybe the clojure training stuff the relevance guys do, but that is sort of few and far between |
| 19:19 | technomancy | bbloom: doesn't closing over something count as an implicit lexical parameter? |
| 19:19 | noonian | thanks guys |
| 19:20 | hiredman | once they have experience with other stuff, clojure should be very attractive to them and you won't be able to stop them picking it up |
| 19:21 | mikerod | bbloom: Interesting topic. This is the first I've looked into bound-fn. This gave me some things to add to the reading list. |
| 19:21 | bbloom | technomancy: i guess so, but it seems kinda rigid compared to what scala & haskell can do w/ implicit arguments |
| 19:21 | noonian | yeah, I'm just trying to present Clojure as an alternative because I doubt they are aware of it at all |
| 19:22 | bbloom | technomancy: although, those rely on a type system, i guess you could imagine an untyped variant of them. not sure what it would look like tho |
| 19:22 | technomancy | bbloom: "implicit" is uncomfortably close to "magic" in my experience |
| 19:22 | technomancy | but I haven't used haskell or scala |
| 19:22 | bbloom | i can't change the literature, but i'd s/implicit/contextual/ |
| 19:22 | callen | I have, I like it. |
| 19:23 | bbloom | oh, so interestingly, it seems haskell's implicit parameters are type checked, but resolved by NAME not by type |
| 19:23 | callen | technomancy: imagine refinements but not retarded. Like that. |
| 19:23 | bbloom | scala's implicit parameters are resolved by type, which seems dumb to me |
| 19:23 | callen | er, implicit arguments, not Scala implicits, sorry. |
| 19:23 | bbloom | http://www.haskell.org/haskellwiki/Implicit_parameters |
| 19:23 | callen | I misunderstood |
| 19:25 | bbloom | technomancy: compare to the approach here: http://www.scala-lang.org/old/node/114 |
| 19:26 | bbloom | bound-fn pushes/pops bindings on top of the dynamic bindings, which involves a linear scan of the bindings |
| 19:26 | bbloom | in theory you could just *set* without supplementing the implicit bindings map |
| 19:27 | bbloom | i'm not sure how either scala or haskell handle implicits with respect to closures tho |
| 19:28 | bbloom | also, it seems common to want to transfer some subset of dynamic vars to implicit ones. there is this temptation to not pass *vars* but it makes sense to leave the dynamic extent world when you ultimately call a function that wants that argument from the lexical extent of the caller |
| 19:29 | callen | bbloom: closures themselves can have implicit arguments in Scala |
| 19:29 | callen | https://issues.scala-lang.org/browse/SI-1492 |
| 19:30 | bbloom | gotcha. i take issue with the dispatch by type, however |
| 19:31 | callen | there's a lot to take issue with in Scala, it's not a language for people whose dicks get raw at freckles on a pretty girl's face. |
| 19:31 | callen | most people are just happy to have a non-trivial type system. |
| 19:31 | bbloom | i have no idea what that means, but i'm quite certain it's inappropriate in here |
| 19:31 | callen | bbloom: whining about relatively unimportant flaws. |
| 19:33 | cromney | .. |
| 19:57 | callen | cromney: are you not entertained? |
| 20:00 | TimMc | callen: Gonna have to agree with bbloom here. |
| 20:09 | callen | TimMc: I would too, if I were you. |
| 20:11 | llasram | wow |
| 20:12 | travisrodman | hello clojurians... i have a java compilation issue |
| 20:12 | travisrodman | i am building in maven, using a java class that has a static initializer |
| 20:13 | travisrodman | and when the clojure code is compiled, it seems to be executing the initialization of the class |
| 20:13 | travisrodman | instead of just compiling the code |
| 20:13 | technomancy | travisrodman: clojure code can't be compiled without being run |
| 20:13 | travisrodman | it works fine building in lein, and i am using the theoryinpractise plugin in maven for the build |
| 20:14 | travisrodman | hmm |
| 20:14 | llasram | travisrodman: Importing a class in Clojure forces the class to be loaded, which will run any static initializers on the class |
| 20:15 | travisrodman | that is unfortunate... is there any way to work around this without modifying the original java code? |
| 20:15 | technomancy | most likely lein wasn't doing any compilation at all |
| 20:15 | technomancy | travisrodman: you could resolve the class at runtime. it's pretty awkward though. |
| 20:15 | technomancy | and slow |
| 20:15 | travisrodman | thanks for the immediate feedback btw... |
| 20:15 | technomancy | or just don't AOT the clojure code |
| 20:16 | llasram | travisrodman: Not that I'm aware of. In code I control I've just been pushing things I want deffered into static inner classes |
| 20:16 | llasram | deferred even |
| 20:16 | llasram | No, I was right the first time -- just have erc-spelling-mode off somehow |
| 20:17 | travisrodman | unfortunately, the clojure code is primarily providing a dsl for the java, so the clients are looking to compile as part of the maven build |
| 20:18 | travisrodman | @technomancy: what would the class resolution at run-time look like... i can google that if the answer is too involved. |
| 20:18 | llasram | travisrodman: I'm not entirely following. Can you provide more details? |
| 20:18 | technomancy | I guess it's basically just reflection |
| 20:19 | travisrodman | @technomancy: right... see, I am using gen-class to output interfaces that can be utilized by the java in the larger system, so the AOT is somewhat necesary, I believe |
| 20:19 | travisrodman | @technomancy: in that case, how would you not compile the code, or would it be deferred in some manner i am not aware of if the clj's were just included in the jar |
| 20:20 | llasram | travisrodman: Oh! Instead, you can write Java stub classes which load Clojure namespaces and invoke functions via the Clojure Java APIs |
| 20:20 | travisrodman | @llasram: what can I clarify for you? |
| 20:20 | llasram | I believe your last statement clarified sufficient |
| 20:20 | llasram | sufficiently even |
| 20:21 | llasram | Oh, and FYI, in IRC you generally just refer to someone's handle directly. No need for an `@` prefix |
| 20:21 | travisrodman | ah, thanks |
| 20:21 | llasram | travisrodman: Here's an example of the style I've adopted lately: https://github.com/damballa/abracad/blob/master/src/java/abracad/avro/ClojureDatumReader.java |
| 20:22 | technomancy | yeah, you could bridge the gen-class->regular-clojure with runtime require and write your regular clojure using the class normally |
| 20:22 | travisrodman | technomancy: okay, i will look into that |
| 20:23 | travisrodman | llasram: thanks. i will look that over, but i am in the unfortunate position of not being able to bend the java to my will, but i am sure it will be worth looking at none-the-less |
| 20:24 | travisrodman | thanks, very much, for the feedback |
| 20:24 | llasram | travisrodman: Oh, sure, but you can add new Java. The philosophy is that you write Java to interface with Java, write Clojure to actually implement the program logic |
| 20:26 | travisrodman | out of the interest in understanding, why, during the maven build, would the code behave as though initialized, as opposed to just compiling, as you would with any other java? is it because it needs to run through the clojure compiler, and that is causing the instantiation? |
| 20:27 | travisrodman | llasram: in a sense, that is what the clojure is doing, i am using proxy to generate classes-on-the-fly so an entirely distinct group of users can augment functionality, without java or the original code |
| 20:28 | travisrodman | it is just that the some of the calls rely on classes in the java to support the dsl, and this is where this issue is coming in. |
| 20:28 | travisrodman | thanks for the code sample though... always expanding my understanding... I appreciate it |
| 20:30 | llasram | travisrodman: In Clojure compiling are less distinct than Java. You're essentially running some code, and just saving off the classes which are being dynamically generated. The running-of-code which loads namespaces loads any classes which are `:import`ed, which runs their static initializers |
| 20:30 | llasram | s,compiling,compiling and running, |
| 20:30 | travisrodman | llasram: that is very intersting... so in reality, instead of wrapping from the clojure perspective, you are consuming from the java side... very nice. |
| 20:31 | travisrodman | llasram: got it, in a sense, how the macros are expanding and replacing themselves with their executed values, until it finally settles on the final bytecode? |
| 20:31 | travisrodman | llasram: am i understanding that correctly? that was a bit of a statement that turned into a question. |
| 20:32 | llasram | Well, macros don't really enter into the picture, except in that macro-expansion is a step in code compilation. More to the point is that in Clojure, the compilation unit is the top-level form |
| 20:32 | llasram | And compilation/run time are only distinguished per top-level form |
| 20:33 | llasram | So once you've executed the `ns` form when loading a file |
| 20:33 | technomancy | which is really *so* much simpler than the alternative |
| 20:33 | llasram | Everything needs to be set up for anything which follows -- e.g., including code which depends on classes having been loaded |
| 20:33 | technomancy | if you look at the crazy backflips racket has to do to have a separate non-runtime compile phase... whew. |
| 20:34 | llasram | I really should look at Racket more... |
| 20:34 | llasram | travisrodman: I need to idle for a bit, but best of luck! |
| 20:34 | travisrodman | np... thanks for the info |
| 20:36 | travisrodman | technomancy: thanks for the tip on that i will check it out. i am sure the solutions you are presenting are cleaner, more straightforward, and in the end, better, it is good to know the alternative |
| 20:53 | Guest9805 | Hi, everyone. I'm having trouble understanding a few methods in Clojure relating to Java interop. I saw a solution to a 4Clojure problem that used the (.get) method from Java, and I can't seem to find for the life of me what that function does or where it comes from. Mind you, I'm not a Java programmer, so it's been extra difficult. |
| 20:58 | Guest9805 | Anyone? |
| 20:58 | clojurebot | Just a heads up, you're more likely to get some help if you ask the question you really want the answer to, instead of "does anyone ..." |
| 21:01 | hyPiRion | Guest9805: I wouldn't worry too much. It's most likely done on a vector or a map, in which case it is equivalent with a normal get |
| 21:03 | Guest9805 | Ah, okay. Just tried both in the REPL, and they seem to work the same way. I guess that solution wasn't very idiomatic. |
| 21:03 | hyPiRion | yeah, sounds a bit strange |
| 21:08 | mthvedt | is there a way to make compojure not automagically wrap your return values in certain routes |
| 21:18 | xeqi | mthvedt: you could return a ring response yourself |
| 21:19 | mthvedt | xeqi: i want to return a map that's handled by ring middleware |
| 21:28 | xeqi | mthvedt: and what is compojure doing to the map? |
| 21:29 | xeqi | sticking it in :body ? |
| 21:29 | mthvedt | xeqi: compojure routes add :headers, :response, and an empty :body to any APersistentMap |
| 21:29 | xeqi | ah, yeah https://github.com/weavejester/compojure/blob/master/src/compojure/response.clj#L23 |
| 21:32 | mthvedt | i have middleware that turns maps into JSON responses, which compojure is interfering with, so that's annoying |
| 21:51 | jonh | bnls |
| 21:52 | coventry | Where would I find documentation for standard Server-Sent-Events code? (The pedestal tutorial is referring to it on the Making the Service wiki page.) |
| 22:14 | coventry | Oh, it's a javascript concept. I was looking for it in a clojure context. |
| 22:24 | egghead | coventry: it's something a server does that js can pay attention to |
| 22:25 | egghead | coventry: https://developer.mozilla.org/en-US/docs/Server-sent_events |
| 22:47 | coventry | egghead: thanks. |
| 22:48 | muhoo | mthvedt: there's a ring-json-middleware, IIRC |
| 22:48 | mthvedt | muhoo: stackoverflow suggests compojure breaks that middleware also |
| 22:51 | muhoo | i dunno. i'm doing a project rght now that retrns json for api endpionts, have not had any problems. |
| 22:52 | muhoo | doign it manually, i..e (fn [req] {:status 200 :body (json/ncode (do-stuff req)))}) |
| 22:53 | muhoo | or rather (GET "/foo" req {:status 200 :body (jon/encode (do-stuff req))}) |
| 22:53 | egghead | i'm doing some fun edn over websockets |
| 23:14 | llasram | Huh. This is interesting. A *data-readers* tagged literal constructor can return arbitrary forms, which are then treated as what has been just read by the reader. If the function returns forms which represent code and the forms are being compiled, the tagged literal can inject arbitrary code to be compiled |
| 23:15 | llasram | Maybe this intentional. It seems consistent. But I found it surprising at first |
| 23:20 | xeqi | llasram: or the data reader could just eval the string itself |
| 23:40 | Apage43 | here's my json-response https://github.com/couchbaselabs/mortimer/blob/master/src/mortimer/web.clj#L26-L30 |
| 23:41 | Apage43 | which i copy around because the existing middleware I've run across uses data.json, and I prefer cheshire |