2013-08-23
| 00:47 | gdev | `cbp, couldn't reproduce it, closing the trouble ticket =/ |
| 00:51 | babu` | dakrone, Any idea when you will be able to implement proxy auth for clj-http.client? I looked around and found http.async.client and converted my code to use that. But ^C^K with clj-http is instantaneous but with the async it takes several seconds. |
| 00:52 | dakrone | babu`: I will not be able to get to it tonight, but hopefully tomorrow or sometime this weekend? |
| 00:52 | dakrone | I don't think it will be difficult, just requires reading docs to find out how to do it |
| 00:58 | kendallbuchanan | Quick question: I'm making a leiningen library, in which I'd like to bind the contents of a file in "resources" to a local var, and then access that var's value from a project depending on the library. |
| 00:58 | kendallbuchanan | Basically, I want to bind the contents of a file to a var at compilation, not runtime. Any thoughts? |
| 01:01 | gdev | put the slurp in clojure file that has to be AOTd ? |
| 01:03 | kendallbuchanan | yeah |
| 01:03 | dakrone | babu`: actually, this looks pretty easy, so I'm hoping to have it done by tomorrow, the hardest part will be testing it |
| 01:04 | kendallbuchanan | I'd like a macro like "defcontents", or something: (defcontents my-file "./file.txt"), and my-file would reference the contents of "file.txt" |
| 01:05 | kendallbuchanan | or, is there a way to expose the "resources" directory of the library to the hosting program? |
| 01:05 | kendallbuchanan | that'd be another solution, I suppose |
| 01:06 | gdev | and this library has to have the contents of it at compile time to do its job? |
| 01:07 | kendallbuchanan | the program needs access to the contents of a file contained in the library's "resources" path |
| 01:07 | gdev | still, I think defcontents could be a normal function in a namespace that gets AOT compiled |
| 01:07 | kendallbuchanan | I'm unfamiliar with AOT… any constructs I should look up? |
| 01:08 | gdev | stands for ahead of time compile |
| 01:09 | gdev | in your project.clj you can specify what needs to be compiled |
| 01:10 | kendallbuchanan | ah, it's a compilation setting, then? |
| 01:11 | kendallbuchanan | Okay, I think I understand now… thanks!!! |
| 01:12 | gdev | no problem =) glad i could help |
| 01:14 | dissipate | when is the entire java standard library going to be ported to pure clojure? |
| 01:15 | gdev | August 13 2016 |
| 01:15 | mischov | And not a minute earlier. |
| 01:16 | dissipate | gdev, sweet |
| 01:16 | callen | mischov: nor later. A wizard's grimoire arrives precisely when it means to. |
| 01:16 | dissipate | mischov, if the entire java standard library was ported to clojure, no more calls to java (excepting for 3rd party libs) |
| 01:16 | dissipate | think of how great that would be |
| 01:17 | mischov | It seems like it might be a tad bit slower. |
| 01:17 | callen | every new person says that. |
| 01:17 | callen | then they learn not to care and move on. |
| 01:18 | dissipate | callen, we shouldn't care? |
| 01:19 | callen | dissipate: it doesn't really affect the day to day experience of writing Clojure. |
| 01:19 | babu` | dakrone, ok thanks, I can pull the updated version when available and run my program and see if it works. |
| 01:19 | dissipate | callen, or are you saying a new standard library should be built in pure clojure and completely discard the java standard library? |
| 01:20 | gdev | clojure in clojure is just a fantasy dreamed up by people who were just wanting to do web programming anyway |
| 01:20 | dissipate | callen, but every call to a java library function is a call that causes side effects. isn't the goal to get rid of side effects? |
| 01:21 | callen | the goal is to write nice software in a sane way. |
| 01:21 | callen | not to engage in a religious crusade against flipping bits. |
| 01:21 | callen | bits are gonna get flipped, one way or another. |
| 01:22 | dissipate | callen, you have never been burned by side effects in the java libs? |
| 01:24 | callen | dissipate: I roast people that ask too many questions over a spit. |
| 01:24 | dissipate | how rude |
| 01:25 | mischov | bear with him.. |
| 01:25 | callen | dissipate: but more seriously, as somebody who used to do CL before, the degree to which I am impacted by side effects in libraries, Java or otherwise, is much less substantial. |
| 01:25 | callen | dissipate: I would advise, "chill, marinate in the parens for awhile, and enjoy" before launching any crusades. |
| 01:25 | gdev | C-x M-c M-butterfly is how I flip bits |
| 01:26 | callen | gdev: like any civilized person. |
| 01:26 | callen | dissipate: you'll find something much more important to dislike than that Clojure is hosted in the JVM and uses Java libraries in some cases. |
| 01:28 | dissipate | callen, no, i'm glad the java libs are available. but i figured it would be good if clojure could escape the java ecosystem entirely some day. |
| 01:28 | callen | dissipate: a Clojure-on-the-LLVM project some day could be cool. I'm not really sweating it. 99% of what I do is server-side. |
| 01:28 | callen | well, server-side or in a web browser. |
| 01:28 | dissipate | callen, actually, right now i dislike the fact that clojure isn't a replacement for scripting languages |
| 01:29 | callen | it's served fine for me there. |
| 01:29 | mischov | Clojurescript+node? |
| 01:29 | callen | mischov: some people do that. Prismatic used to do that (inadvisedly) on the backend, lol. |
| 01:30 | callen | they use the standard backend tooling now. |
| 01:30 | mischov | dissipate: There are a number of clojure projects targeting other ecosystems. Take a look around for clojure in python, c, etc, or even clojure in clojure |
| 01:32 | dissipate | mischov, have you tried clojure on .NET? |
| 01:33 | mischov | Can't say I have. |
| 01:52 | gdev | i've yet to meet anyone who uses clojure on the CLR |
| 01:53 | gdev | i was tempted to try it out just to say i did it, but then I remembered I had a dentist appointment |
| 02:21 | [Neurotic] | Newb clojure q - looking at different testing libs. Anyone got one they love way more than another? Looking at Midje it seems quite nice. Opinions? |
| 02:22 | wink | seemed nice to me as well :) |
| 02:23 | [Neurotic] | ringingf endorsement ;) |
| 02:28 | callen | [Neurotic]: I prefer clojure.test |
| 02:30 | [Neurotic] | how come? |
| 02:30 | [Neurotic] | the repl support in midje seemed to sell me |
| 02:44 | s4muel | Oh, this chat again. |
| 02:45 | [Neurotic] | heh yeah |
| 02:45 | [Neurotic] | sorry ;) |
| 02:47 | s4muel | No, it's quite alright. I am still on the 'new' side of Clojure and expectations works for me so far. |
| 02:50 | cgag | anyone seen "peerUri is undefined" when trying to use the clojurescript browser repl? |
| 02:51 | [Neurotic] | ah nice and minimal |
| 03:02 | futile | yo dawg |
| 03:02 | futile | i herd u like programming languages so i put a programming language in your programming language so you can program while you program |
| 03:02 | futile | [Neurotic]: yeah expectations is pretty sweet |
| 03:25 | dissipate | what is the difference between a 'symbol' and a 'special form'? |
| 03:25 | TEttinger | ,(class :whatamI) |
| 03:25 | clojurebot | clojure.lang.Keyword |
| 03:26 | TEttinger | dissipate, good question |
| 03:26 | TEttinger | I kinda would think a symbol is something like the names in let bindings, or the name after def or defn. I'm probably wrong though. |
| 03:27 | amalloy | dissipate: they're pretty big difference: they're not at all alike. a symbol is basically a name, often used to refer to an object of some kind, or to represent the program's source code |
| 03:28 | amalloy | whereas a special form is like a primitive operator of the language: "let" and "fn" are two examples, as they're "function-like things" that are actually implemented as compiler specials |
| 03:29 | amalloy | we can compare to java, by a somewhat questionable analogy: in the expression "int x = 5 + 2;", int and x are a little like symbols, and = and + are like special forms |
| 03:31 | dissipate | amalloy, so they are clojure's 'built ins'? |
| 03:32 | cgag | yep |
| 03:32 | dissipate | i'm looking here: http://clojure.org/special_forms |
| 03:32 | amalloy | yes. there are a smallish number of them, but of course it's a little nebulous what counts |
| 03:32 | dissipate | doesn't seem to be too many |
| 03:33 | amalloy | dissipate: that's typical of a lisp |
| 03:33 | dissipate | and it has been rigorously proven that these make clojure turing complete? i'm assuming so. :D |
| 03:33 | amalloy | dissipate: it's been rigorously proven that just (fn ...) makes a language turing complete |
| 03:34 | cgag | that's the beauty of it, so many things you need primitives for in other languages you can do as macros in lisp |
| 03:34 | dissipate | cgag, i haven't gotten to macros yet. how do the special forms relate to macros? |
| 03:35 | cgag | in most other languages, something like "or" is built into the language |
| 03:35 | amalloy | dissipate: macros act a lot like special forms, but are written by you instead of rich |
| 03:36 | cgag | a = b || c |
| 03:36 | Raynes | Lisp is fanntastic. |
| 03:36 | amalloy | you can think of them as a little like compiler extensions, except instead of hideously hairy they are pretty simple |
| 03:36 | cgag | you can't write || yourself because anything you write yourself evaluates it's arguments right away, and || is supposed to short circuit |
| 03:36 | dissipate | cgag, yes, and? |
| 03:37 | cgag | with macros, you can control when arguments get evaluated, so you can just write or as a macro on top of if |
| 03:38 | dissipate | hmm, i don't see '||' in the special forms list |
| 03:38 | amalloy | dissipate: in clojure, (and true (/ 10 0)) doesn't break (because and short-circuits as you'd expect), but it doesn't have to be a special form like it would in, say, ruby |
| 03:38 | dissipate | is it a standard macro? |
| 03:38 | cgag | it's "or" i nclojure |
| 03:39 | cgag | it's not a special form, it's just a macro in the standard library |
| 03:39 | amalloy | instead, or is written in clojure as (defmacro or [x y] `(if-let [x# ~x] x# ~y)) |
| 03:39 | amalloy | you don't need to worry about *how* that works, the key point is just that you can write it inside the language instead of as part of the compiler |
| 03:39 | amalloy | (and of course that's a simplified version of or that only accepts two args; the real one takes arbitrarily many) |
| 03:40 | dissipate | that's pretty wild |
| 03:40 | dissipate | this is a wild language |
| 03:41 | amalloy | i just noticed i accidentally switched from and to or partway through. hope the illustration still worked |
| 03:42 | dissipate | amalloy, how much contention is there over the selection of the special forms? certainly not everyone agrees on what those should be? |
| 03:42 | amalloy | wellllll, i'm not sure what you mean. nobody gets to contend, because rich already picked them to build the language from |
| 03:43 | dissipate | amalloy, right, but there are many other flavors of lisp, no? |
| 03:44 | amalloy | ah. yes, that's true, and they don't all have identical special forms. but there's a lot in common |
| 03:44 | dissipate | it's interesting that there are so few |
| 03:46 | TEttinger | dissipate, there's a famous paper that kinda lays out the basics needed to implement lisp. can't remember the name. |
| 03:48 | cgag | anyone seen "peerUri is undefined" when trying to use the clojurescript browser repl? |
| 03:49 | TEttinger | cgag, I'm afraid I don't yet use clojurescript. |
| 03:50 | amalloy | TEttinger: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.111.8833&rep=rep1&type=pdf ? |
| 03:50 | TEttinger | dissipate, http://www-formal.stanford.edu/jmc/recursive.html this paper. it's a little complex in parts, but it's amazing that the language can be defined with such a small set of forms |
| 03:52 | TEttinger | amalloy, did we link to the same paper? |
| 03:52 | amalloy | i won by two seconds |
| 03:52 | amalloy | i was trying to find the paper you mentioned, so it's not surprising it's the same |
| 03:52 | TEttinger | heh |
| 03:53 | TEttinger | I was wondering if the PDF is better-formatted than the HTML version |
| 03:53 | cgag | 'night people, welcome aboard dissipate |
| 04:18 | andyfingerhut | I am trying to understand how core.clj in the Clojure source code can require clojure.java.io, which seems to be compiled later in the build. Is it difficult to explain how that works? |
| 04:19 | kral | any company here that is looking for a wannabe clojure programmer? :) |
| 04:23 | amalloy | andyfingerhut: i don't know what you mean by "later in the build". the compiler evals 90% of clojure.core, recurses into clojure.java.io at the request of clojure.core, and then goes back to clojure.core |
| 04:24 | amalloy | ie, compiling a file isn't an atomic operation, and it can be interrupted to go compile another one partway through |
| 04:25 | andyfingerhut | amalloy: Don't be surprised if I am missing something very basic here. If you build Clojure source code using 'ant', for example, the build.xml file invokes the compiler on a sequence of namespaces that starts with clojure.core, and much later in the list it explicitly calls out clojure.java.io as well. Is that clojure.java.io perhaps unnecessary? |
| 04:26 | amalloy | welllllll, i'm not so sure about that part |
| 04:27 | andyfingerhut | I guess I can try an experiment to see. |
| 04:27 | amalloy | it may be the case that Compile/main needs to be passed a list of all namespaces that will be turned into classfiles |
| 04:28 | amalloy | with other namespaces that are required being only "temporarily" compiled |
| 04:29 | amalloy | but i think it's probably the case that you could omit some of those args and they would still be compiled |
| 04:31 | andyfingerhut | Deleting the occurrence of clojure.java.io from that list of namespaces in build.xml causes the ant build to fail when it reaches clojure.java.shell (or near there), probably when it tries to do a :use of clojure.java.io. |
| 04:36 | andyfingerhut | amalloy: Do you have a technical meaning of "only temporarily compiled" in mind? |
| 04:37 | andyfingerhut | amalloy: e.g. a compilation that does not cause .class files to be written to disk, perhaps? |
| 04:37 | amalloy | andyfingerhut: i meant in the way that compilation happens when you're not doing AOT: just to classes defined in memory via the DynamicClassLoader |
| 04:44 | hiredman | that seems unlikely |
| 04:45 | andyfingerhut | hiredman: Was that in reference to something I said? |
| 04:50 | hiredman | to amalloy's explanation, because non-transitive aot is something people have wanted for a long time |
| 04:51 | hiredman | but I guess that isn't really non-transitive aot because it is still broken |
| 04:52 | amalloy | yeah, i think it's pretty clear that's not what's going on, just from andyfingerhut's one experiment. if it were, the compiler would work as usual on other files but not output a .class for clojure.java.io |
| 04:57 | turbopape | hi everybody, |
| 04:57 | hiredman | I suspect it is a classloader issue, the compiler is generating classes using a dynamic classloader, but once compilation finishes the classloader is popped before the next namespace is compiled |
| 04:58 | turbopape | where is the link for lighttable 0.5? I only find the linkg for .4.11, |
| 04:58 | turbopape | and whenever I hit update It tells me that I am on the last version ... |
| 04:59 | turbopape | Ah, I actually needed to refresh my browser... |
| 04:59 | turbopape | never mind ... |
| 05:29 | NeedMoreDesu | I've written fast version of lazy-shuffle on vectors. http://www.everfall.com/paste/id.php?slhnb97yha7q |
| 05:30 | NeedMoreDesu | Sad story is, it's not that lazy if you need to get vector first lol. |
| 05:38 | NeedMoreDesu | Wow thats odd. Why my (vec (lazy-shuffle ...)) works 8 times slower that (vec (list (lazy-shuffle ...))) ? |
| 05:38 | TEttinger | NeedMoreDesu, that will blow the stack. |
| 05:39 | TEttinger | (on large collections) |
| 05:39 | TEttinger | you are recursing without using an explicit recur, and clojure will just go on creating call frames until it blows the stack |
| 05:40 | NeedMoreDesu | Im not recursing, it's lazy collections. |
| 05:40 | NeedMoreDesu | It wont blow stack. |
| 05:40 | TEttinger | (defn lazy-shuffle... (lazy-shuffle |
| 05:40 | NeedMoreDesu | (lazy-seq (lazy-shuffle ..)) |
| 05:41 | NeedMoreDesu | that makes difference |
| 05:41 | TEttinger | ok, didn't see that part |
| 05:41 | TEttinger | I've always been nervous about recursion on JVM |
| 05:41 | NeedMoreDesu | I found out why (vec (list ..)) is faster lol |
| 05:42 | TEttinger | I'm curious. pop? |
| 05:43 | NeedMoreDesu | http://clojuredocs.org/clojure_core/clojure.core/subvec |
| 05:43 | NeedMoreDesu | subvec is O(1) |
| 05:43 | NeedMoreDesu | So I think pop is O(1) too |
| 05:44 | NeedMoreDesu | persistent vectors is just awesome thing. |
| 05:47 | andyfingerhut | pop on vectors is O(log n), but such a nice fast O(log n) that only a theorist should quibble between that and O(1). |
| 05:47 | NeedMoreDesu | log32, afaik |
| 05:47 | andyfingerhut | pop on vectors doesn't use the same implementation that subvec does. |
| 05:48 | NeedMoreDesu | Is it faster? |
| 05:48 | hyPiRion | than what? |
| 05:48 | NeedMoreDesu | than subvec. |
| 05:49 | andyfingerhut | The O(log n) pop on vectors is asymptotically slower than O(1) subvec for large enough vectors. However, subvectors are not quite first-class citizens in the Clojure implementation today -- there are funky limitations on what you can do with subvectors |
| 05:49 | NeedMoreDesu | Oh. |
| 05:50 | NeedMoreDesu | So it's faster to use subvectors in this case? |
| 05:50 | andyfingerhut | Several JIRA tickets open for the limitations on subvecs, if you are curious. |
| 05:51 | andyfingerhut | There could be constant factors hidden in the O(1) vs. O(log n) that still make pop faster than subvec. For that you'd have to do some benchmarking to find out. |
| 05:54 | NeedMoreDesu | Results looks pretty much same. |
| 05:55 | andyfingerhut | That doesn't surprise me. I suspect they both usually allocate about the same amount of memory, which probably dominates the run time. Not much computation needed for those operations. |
| 05:56 | TEttinger | how about ##(sort-by #(rand-int -1000 1000) [:a :bb :ccc :dddd]) |
| 05:56 | lazybot | clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox80477$eval85003$fn |
| 05:56 | TEttinger | how about ##(sort-by (fn [] (rand-int -1000 1000)) [:a :bb :ccc :dddd]) |
| 05:56 | lazybot | clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox80477$eval85014$fn |
| 05:56 | hyPiRion | heh. |
| 05:56 | hyPiRion | ,(sort-by (fn [_] (rand-int -1000 1000)) [:a :bb :ccc :dddd]) ; it is |
| 05:56 | NeedMoreDesu | Sometimes pop is faster, sometimes subvec. Well, I guess it's ok to use pop. |
| 05:56 | clojurebot | #<ArityException clojure.lang.ArityException: Wrong number of args (2) passed to: core$rand-int> |
| 05:57 | andyfingerhut | I'd recommend going for pop, to avoid the corner cases you might otherwise hit with subvectors. |
| 05:57 | gvickers | Howcome ,,(= (keys {'foo "baz" 'bar "baz"}) ['bar 'baz]) |
| 05:57 | gvickers | is false |
| 05:57 | NeedMoreDesu | TEttinger but it's not lazy. |
| 05:57 | andyfingerhut | Not so much bug corner cases, but feature-not-yet-implemented-in-Clojure corner cases. |
| 05:58 | gvickers | meant for the vector to be ['bar 'foo] |
| 06:00 | NeedMoreDesu | gvickers: it's not really good idea to trust in order of keys in hash-map |
| 06:01 | andyfingerhut | gvickers: That and in your example the keys are 'foo and 'bar, not 'bar and 'baz, but yeah, what NeedMoreDesu said, unless you use a sorted-map, or sort the result of keys. |
| 06:03 | NeedMoreDesu | (keys (sorted-map 'foo "baz" 'bar "baz")) => (bar foo) |
| 06:03 | NeedMoreDesu | Still not ordered in that way it is written, but at least its the same each time it's launched. |
| 06:04 | gvickers | NeedMoreDesu: thanks, I think im going to try every? contains? {.... instead. forgot hashmaps are not sorted :p |
| 06:11 | TEttinger | ibdknox, it isn't in the announcement, but were themes removed from 0.5 of light table? |
| 06:14 | agumonkey | hello |
| 06:14 | agumonkey | i'm having issues with ordering in sets |
| 06:14 | agumonkey | (map (fn [e] e) #{:a :b :c :d}) |
| 06:15 | agumonkey | => (:a :c :b :d) |
| 06:15 | TEttinger | sets are unordered. |
| 06:15 | TEttinger | you want a sorted-set |
| 06:15 | agumonkey | so map f set will always be potentially 'random' ? |
| 06:15 | TEttinger | ,(map (fn [e] e) (sorted-set :a :b :c :d)) |
| 06:16 | clojurebot | (:a :b :c :d) |
| 06:16 | agumonkey | TEttinger: aight thanks |
| 06:16 | TEttinger | also, sorted-set-by |
| 06:16 | TEttinger | that one is handy for different sort orders |
| 06:16 | TEttinger | yours is alphabetical now |
| 06:16 | andyfingerhut | Or use regular sets, but before doing things like map on them, sort the elements with the function sort. |
| 06:16 | TEttinger | ,(map (fn [e] e) (sorted-set :a :aa :c :d)) |
| 06:16 | clojurebot | (:a :aa :c :d) |
| 06:17 | TEttinger | andyfingerhut, that too |
| 06:18 | agumonkey | is there a syntax literal that I can use with `into` ? |
| 06:18 | agumonkey | or is (apply sorted-set existing-unordered-set) idiomatic enough (if at all) ? |
| 06:19 | TEttinger | ,(into sorted-set (range 2 5)) |
| 06:19 | clojurebot | #<ClassCastException java.lang.ClassCastException: clojure.core$sorted_set cannot be cast to clojure.lang.IPersistentCollection> |
| 06:19 | andyfingerhut | There is no literal syntax in Clojure for sorted sets or maps. |
| 06:19 | TEttinger | ,(into (sorted-set) (range 2 5)) |
| 06:19 | clojurebot | #{2 3 4} |
| 06:19 | hyPiRion | ^ |
| 06:19 | TEttinger | that's as close as it gets |
| 06:20 | agumonkey | close enough |
| 06:20 | hyPiRion | also, in case you need |
| 06:20 | TEttinger | but regular sets sorted as needed also work |
| 06:20 | hyPiRion | ,(into (sorted-set-by >) #{2 3 4 5}) |
| 06:20 | clojurebot | #{5 4 3 2} |
| 06:20 | agumonkey | thanks |
| 06:30 | ciphergoth | would you use clojure.async in a live commercial application? |
| 06:31 | ro_st | probably :-) be nice for it to go out of SNAPSHOT first |
| 06:31 | hyPiRion | no, as there is still no official version out. |
| 06:31 | ciphergoth | *nods* |
| 06:34 | hyPiRion | Apart from that, I'd be all over it I assume |
| 06:35 | ciphergoth | it is very impressive! |
| 06:35 | ciphergoth | making it play nicely with aleph could be annoying |
| 07:04 | muhoo | why would you use both in a single app? |
| 07:33 | muhoo | hmm, how long does memoize keep stuff around? |
| 07:34 | mpenet | forever |
| 07:34 | mpenet | core.memoize has caching strategies |
| 07:34 | hyPiRion | until you discard the function |
| 07:43 | muhoo | ah i see, i can set it |
| 07:44 | muhoo | getting tired. now i'm trying to figure out how to nested destructure stuff, i.e. |
| 07:45 | muhoo | i have a ring req i want to take one in and get params out, like (defn foo [{:keys [{:keys [bar baz] :as params} headers] :as req}] foo) |
| 07:46 | muhoo | so basically pull out the params and headers, but also pull out the individual params as their names |
| 09:12 | [Neurotic] | seancorfield: you awake? |
| 09:30 | jamii | I remember reading something about capturing repl interactions and reusing them as regressions tests but I can't for the life of me find it again. Does anyone know what I'm talking about? |
| 09:33 | jamii | Aha - https://github.com/cgrand/replay |
| 09:45 | muhoo | [Neurotic]: i doubt it. it's 6:30am here |
| 09:45 | [Neurotic] | it was always possible ;) |
| 10:02 | edw | ,(parition 2 '(1 2 3 4 5)) |
| 10:02 | clojurebot | #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: parition in this context, compiling:(NO_SOURCE_PATH:0:0)> |
| 10:02 | edw | ,(partition 2 '(1 2 3 4 5)) |
| 10:02 | clojurebot | ((1 2) (3 4)) |
| 10:02 | edw | Does that result concern anyone? It doesn't seem to match the docs. |
| 10:04 | edw | OK, it does match the docs. |
| 10:04 | edw | Or the examples… |
| 10:05 | jkkramer | ,(partition-all 2 '(1 2 3 4 5)) |
| 10:05 | clojurebot | ((1 2) (3 4) (5)) |
| 10:05 | vijaykiran | edw: what you are looking for is partition-all |
| 10:05 | vijaykiran | ah - ask jkkramer said |
| 10:06 | edw | Ah, thank you. I was doing (parition n n nil coll), which is a bit of a PITA. |
| 10:24 | jtoy | &(doseq [x [1 2] i (take 2 (range))] (println i)) |
| 10:24 | lazybot | ⇒ 0 1 0 1 nil |
| 10:24 | jtoy | why does thta print 0 1 0 1 and not just 0 1 ? |
| 10:25 | ToxicFrog | ...how does that resolve x and i? |
| 10:25 | ToxicFrog | &[x i] |
| 10:25 | lazybot | java.lang.RuntimeException: Unable to resolve symbol: x in this context |
| 10:26 | ToxicFrog | Oh, doseq takes a binding-form. |
| 10:26 | ToxicFrog | I thought it was another dorun variant. |
| 10:27 | ToxicFrog | jtoy: because it iterates over the product of both lists. |
| 10:27 | ToxicFrog | &(doseq [x [1 2] y [3 4]] (println [x y])) |
| 10:27 | lazybot | ⇒ [1 3] [1 4] [2 3] [2 4] nil |
| 10:27 | jtoy | i just want to have an i for each item in x |
| 10:27 | jtoy | how would i do that with doseq? |
| 10:28 | agumonkey | maybe zip |
| 10:28 | ToxicFrog | So, first it iterates over the first value of x (1) and all values of i, then over the second value of x and all values of i - so each value of i shows up twice. |
| 10:28 | ToxicFrog | jtoy: what do you mean by "an i for each item in x"? |
| 10:28 | jtoy | so if i have x [ 34 78 99] i want to have an i that prints out 0 1 2 |
| 10:28 | ToxicFrog | Er |
| 10:29 | jtoy | just the step I am at in the collection |
| 10:29 | agumonkey | jtoy: always 0 1 ... ? or any value ? |
| 10:29 | ToxicFrog | so (take (count x) (range)) then? |
| 10:29 | jtoy | yes, which is what I have earlier, but i dont want the product |
| 10:29 | cmajor7 | jtoy: (map-indexed (fn [i xi] ...) [34 78 99]) |
| 10:29 | ToxicFrog | &(let [x [5 8 12 4]] (take (count x) (range))) |
| 10:29 | lazybot | ⇒ (0 1 2 3) |
| 10:29 | agumonkey | cmajor7: +1 |
| 10:30 | ToxicFrog | jtoy: "don't want the product"? |
| 10:32 | jtoy | ToxicFrog: you said earlier it itterates over the product of both? |
| 10:32 | tbaldridge | dnolen: ping |
| 10:32 | jtoy | i want to iterate through random collection with doseq but also know the position i am at |
| 10:33 | cmajor7 | jtoy: why doseq? why not map-indexed? |
| 10:33 | cmajor7 | jtoy: that does exactly that |
| 10:33 | jtoy | cmajor7: I am writing out a file and i need to put the line number |
| 10:33 | jtoy | (doseq [line lines] (write lines and line number)) |
| 10:33 | atyz | This might be silly - is there an easy way to return a realized map of a datomic entity with sub-entities (I have isComponent true). I'm in the midst of writing a function to realise them all and it feels like there should be an easier way |
| 10:34 | jtoy | cmajor7: is there a better way? |
| 10:34 | cmajor7 | jtoy: (map-indexed (fn [n line] (write (str "n:" line))) lines) |
| 10:34 | ToxicFrog | jtoy: doseq does, yes. The answer is not to use doseq. |
| 10:34 | scgilardi | atyz: does "touch" get close? |
| 10:34 | cmajor7 | (map-indexed (fn [n line] (write (str n ":" line))) lines) |
| 10:35 | jtoy | cmajor7: ok, I see, thanks |
| 10:35 | atyz | scgilardi: touch only realises the primary entity - not it's children |
| 10:38 | scgilardi | I think the intent is for it to recursively realize isComponent children. (from: https://groups.google.com/forum/#!topic/datomic/wsyvv8BCQw0 ) not sure why it wouldn't be in your case. |
| 10:41 | cmajor7 | atyz: are your "refs" are "isComponent" or something else? |
| 10:41 | atyz | scgilardi: the problem is that it realises them as a DatomicEntityMap so if I want to do any manipulation to any of the subcomponents it won't allow me to |
| 10:42 | atyz | cmajor7: isComponent true on all in question here |
| 10:42 | cmajor7 | usually [entity has "refs"], those "refs" should be "isComponent" to realize on (touch entity) |
| 10:42 | atyz | cmajor7: basically I don't want to have to use my datomic entity names in my application code |
| 10:43 | cmajor7 | atyz: why names? |
| 10:43 | cmajor7 | atyz: you only need id(s) to -> touch .. |
| 10:44 | cmajor7 | i.e. |
| 10:44 | cmajor7 | (defn entity [id] |
| 10:44 | cmajor7 | (d/entity (db-now) id)) |
| 10:44 | cmajor7 | (defn touch-id [id] |
| 10:44 | cmajor7 | (d/touch (entity id))) |
| 10:45 | cmajor7 | this of course has a "db-now" hardcoded.. if you need to touch with different db values, pass those as well.. |
| 10:45 | atyz | Oh sorry - miscommunication - the touching part works fine if you're trying to just print the data or access it. however I need to turn {:source/name "something" :sub {:sub/meh "somethingelse}} into {:name "something" :sub {:meh "somethingelse"}} |
| 10:46 | lycrgs678 | I am new to clojure. What's the most common framework used for webapps? Noir? |
| 10:46 | atyz | ** :source/sub |
| 10:46 | cmajor7 | lycrgs678: compojure |
| 10:46 | lycrgs678 | thank you cmajor7 |
| 10:46 | cmajor7 | atyz: you mean convert to "no datomic" namespace map? |
| 10:47 | atyz | cmajor7: yes |
| 10:48 | cmajor7 | atyz: yea.. looking at my code from some time ago, I have a function that does that :) |
| 10:48 | atyz | cmajor7: i would love it if you would let me look at it? :) |
| 10:48 | cmajor7 | atyz: but it is a bit logic specific |
| 10:49 | cmajor7 | atyz: trying to see if it can be cleaned up to show you. it is for a customer.. so not quite open source.. |
| 10:50 | atyz | cmajor7: ahh - it would be appreciated if you could |
| 10:50 | atyz | are you currently using your fully qualified datomic names in your code? |
| 10:51 | cmajor7 | atyz: you mean the attribute names as they are in the schema? |
| 10:51 | atyz | cmajor7: yes, sorry |
| 10:52 | cmajor7 | atyz: yes, I do, but I do the conversion, since I pack the data in protobufs before sending it elsewhere |
| 10:52 | jballanc | anyone have advice on using npm/bower libraries with Clojurescript? |
| 10:53 | cmajor7 | atyz: looking at the function, I wish I would write it now as I know a Clojure and Datomic better, otherwise I don't like my own code from 7 months ago :) it'd be easier if you give me a result of the query you want converted to a "no namespaced" map |
| 10:56 | dnolen | tbaldridge: pong |
| 10:56 | tbaldridge | dnolen: in CLJS if I have a predicate (active? foo) is negating with not going to slow things down a ton? (not (active? foo)) |
| 10:57 | tbaldridge | or can I type hint that with ^boolean to speed things up? |
| 10:57 | dnolen | tbaldridge: you don't need to negate, you can just type hint ^boolean |
| 10:58 | dnolen | tbaldridge: the only time you might negate is you're checking for nil |
| 10:58 | dnolen | tbaldridge: (if x ...) where x might be nil will emit a truth call. so (if-not (nil? x) ...) is better |
| 10:58 | tbaldridge | and (not (nil? x)) should be hinted? |
| 10:59 | tbaldridge | well here's the actual code: (and (not (nil? buf)) (pos? (count buf))) |
| 10:59 | dnolen | tbaldridge: oh you never need to hind cljs.core predicates they already are |
| 10:59 | dnolen | tbaldridge: protocols don't support type hints in Clojure is the problem with protocol methods that return boolean values |
| 10:59 | dnolen | tbaldridge: yes there's not way around that - but no need for type hints there. |
| 11:00 | tbaldridge | ok, so I should be good then. I'm re-writing core.async CLJS channels today, so far I've probably cut 25% of the code. So this is looking good. |
| 11:01 | dnolen | tbaldridge: awesome! you can always look at the simple output to know if you're doing your boolean stuff correctly |
| 11:01 | dnolen | tbaldridge: if it's right you won't get if((function() { ... }()) { ... } |
| 11:01 | tbaldridge | dnolen: kk |
| 11:01 | dnolen | tbaldridge: or if(cljs.core.truth_(x)) { ... } |
| 11:08 | wakeup | hi all |
| 11:09 | glosoli | hey |
| 11:09 | wakeup | I apparently have a LazySeq, and another seq, and I want the |
| 11:09 | wakeup | elements in seq that do not appear in LazySeq? |
| 11:10 | wakeup | clojure complains lazyseq doesn't support contains? |
| 11:10 | wakeup | how do I convert my lazyseq to a seq I can call contains on? |
| 11:11 | arrdem | wakeup: do you have bounds on the lazyseq's length? |
| 11:11 | wakeup | arrdem: its the result of map and concat so I'd say yes, its not infinite |
| 11:12 | arrdem | wakeup: I mean you can just (apply list <expression>) |
| 11:13 | arrdem | wakeup: but I contend that you should be able to perform a constant space difference operation by sequentially resolving the items of the lazy seq and testing them for membership in the hard seq. |
| 11:13 | wakeup | Ah |
| 11:13 | wakeup | I uset set and difference and it works |
| 11:17 | tgoossens | how do i get the output of pprint written into a file? |
| 11:17 | arrdem | tgoossens: you can bind *out* to a file object for one.. |
| 11:18 | tgoossens | jmm |
| 11:18 | tgoossens | *hmm |
| 11:19 | arrdem | so (binding [*out* (File. "~/my/path.dump")] (pprint <expr>)) |
| 11:19 | arrdem | ,*out* |
| 11:19 | clojurebot | #<StringWriter > |
| 11:19 | arrdem | yep. that's the var. |
| 11:19 | wolfes | Is there a way to get every namespace in a lein project to (require '[clojure.repl/pprint :as pp]) |
| 11:20 | wolfes | i figured out how to do it on init for the first namespace |
| 11:20 | wolfes | but it doesnt seem to carry over for other ns |
| 11:20 | arrdem | wolfes: no and there shouldn't be one. |
| 11:20 | arrdem | wolfes: you _can_ tell lein to automatically (require) some namespace when kicking off a repl |
| 11:21 | wolfes | repl-options init :) |
| 11:21 | tgoossens | iit doesn't write anything to the file though |
| 11:21 | tgoossens | (binding [*out* (File. "~/my/path.dump")] (pprint <expr>)) |
| 11:21 | tgoossens | oops |
| 11:22 | tgoossens | (binding [*out* (java.io.FileWriter. (java.io.File. "graph.txt"))] (pprint "hello")) |
| 11:22 | arrdem | tgoossens: (-> *out (.flush) (.close))? |
| 11:23 | tgoossens | my god |
| 11:26 | jkkramer | (with-open [f (clojure.java.io/writer "graph.txt")] (binding [*out* f] (pprint "hello"))) |
| 11:26 | jkkramer | …i think. that's untested |
| 11:26 | tgoossens | it works though... |
| 11:26 | arrdem | jkkramer: so what you're really saying is that like me you're spitting sexprs from the hip with not enough coffee |
| 11:27 | arrdem | ,0xC0FFEE |
| 11:27 | clojurebot | 12648430 |
| 11:27 | llasram | ,0xDECAFBAD |
| 11:27 | clojurebot | 3737844653 |
| 11:27 | jkkramer | yeah, too bad irc doesn't have paredit |
| 11:27 | arrdem | I kinda want to write an erc script that supports diff messages... |
| 11:28 | arrdem | so I can retroactively ammend what I've previously said :P |
| 11:35 | hyPiRion | ,36rClojurebot |
| 11:35 | clojurebot | 1279886746883501 |
| 11:36 | arrdem | hyPiRion: why 36? I'd think that 26 or 52 would be in order. |
| 11:37 | hyPiRion | ,26rClojurebot |
| 11:37 | clojurebot | #<NumberFormatException java.lang.NumberFormatException: For input string: "urebot"> |
| 11:37 | hyPiRion | ,52rClojurebot |
| 11:37 | clojurebot | #<NumberFormatException java.lang.NumberFormatException: Radix out of range> |
| 11:37 | hyPiRion | that's why |
| 11:37 | arrdem | I see the error, I don't follow the why. |
| 11:38 | cmajor7 | atyz: (defn map-walk [m] (if (map? m) (reduce (fn[a [k v]] (assoc a (-> k name keyword) (map-walk v))) {} m) m)) |
| 11:38 | cmajor7 | make sure there are no duplicates in names of different namespaces on the same level, since it is going to ignore all but last |
| 11:38 | cmajor7 | {:some/one 21 :every/one 42} => {:one 42} |
| 11:38 | atyz | cmajor7 thank you! |
| 11:39 | hyPiRion | well, base 36 is the highest supported with the r-format. 26 isn't enough because we start off with 0123456789, then the letters |
| 11:39 | TimMc | arrdem: 36 is the max radix for Java parseint. |
| 11:39 | TimMc | You get some prefix of 0-9a-z. |
| 11:39 | hyPiRion | it's like, hm |
| 11:40 | TimMc | (Somehow I missed that hyPiRion had just explained it.) |
| 11:40 | hyPiRion | ,(apply str (concat (range 10) (take 26 (map char (iterate inc (int \a)))))) |
| 11:40 | clojurebot | "0123456789abcdefghijklmnopqrstuvwxyz" |
| 11:40 | TimMc | Oh, and 52 (or 62) isn't an option because the format treats upper and lower case identically. |
| 11:41 | arrdem | TimMc: ah OK I didn't know there was an upper bound on the reader radix or that it was case insensitive :P |
| 11:42 | TimMc | &[36ra 36rA] |
| 11:42 | lazybot | ⇒ [10 10] |
| 12:24 | tbaldrid_ | dnolen: so, on my box, with the new dispatcher and channel code, I can put 1 mil messages into a (chan 1) in 3600 ms. With a (sliding-buffer 1), that drops to 328ms |
| 12:25 | bbloom | tbaldridge: but how many messages are being dropped that way? |
| 12:25 | dnolen | tbaldridge: what changes did you make to the dispatcher? |
| 12:25 | dnolen | tbaldridge: note I think my old tick idea was not good one because it ruins reasoning about buffer sizes |
| 12:25 | tbaldridge | dnolen: just the tick based ones you discussed. I added a unbounded ring buffer for the task queue, and then we run a max of 1024 tasks on each dispatch |
| 12:26 | bbloom | tbaldridge: oh nevermind, ignore my comment. misread you |
| 12:26 | TimMc | Do the size limits on the buffers guarantee an exact size, or a minimum size? |
| 12:26 | dnolen | tbaldridge: yes so I said earlier the tick idea is not good, you can lose control of buffer semantics |
| 12:26 | tbaldridge | bbloom: that's why the sliding buffer is slower, it just testing one side of the buffer |
| 12:26 | bbloom | yup gotcha now |
| 12:26 | tbaldridge | dnolen: eh, let me paste my code and see what you think |
| 12:26 | dnolen | tbaldridge: so now a buffer of size 5000 will never do what it's intended to do |
| 12:26 | coventry | What's the closest clojure has these days to CL conditions and restarts? It looks like error-kit is no longer used? |
| 12:27 | tbaldridge | dnolen: this is the new dispatcher code, it's not the same as the code you had https://gist.github.com/halgari/6321034 |
| 12:29 | tbaldridge | and that has a bug....well it's still WIP |
| 12:30 | dnolen | tbaldridge: so try this, remove the dispatcher code and try with with (chan 1024) and (chan 5000) |
| 12:30 | dnolen | tbaldridge: I'm just not convinced about putting more logic in the dispatcher anymore |
| 12:32 | tbaldridge | but think of the logic, every time we have a put/take match inside a channel we have to run the dispatcher. so (chan) will always dispatch. So that code will be super slow without a better dispatcher. |
| 12:32 | dnolen | tbaldridge: this is not a real problem |
| 12:33 | dnolen | tbaldridge: if somebody doesn't want to be dispatching all the time use a larger buffer size |
| 12:33 | dnolen | tbaldridge: also I did some numbers about common use cases of (chan) like in the interactive case, mouse input |
| 12:34 | dnolen | tbaldridge: it would take a pipeline 300 channels deeps in modern browsers before you would have a problem w/ (chan) and mouse input |
| 12:34 | dnolen | if you mouse channel pipeline is 300 channels deep something needs refactoring. |
| 12:35 | tbaldridge | so what's the penalty of using a more complex dispatcher? time to do some tests. |
| 12:35 | dnolen | tbaldridge: the penalty is (chan N) where > N 1024 |
| 12:35 | dnolen | tbaldridge: that's a show stopper in my opinion |
| 12:36 | tbaldridge | (chan N) where > N 1024 ? |
| 12:36 | dnolen | tbaldridge: you will want a fat chan if you're creating events via data, 1024 is too small |
| 12:36 | supersym | coventry: I don't know about those, the only thing that springs to mind is https://github.com/MichaelDrogalis/dire |
| 12:37 | supersym | it has some example for self-correcting code |
| 12:37 | dnolen | tbaldridge: if you have custom dispatch code you're breaking how buffered channels works, whatever N is pick is now the clamp, instead of the user defined buffer size |
| 12:38 | tbaldridge | No, with my code the semantics stay the same, we just simply run as many tasks as possible before dispatching again. So we move the task queue from the browser into user code. |
| 12:38 | dnolen | tbaldridge: hrm, looking again |
| 12:38 | tbaldridge | New dispatcher/run functions are always put at the input of the FIFO queue. |
| 12:39 | dnolen | tbaldridge: ok how does this not break (chan) ? does that mean I need 1024 mouse events before another go block gets to run ? |
| 12:39 | dnolen | a go block which might be consuming those events? |
| 12:41 | dnolen | tbaldridge: note the browser will emit at most ~160 mouse events a second |
| 12:43 | tbaldridge | dnolen: nope, it doesn't break. the mouse event put!s into the chan and ends up in the puts queue, pending takes are dispatched, if there are no pending takes, then the mouse events pile up in the take queue. |
| 12:44 | tbaldridge | *pile up in the put queue |
| 12:44 | coventry | supersym: Thanks, looking now. |
| 12:44 | dnolen | tbaldridge: dispatched? but won't it just end up in the dispatch queue instead of running immediately? |
| 12:44 | bbloom | for some reason my irc client has changed tbaldridge's handle from red to green, which now matches dnolen's, making it impossible to follow this discussion :-) |
| 12:45 | dnolen | tbaldridge: ok sorry I reading more closely now |
| 12:46 | tbaldridge | they don't run immediately with the old code either. the callback you get back from a impl/put! is the same callback you handed to impl/put! not the take's callback |
| 12:46 | tbaldridge | so dispatch is always run against "the other guy" |
| 12:46 | dnolen | tbaldridge: I see now, you're accounting for more stuff that might appear between dispatches |
| 12:46 | tbaldridge | right |
| 12:47 | dnolen | tbaldridge: hey pretty cool :) |
| 12:47 | dnolen | tbaldridge: if the ring buffer is 32 how could you ever reach 1024? |
| 12:47 | tbaldridge | I got one nasty bug to fix, but then I'll throw this all up in a branch and see where what you all think. I've also added .unbounded-unshift that resizes a ring-buffer if it runs out of space. |
| 12:48 | dnolen | tbaldridge: ok I get it now |
| 12:48 | tbaldridge | so each time it runs out of space, it'll double in size |
| 12:48 | dnolen | tbaldridge: unbounded-shift was the missing part for me |
| 12:48 | dnolen | tbaldridge: looks cool, will try it when you get it up |
| 12:52 | coventry | supersym: dire looks awesome. I'm more interested in the restart side of the condition/restart system though. Something which will return the full stack at the point an exception occurs, rather than the stack in the catch/finally clause. |
| 12:53 | dnolen | tbaldridge: so do the takes/puts in ManyToManyChannel use ring buffers now too? |
| 12:53 | tbaldridge | dnolen: yes |
| 12:53 | dnolen | tbaldridge: sweet |
| 12:54 | tbaldridge | "ring buffer all the things!" |
| 13:03 | konr` | Is there a protocol for objects that implement toString? |
| 13:04 | dnolen | konr`: for CLJS? |
| 13:04 | konr` | dnolen: regular CLJ |
| 13:04 | dnolen | konr`: that would be Object |
| 13:04 | dnolen | konr`: no protocol |
| 13:05 | konr` | dnolen: hmmm, didn't know of that! |
| 13:05 | dnolen | konr`: also for equals and hashCode |
| 13:06 | dnolen | konr`: this means this can only be done in deftype, you can extend-type this stuff |
| 13:06 | dnolen | s/can/cannot |
| 13:06 | supersym | coventry: ok, don't know any that does, soz |
| 13:06 | dnolen | konr`: doesn't work w/ defrecord since those things are provided for you |
| 13:06 | dnolen | " this means this can only be done in deftype, you cannot extend-type this stuff" |
| 13:06 | coventry | Supersym: no worries |
| 13:11 | tbaldridge | dnolen: here's the code: https://github.com/clojure/core.async/tree/tims-optimizations |
| 13:13 | dnolen | tbaldridge: I leave some comments (minor boolean related stuff) |
| 13:13 | tbaldridge | kk |
| 13:17 | bbloom | tbaldridge: total nitpick, but there's really no need for "constants" to be IN-ALL-CAPS |
| 13:17 | bbloom | i mean, *everything* is supposed to be immutable, right? :-) |
| 13:17 | tbaldridge | bbloom: but, but, that's the way it's done in C :-P |
| 13:18 | bbloom | tbaldridge: right, but in cleff i had to do COMMUNICATION-IDX to match what you did & i felt dirty :-P |
| 13:18 | dnolen | tbaldridge: ok little perf comments added |
| 13:18 | tbaldridge | bbloom: I'm sorry that I make you feel dirty. lol |
| 13:18 | bbloom | tbaldridge: you're forgiven, but only b/c the code is otherwise quite clean |
| 13:19 | dnolen | tbaldridge: looks pretty nice, after those changes I'll give it a run around |
| 13:20 | tbaldridge | dnolen: kk I'll get it updated |
| 13:22 | mdrogalis | coventry: I'm around if you need help with it. |
| 13:26 | wei_ | how can I make (pr-str (org.bson.types.ObjectId. "5217512f3b7e53472217ea65")) return an EDN-readable format? i.e. #"ObjectId" "5217512f3b7e53472217ea65" |
| 13:27 | mdrogalis | wei_: What datatype do you want it to coerce to in EDN? |
| 13:27 | wei_ | a str |
| 13:27 | stuartsierra | wei_: define a new method for print-method. |
| 13:27 | wei_ | I'm trying to serialize mongo objects for use in clojurescript |
| 13:28 | tbaldridge | dnolen: done |
| 13:31 | lynaghk | dnolen: ping |
| 13:31 | dnolen | lynaghk: pong |
| 13:31 | lynaghk | dnolen: what are your thoughts on Polymer/WebComponents? |
| 13:31 | dnolen | lynaghk: not particularly positive |
| 13:31 | wei_ | @stuartsierra could you elaborate a bit? I'm not understanding the print-method example |
| 13:32 | lynaghk | dnolen: yeah, I thought it was something like that (via a few of your tweets) |
| 13:32 | lynaghk | dnolen: is there anything in particular that you think is a bad idea? |
| 13:32 | stuartsierra | wei_: (defmethod clojure.core/print-method org.bson.types.ObjectId [oid writer] …) |
| 13:33 | dnolen | lynaghk: my experience with every UI system just tells me the assumptions present in Polymer are deeply flawed |
| 13:33 | wei_ | i see, thanks. does that activate globally? |
| 13:33 | lynaghk | dnolen: there are some usual Clojurist things I'm not a fan of (e.g., implementation inhertance of components), but the general idea of trying to package up reusable components as new tags seems like a sound one to me---at least, it's a continuation of what browsers are already. |
| 13:34 | lynaghk | dnolen: those assumptions being? |
| 13:34 | dnolen | lynaghk: what's the value over jQuery UI or other widget libraries? |
| 13:34 | lynaghk | dnolen: declarative markup; that something lower level is handling initialization for you |
| 13:35 | lynaghk | rather than a shitshow main() method that is tightly coupled to IDs/classes. |
| 13:35 | patchwork | dnolen, lynaghk: From what I have heard of this, the advantage is the nested definition of components |
| 13:35 | dnolen | lynaghk: so you really don't believe Polymer is not going to result in a shitshow? |
| 13:36 | wei_ | lynaghk: is this related to your quest for finding the perfect data binding solution for webapps? |
| 13:36 | lynaghk | I'm not sure how I feel about the "bang-on-the-view-model" approach of WebComponents/Angular.js, but I'm not sure what a more functional approach would look like |
| 13:36 | dnolen | lynaghk: this has all been done before, we know what the results look like |
| 13:37 | lynaghk | dnolen: the UI situation on the web right now is a shitshow, and polymer/angular seem like an improvement to me over the defacto main() method approach |
| 13:37 | dnolen | lynaghk: I don't see how Polymer will be an improvement beyond anything surface level |
| 13:37 | dnolen | lynaghk: it solves two small things, but people will still make shitty components |
| 13:37 | bbloom | lynaghk: check out react.js |
| 13:38 | lynaghk | dnolen: you could use some of the good ideas of polymer in conjunction with core.async coordination |
| 13:38 | dnolen | lynaghk: implementation inheritance will be monstrosity |
| 13:38 | lynaghk | dnolen: totally |
| 13:38 | Anderkent | core.async question: does alts! busy loop until a channel is available? It seems so from eye-balling the code (ioc-alts! never returns nil, always either result or :recur). The docs say it will park though... |
| 13:38 | dnolen | lynaghk: if that's the way the current is flowing - not much you can do about it but I just don't really care that much. |
| 13:38 | lynaghk | bbloom: react.js doesn't seem to have a good story about separating markup from behavior |
| 13:39 | dnolen | lynaghk: also I find the markup parts very suspect |
| 13:39 | coventry | mdrogalis: Thanks. |
| 13:39 | dnolen | lynaghk: does the spec allow you replace w/ whatever you want? |
| 13:39 | lynaghk | dnolen: the notion of being able to create custom tags with their own styling and behavior? |
| 13:40 | dnolen | lynaghk: I mean how flexible is it, is it easy to break components if I add my own attributes, if I embed some subview etc. |
| 13:40 | bbloom | lynaghk: in what way do you want to separate markup from behavior? it strikes me as a strange idea that you even can strictly separate structure from behavior. doesn't behavior require some structure to operate on? |
| 13:40 | dnolen | lynaghk: or is this something they expect people mess up as usual? |
| 13:41 | lynaghk | dnolen: it's certainly more flexible/composable than something like jQuery UI---all of those things expect to get an element that they can totally own and clobber without any thought to composability |
| 13:41 | jtoy | how does one process a pair of items from 2 collections at the same time? |
| 13:42 | jtoy | so if i had [1 2 3 ] [4 5 6] i could get 1,4 and 2,5 and 3,6 ? |
| 13:42 | lynaghk | bbloom: you definitely need some structure, but you should be able to do that in the HTML and not have to do it in the JS. |
| 13:42 | technomancy | ,(map vector [1 2 3] [4 5 6]) |
| 13:42 | clojurebot | ([1 4] [2 5] [3 6]) |
| 13:42 | bhauman | Anderkent: blocks inside of a go block. |
| 13:42 | dnolen | lynaghk: so then my concern is the value proposition is very small - with some resoundingly bad OO ideas baked in |
| 13:43 | bhauman | Anderkent: as far as I know it's reactive |
| 13:43 | lynaghk | bbloom: that all of the react.js examples I've seen have lots of HTML-in-strings-in-JS gives me the idea that it'll be very hard to build, e.g., a <tabs showing="idx"> <tab>...</tab> <tab>...</tab> </tabs> kind of component |
| 13:43 | lynaghk | dnolen: I agree with you about the OO ideas 100% |
| 13:44 | lynaghk | dnolen: re: value of building custom tags, it's by far the most composable approach I've seen thus far in the web UI world. |
| 13:44 | jtoy | thx |
| 13:44 | lynaghk | especially w.r.t. collaborating with designers |
| 13:44 | bbloom | lynaghk: there are no HTML-strings-in-JS. they have an *optional* javascript preprocessor that converts XML literals into data construction calls |
| 13:44 | dnolen | lynaghk: I just think it's all very short sighted. Looking forward who cares about the DOM, we need/want to abstract UI components over SVG, Canvas, WebGL |
| 13:45 | Anderkent | bhauman: so from doing it on the repl it seems it doesn't busy loop, but I can't see how that happens from the code. ioc-alts! calls do-alts, which eitehr says 'i read you a value' or returns nil if no channel has anything... ioc-alts! either advances the state machine in the first case, or returns :recur in the latter... Recur just makes the thread loop into ioc-alts! again as far as I can see. |
| 13:45 | dnolen | lynaghk: instead we're gonna get desktop UI thinking all over again, do not want |
| 13:45 | bbloom | dnolen: agree w/ that |
| 13:45 | lynaghk | dnolen: the DOM *is* abstract UI components! |
| 13:45 | dnolen | lynaghk: so how will your Polymer component work in WebGL? |
| 13:45 | dnolen | it won't |
| 13:46 | bbloom | lynaghk: well, only if you allow custom dom elements to be created |
| 13:46 | dnolen | you'll replicate all the crap for a different surface |
| 13:46 | patchwork | dnolen: Abstracting over SVG, Canvas or Webgl you still need an approach to designing them! |
| 13:46 | lynaghk | patchwork: yes! |
| 13:46 | lynaghk | dnolen: you mean building out a full UI that renders in WebGL? |
| 13:46 | jtoy | is there a cleaner way to write this: (map first (filter #(= (last %) 1) (map vector candidates results))) |
| 13:46 | patchwork | The philosophy behind how to design a UI is independent of what it is implemented in |
| 13:46 | bhauman | Anderkent: you are far deeper into it, than I am. i only know from experience that it doesn't loop. But do you have any luck expanding the go macro |
| 13:46 | dnolen | patchwork: Polymer doesn't do this |
| 13:47 | dnolen | lynaghk: UI components are processes not what they look like |
| 13:47 | patchwork | dnolen: Right, but how would you do that? |
| 13:47 | dnolen | patchwork: read my core.async posts |
| 13:47 | cespare | jtoy: well for starters instead of (first (filter you can use find-first |
| 13:47 | patchwork | The question is: What is the best way to design a UI? |
| 13:47 | patchwork | dnolen: I'll check them out. core.async for UI? |
| 13:47 | dnolen | patchwork: yep |
| 13:47 | jtoy | cespare: that is different |
| 13:47 | dnolen | patchwork: http://swannodette.github.io/ |
| 13:47 | sjl | cespare: it's (map first (filter not (first (filter |
| 13:47 | jtoy | i am mapping out the first item |
| 13:47 | Anderkent | bhauman: that's what I did, and I can't see how it returns control - even though I know it does. Perhaps I should put prints into the expanded form :P |
| 13:48 | lynaghk | dnolen: yes, agreed. So with polymer you can define something like <my-button with="arguments"> and style it independently. |
| 13:48 | cespare | jtoy: sorry misread |
| 13:48 | dnolen | lynaghk: but people are going to write logic that targets DOM |
| 13:48 | dnolen | FAIL |
| 13:48 | bhauman | Anderkent: did you see the post explaining the state machines? |
| 13:48 | bbloom | dnolen: you can't say that's FAIL, there are different goals |
| 13:48 | lynaghk | dnolen: if you're saying that polymer isn't great because you can't take it and render it in WebGL, that's not something I'm very concerned about. |
| 13:48 | Anderkent | bhauman: yes. That's where my investigation started |
| 13:48 | Anderkent | I saw the ioc-alts! code and said 'wait a moment this busy loops |
| 13:49 | dnolen | lynaghk: that's not what I'm saying |
| 13:49 | lynaghk | dnolen: (also, if you do things correctly I don't see why you wouldn't be able to take the HTML + CSS and write a WebGL renderer) |
| 13:49 | bbloom | lynaghk: seriously though, go look at react.js. it's much more functional than it is OOP, in fact, it's only as OOP as javascript forces on it |
| 13:49 | jtoy | cespare: it looks bad to me because i do a transformation, filter, then another transformation |
| 13:49 | dnolen | lynaghk: people are going to deliver what could be reusable logic, but it won't be reusable |
| 13:49 | lynaghk | bbloom: noted, I'll take a deeper look at it |
| 13:49 | dnolen | lynaghk: you can only use it with Polymer |
| 13:49 | bbloom | lynaghk: polymer is yet another smalltalk-legacy MVC OOP mess |
| 13:49 | bbloom | lynaghk: react.js looks kinda OOP & demos poorly b/c it seems like it's similar to what you've seen before |
| 13:49 | bhauman | Anderkent: well you are inspiring me to finally take a look at it. |
| 13:50 | Anderkent | it's pretty good |
| 13:50 | Anderkent | just don't start reading large blocks that he pastes in here and there |
| 13:50 | lynaghk | dnolen, bbloom: Again, I'm not 100% sold on polymer---it's just the best concrete thing I'm aware of right now. If you guys can point to other systems (or even whitepapers with pseudocode) I would love to see 'em |
| 13:50 | bbloom | lynaghk: but in reality, it works with *data* & external state. it hydrates instances on demand, memoizes functional rendering output, then incrementally mutates the dom, treating it as an external database |
| 13:50 | bhauman | Anderkent: I have been a happy incurious, consumber |
| 13:50 | Anderkent | I did that, spent 10 minutes parsing some sophisticated code, and then saw that he goes through it expression by expression below that |
| 13:50 | Anderkent | :D |
| 13:51 | bbloom | lynaghk: the majority of your components are stateless & their instances are not retained in memory except when necessary during rendering |
| 13:51 | bbloom | lynaghk: stateful components are OOP only in the sense that they can respond to events in a traditional manner & have some state. but that state isn't stored in the object, it's stored in a global database & referenced by ID. you can't communicate between components except via parameterization |
| 13:52 | lynaghk | bbloom: don't you think many UI components need state? E.g., selected items in a list? |
| 13:52 | bbloom | lynaghk: yes, i do think that. which is why i like react's approach |
| 13:53 | lynaghk | bbloom: aren't polymer components attributes the parameterization you're describing? |
| 13:53 | sjl | cespare: I |
| 13:53 | bbloom | lynaghk: components are built up of 1) types (which are == the classes of the objects / custom element names) 2) "parameters" which are like arguments to the render function 3) children, which is the result of rendering 4) an optional state json object, which can be used to update params or children during the next render pass |
| 13:53 | sjl | 'd probably do something like (for [[c r] (map vector candidates results) :when (= r 1)] c) |
| 13:54 | bbloom | lynaghk: it feels similar to writing a server-side rendering with a templating language, only you can associate state & event handlers with components |
| 13:54 | sjl | and use (zip ...) from flatland/useful instead of (map vector ...) |
| 13:54 | Anderkent | bhauman: ah, I'm an idiot. in ioc-alts! I misread a `when-let` for an `if-let` |
| 13:54 | Anderkent | that's disappointing |
| 13:54 | bbloom | lynaghk: instead of inheritence, you just create lots of small, generally stateless components, which are similar to helper functions |
| 13:54 | lynaghk | bbloom: what triggers re-rendering? Is there a dirty-checking loop like angular, an ordered dependency graph like flapjax, or straight up callbacks on individual properties? |
| 13:55 | Anderkent | .. I'm gonna grab a beer. |
| 13:55 | tbaldridge | dnolen: there's a odd race condition I'm working through may not want to test this quite yet. |
| 13:55 | bhauman | Anderkent: no don't do that it won't help |
| 13:55 | dnolen | tbaldridge: ok |
| 13:55 | bhauman | Anderkent: :) |
| 13:55 | bbloom | lynaghk: it's similar to angular, but where angular diffs the view model, react diffs the views |
| 13:56 | Anderkent | bhauman: going home anyway :P |
| 13:56 | Anderkent | thanks for the help |
| 13:56 | lynaghk | bbloom: I thought the only state was in a JSON object |
| 13:56 | bbloom | lynaghk: it's a transactional model, like clojure. you have a database of components+state, when events fire, things react to them & commit new state. the components can not mutate each other's state nor can they even see the effects of their state changes. after each component gets a chance to react to events, which happen in a synchronous pass, then all the differing state triggers cascading re-renders |
| 13:56 | bhauman | Anderkent: enjoy, don't think I helped but it was good chatting. |
| 13:56 | lynaghk | bbloom: I do like that react.js and polymer both have TodoMVC entries = ) |
| 13:56 | cespare | sjl: jtoy how about (keep-indexed #(if (= (results %) 1) true) candidates) |
| 13:57 | cespare | sjl: jtoy sorry i mean (keep-indexed #(if (= (results %) 1) %2) candidates) |
| 13:57 | bbloom | lynaghk: i think it's extended JSON, like you can have dates in there, just like in angular, you can store anything you can diff |
| 13:57 | dissipate | what is the 'best practices' rule of thumb for destructuring expressions? it seems like those can get out of hand |
| 13:57 | xiaq | clojurebot: how do i play with you? |
| 13:57 | clojurebot | Huh? |
| 13:57 | xiaq | clojurebot: $help |
| 13:57 | clojurebot | Excuse me? |
| 13:57 | xiaq | clojurebot: @help |
| 13:57 | clojurebot | Gabh mo leithscéal? |
| 13:57 | bbloom | lynaghk: dnolen argues correctly that react & polymer are both DOM-centric, but i think that react's model is a deeply functional approach under the hood |
| 13:57 | lynaghk | bbloom: interesting. I'm going to dig through it and Polymer's TodoMVCs. Maybe a blog post will come out of this. |
| 13:58 | lynaghk | or, god help me, some ClojureScript sketches = ) |
| 13:58 | bbloom | lynaghk: dnolen: i've been on-and-off-again working on a underlying-tech-agnostic UI toolkit that has a lot in common w/ react's underlying model |
| 13:58 | lynaghk | bbloom: yeah, the bits of angular/polymer I'm excited about are the DOM integration, not the OO/mutation stuff. |
| 13:59 | bbloom | lynaghk: angular is nice, but you have to write a lot of crazy directive stuff for larger apps & reusable components. react & polymer make modularity the default, but polymer goes full OOP & react goes full memoizing pure render functions w/ a transactional update pass |
| 14:01 | lynaghk | bbloom: interesting summary. Thanks for bringing React to my attention. I'll dig 'round and try to figure out the best ideas to steal for use with cljs |
| 14:02 | bbloom | lynaghk: note that react doesn't bother trying to integrate w/ the dom. there are no actual custom tags reified at runtime b/c there is no value in that. there is no browser-level shadow dom or anything like that |
| 14:02 | dnolen | lynaghk: I also think the initialization stuff is not good |
| 14:03 | sjl | cespare: if results is a vector or somthing that supports effecient acces by index, that will work |
| 14:03 | dnolen | lynaghk: I'm leaning towards a model where widget sitting around in memory never happens, only processes over them that appear or disappear as required which is as it should be in my opinion. |
| 14:03 | sjl | cespare: that also assumes you don't have a candidate, result pair of nil 1 |
| 14:04 | sjl | in which case it wouldn't return the nil properly |
| 14:04 | dnolen | lynaghk: basically I'm done w/ the last 8 years of stuff I've done on the web, Polymer is just more of the same to me in everyway. |
| 14:04 | bbloom | dnolen: that's exactly how react works |
| 14:04 | dissipate | dnolen, what do you mean you are 'done' with it? |
| 14:04 | lynaghk | bbloom: wahhhh, I'm confused now. There is so much value in a shadow DOM and custom tags |
| 14:05 | bbloom | lynaghk: there is value in custom tags, there is no value in reifying them for the browser to inspect |
| 14:05 | dnolen | dissipate: no longer interested in putting any more brain time into that style of programming. |
| 14:05 | bbloom | dnolen: react does not instantiate or retain widgets in memory |
| 14:05 | lynaghk | dnolen: yeah, I know you've been in the space for a while, which is why I'm interested in your opinion on these matters |
| 14:05 | bbloom | dnolen: if you widgets have state, then that state is stored in a global widget-id => state map |
| 14:05 | lynaghk | dnolen: sometimes I need to get pulled by the nose for a while before I can see the light, though = ) |
| 14:06 | bbloom | dnolen: if an event is fired, the object is only instantiated to maintain a javascript-style developer experience. it's about as far from OOP as you can actually get. each object is more like a go-loop which responds to a message & keeps it's state as a loop argument |
| 14:06 | dissipate | dnolen, the web SUCKS. that's my opinion |
| 14:07 | dnolen | bbloom: yes, I still need to look at React (after grokking ANF ;), I've been thinking about a core.async AppState thing |
| 14:07 | lynaghk | dnolen, bbloom: I gotta run right now though. Thanks for all of the good ideas. |
| 14:07 | dissipate | how many more language X to javascript compilers do we need? |
| 14:07 | dnolen | dissipate: heh, I think the web is awesome, CLJS is a good model to reign in the monster |
| 14:08 | dissipate | dnolen, the web is broken as is the industry of 'web programming' |
| 14:09 | dnolen | dissipate: not any more than anything I've used - mainstream desktop / server programming looks equally gnarly to me. |
| 14:09 | dnolen | dissipate: I think browser stuff aside, the reason people don't like web programming is that people are doing distributed system programming with crappy tools. |
| 14:09 | bbloom | everything sucks and no one cares! |
| 14:09 | dissipate | dnolen, all these highly caffeinated 'brogrammers' who think MVC is an architecture. have you ever seen Uncle Bob's stuff? http://www.youtube.com/watch?v=asLUTiJJqdE |
| 14:09 | bbloom | :-) |
| 14:10 | wink | no software is better than no software. |
| 14:11 | wink | best quote from puppetconf :P |
| 14:11 | dissipate | dnolen, on the desktop you can pick your language, your architecture and whatever else. in the browser, you are trapped with HTML, CSS, javascript. that's bad |
| 14:11 | patchwork | dissipate: What is an architecture in your opinion? |
| 14:11 | bbloom | dissipate: you're preaching to the choir regarding choice of superior tools in the browser |
| 14:11 | patchwork | Also, that is what cljs is trying to solve |
| 14:12 | technomancy | http://www.buildingkeystones.com/wp-content/uploads/2012/03/no-software.jpg |
| 14:12 | technomancy | whatever that means |
| 14:12 | dissipate | patchwork, the underpinnings of your software design. the 'stuff' that is not easily changed. |
| 14:12 | bbloom | technomancy: lol that's salesforces logo |
| 14:12 | technomancy | bbloom: still the deeper meaning is a mystery to me |
| 14:13 | bbloom | technomancy: clearly you haven't met the mascots: http://static3.businessinsider.com/image/4e65b08569bedd144500006f-480/salesforce-no-software.jpg |
| 14:13 | bbloom | that's "chatty" the salesforce chatter mascot in the background there. he's a big red smiley face |
| 14:13 | bbloom | :-) |
| 14:13 | patchwork | dissipate: Since the real world constantly demands change of software, could architecture be a liability then? |
| 14:13 | dissipate | patchwork, have you seen any of uncle bob's stuff? |
| 14:14 | dissipate | patchwork, no, not at all. a good architecture let's you swap out technologies like web frameworks, databases etc. |
| 14:14 | patchwork | So then, the architecture is the backbone that allows other things to change |
| 14:14 | dissipate | patchwork, correct |
| 14:14 | dissipate | patchwork, see this on clean architecture: http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html |
| 14:15 | patchwork | Until your architecture becomes the thing preventing some kind of change : ) |
| 14:15 | patchwork | dissipate: I have not heard of uncle bob, I'll check it out. Thanks |
| 14:16 | dissipate | patchwork, he has a lot of material on clean code and clean architecture. he is also a proponent of Clojure. |
| 14:16 | wink | I haven't read the whole thing, but what I saw of Clean Coder was not so awesome |
| 14:17 | dissipate | wink, not sure about that book, but 'Clean Code' seems to be good |
| 14:17 | patchwork | Got it, so he is preaching separation of concerns |
| 14:17 | patchwork | Any static thing can be made dynamic by adding a new level of indirection : ) |
| 14:17 | patchwork | The Law of Code |
| 14:18 | wink | dissipate: maybe I'm mixing it up, but it was this whole "you have to hone your skills even after going home from your 40+h job" - and I say that as someone who lists programming as a huge hobby |
| 14:18 | wink | dissipate: plus a little know-it-all tone. but as I said, I haven't read both books cover to cover |
| 14:18 | bhauman | technomancy: bbloom: they keep using that word, but clearly they do not know ... |
| 14:19 | patchwork | So the architecture always becomes the base of the tree, it is by definition the thing that cannot change. Or rather, what still has not been granted a level of indirection that allows it to change |
| 14:19 | dissipate | patchwork, no, it can change, it's just more work |
| 14:20 | dissipate | wink, yeah, i didn't really agree with that part |
| 14:20 | dissipate | wink, professionals in other industries aren't expected to study after work |
| 14:21 | dissipate | wink, but the problem is what do you do if your shop is using bad languages and technologies? in that case, it is in your interest to study outside of work and try to find a better shop |
| 14:21 | dissipate | for instance, if i worked a java shop, i would work like hell to GTFO of that place |
| 14:23 | dissipate | patchwork, the 'clean' layered architecture approach has the rule of thumb that you put the stuff that changes more often on the outside layers and the stuff that changes the least often in the inside layers |
| 14:23 | wink | dissipate: yeah of course. but that's intent to grow immensely beyond your current gig. not saying that's a bad thing, but a special case |
| 14:24 | dissipate | patchwork, do you agree that 99% of software out there is a big ball of mud? especially web stuff... |
| 14:25 | patchwork | dissipate: I haven't seen 99%! I have seen like 0.001 % |
| 14:25 | patchwork | And yeah, most of it grew from humble beginnings far beyond its original scope |
| 14:25 | dissipate | patchwork, extrapolate from a statistical sample. :P |
| 14:25 | jonasen | Here’s a (demo)project of mine I’ve been working on for a while: http://cljsfiddle.net |
| 14:26 | jonasen | It’s very (very!) alpha still so don’t expect too much :) |
| 14:26 | patchwork | dissipate: knowing how it is going to change beforehand is hard. I have also seen projects set up an architecture they never ended up needing, then growing in another direction and becoming a ball of mud anyway |
| 14:26 | seangrov` | jonasen: This is a great idea! |
| 14:27 | patchwork | To truly design software well you have to see what you will need in the future |
| 14:27 | patchwork | Since this is impossible in practice, most software is gangly and obtuse |
| 14:27 | jonasen | Note that it'll be quite slow the first time you run a program, after that it will hopefully be a fast edit/run cycle thanks to http caching. Also, I'm only running an in-memory db for now so don't expect your work to be saved for long. |
| 14:27 | muhoo | i seee..... lines of code.... requirements changing constantly out from under you.... |
| 14:27 | benkay | jonasen++ |
| 14:27 | patchwork | muhoo: You really can see the future! |
| 14:28 | jonasen | a more advanced example: http://cljsfiddle.net/fiddle/jonase.bezier |
| 14:28 | dissipate | patchwork, and why doesn't this happen in other industries like mechanical engineering? |
| 14:28 | jonasen | seangrov`: benkay: thanks |
| 14:28 | dissipate | or electrical engineering for that matter |
| 14:28 | muhoo | it does happen in mechanical and electrical engineering |
| 14:28 | benkay | jonasen now implement nrepl.el keybindings |
| 14:28 | benkay | jk jk |
| 14:28 | dissipate | if one's designs were a big ball of mud, they would get thrown out, in those industries, no? |
| 14:28 | muhoo | it's slow-motion mud |
| 14:28 | patchwork | dissipate: Because no one comes along and changes the design of the bridge after its built |
| 14:28 | seangrov` | benkay: Yeah, the editor could probably use a touch of work :) |
| 14:29 | seangrov` | Very smart though |
| 14:29 | seangrov` | Well done! |
| 14:29 | muhoo | change is expensive and slow in hardware and mechanical. |
| 14:29 | benkay | dissipate: naw, man. you just hire more grunts to put the stuff together better. |
| 14:29 | benkay | dissipate: or you hire more grunts to test the stuff more rigorously |
| 14:29 | patchwork | The bridge is there now, people accept it can't change |
| 14:29 | benkay | dissipate: i left for many many reasons |
| 14:29 | dissipate | patchwork, things change in electrical and mechanical engineering. |
| 14:30 | dissipate | benkay, from which industry? |
| 14:30 | patchwork | dissipate: Sure, but not after the project is built. |
| 14:30 | patchwork | The designs change |
| 14:30 | muhoo | yes, after it's built. rev 2. rev 3, green wire and dead bugs haging off the board. |
| 14:30 | jonasen | benkay: heh, that'll have to wait |
| 14:30 | benkay | multiphysics engineering |
| 14:30 | benkay | dissipate: multiphysics engineering |
| 14:31 | patchwork | muhoo: Well sure, they change it as much as it can. But bridges are far less adaptable than software |
| 14:31 | dissipate | patchwork, you aren't disturbed at all by the fact that the average CS grad has no notion of software craftsmanship, or very little? and especially no notion of architecture. they got their degree by banging out code over long nights that none of their TAs can properly review because they went through the same program. |
| 14:31 | muhoo | it's just a slower, more expensive process |
| 14:31 | muhoo | speed and cost make people more careful :-) |
| 14:31 | benkay | big-ish and small-ish systems for http://cascademicrotech.com among others, dissipate |
| 14:31 | patchwork | If you could modify a bridge as easily as you modify some code, we would see some horrific things |
| 14:31 | dissipate | benkay, and you left the industry because? |
| 14:31 | patchwork | You would see software level horror in bridge form |
| 14:32 | benkay | i left the industry for a multitude of reasons, dissipate. |
| 14:32 | benkay | speed of innovation |
| 14:32 | benkay | capital requirements for everything |
| 14:32 | boodle | I have a ring app I'm trying to deploy that uses jdbc mysql and sqlserver drivers.. I'm clueless on java and running into this: http://stackoverflow.com/questions/14977228/creating-an-uberjar-for-a-project-that-uses-mysql-and-sqlserver |
| 14:32 | benkay | mean reversion on teams |
| 14:32 | dissipate | benkay, so you do clojure software development now? |
| 14:33 | benkay | no beer in offices because you can't get insurance if your line operators have access to alcohol on-shift, and providing alcohol to the engineers makes the eng/prod split even worse |
| 14:33 | loliveira | .mt |
| 14:33 | benkay | i do cloud operations. clojure is involved. |
| 14:34 | dissipate | benkay, i see. seems like out of the frying pan into the fire. but i guess that's just my perspective. |
| 14:35 | benkay | writing code and managing boxen in service of increasing scale of problems i and my fellas can tackle sanely. |
| 14:35 | dissipate | at least you get to use clojure. so few clojure shops out there. |
| 14:35 | benkay | "mean reversion of teams" |
| 14:35 | benkay | i'm a snob. |
| 14:35 | seangrov` | dissipate: We're (probably) hiring two people who don't know clojure, they're happy to learn it |
| 14:35 | seangrov` | Plenty of places hiring developers |
| 14:35 | benkay | i don't have to design machines in such a way that operators can't rip their fingers off. |
| 14:35 | benkay | that's a net win. |
| 14:35 | seangrov` | Err, hiring developers to code in clojure |
| 14:36 | patchwork | dnolen: I am enjoying the CSP articles. Thanks for sharing |
| 14:36 | dissipate | seangrov`, you aren't worried how long it is going to take them? i'm coming from imperative languages and this is completely different stuff for me. :P |
| 14:36 | dnolen | patchwork: np |
| 14:37 | patchwork | dnolen: Have you built any large UI's with this approach? |
| 14:37 | dissipate | benkay, how long did it take you to make the transition? |
| 14:37 | patchwork | curious how it scales |
| 14:37 | seangrov` | dissipate: They have good skills and experience. I expect it to be a few weeks before they're up to speed and productive |
| 14:38 | benkay | dissipate: 9 months. |
| 14:38 | dissipate | seangrov`, a few weeks?? wow. someone told me it takes about a year to get comfortable with Haskell. Clojure isn't as bad, so cut that in half to maybe 6 months? a few weeks sounds cray |
| 14:38 | benkay | 6 before i was self-sufficient as a consultant |
| 14:39 | benkay | 9 total before i was useful in someone else's organizatino |
| 14:39 | dnolen | patchwork: nope since I'm still learning it, but the autocompleter is a convincing non-trivial example in IMO |
| 14:39 | dissipate | benkay, wow, that's pretty quick. that's cool |
| 14:39 | benkay | but that's 9 months of 70+ hr weeks working and studying the computation stack. |
| 14:39 | dnolen | patchwork: much cleaner than other similar things I've build in the past and more flexible |
| 14:40 | benkay | granted i wasn't starting from scratch, i had a fair amount of experience in simulation and control system design and implementation. |
| 14:40 | dissipate | benkay, OpenStack? |
| 14:40 | benkay | dissipate: what about it? |
| 14:40 | seangrov` | dissipate: The ideas are already their in other languages, they're just expressed more succinctly in clojure. Takes time to understand, and I expect they'll be putting in time like benkay, but it's a matter of self-improvement |
| 14:40 | dissipate | benkay, is that what you are using or are you on AWS or a third party cloud provider? |
| 14:40 | benkay | ah. |
| 14:41 | benkay | client dependent. |
| 14:41 | benkay | the client that i've been working with the most for the past 5 months is actually a bare-metal shop |
| 14:41 | benkay | >.< |
| 14:41 | patchwork | dnolen: Haven't gotten to the autocompleter yet, I'll check it out. |
| 14:41 | benkay | i wasn't involved in those discussions. |
| 14:41 | patchwork | dnolen: Seems like you would still have to have somewhere to store and access all the channels in a non-gnarly way |
| 14:42 | dnolen | patchwork: no |
| 14:42 | dissipate | seangrov`, personally, i haven't found anything quite like macros in other languages. |
| 14:42 | seangrov` | dissipate: Meh, reader macros are even crazier :) |
| 14:42 | dnolen | patchwork: you don't store channels anywhere |
| 14:42 | dnolen | patchwork: you wire things together but calling functions |
| 14:42 | benkay | but generally speaking, openstack is overkill for most clients. a simple cloud instance spinup script and provisioning tool serves most totally sufficiently. |
| 14:42 | justin_smith | dnolen: pub-sub :: malloc :: core.async : gc ? |
| 14:42 | benkay | that said, i' |
| 14:42 | dnolen | s/but/by |
| 14:43 | benkay | i'm always looking for larger scales of problem. |
| 14:43 | justin_smith | oops, extra : above |
| 14:43 | dissipate | benkay, Puppet/Chef? |
| 14:43 | patchwork | dnolen: Ah, you just hook them up? But what if you want to change the wiring? |
| 14:43 | patchwork | interesting… I'll have to mess with it |
| 14:43 | benkay | chef for big client, salt for smaller clients, been playing around with ansible. |
| 14:43 | dnolen | justin_smith: pub-sub is one thing you can do w/ core.async, but you want to avoid pub-sub since that's a resource problem |
| 14:43 | dissipate | benkay, go work for google. that's pretty large scale. :P |
| 14:43 | benkay | f that |
| 14:43 | dnolen | patchwork: just give the channel to someone else if you need to |
| 14:43 | benkay | organizational pathology all the way down, dissipate. |
| 14:44 | benkay | plus no actual interaction with business. |
| 14:44 | dissipate | benkay, but i heard they pay well |
| 14:44 | benkay | look, we solve problems. |
| 14:44 | benkay | money ain't everything. |
| 14:44 | dnolen | justin_smith: sometimes you do need it of course, I'm still thinking about it, hoping to right up my thoughts on that at some point. |
| 14:44 | dnolen | s/right/write |
| 14:44 | benkay | personal growth, joy in the experience of life and reputational development are all vastly more important to me and mine. |
| 14:45 | benkay | i'd rather work 30 hours per week for 80k than 40 for 120. |
| 14:46 | benkay | (that said, solving other humans business problems is so fun that i find myself working more than the important humans in my life want me to) |
| 14:47 | dissipate | benkay, and these business people have no idea you are using clojure? |
| 14:48 | benkay | i strive to find clients who trust me to use the appropriate tools for a given problem. |
| 14:49 | benkay | open comms are the foundation of trust. |
| 14:49 | dissipate | if they bring other developers on board later, there's going to be some WTFs :D |
| 14:49 | benkay | ah, your assumptions are showing. |
| 14:49 | dissipate | how so? |
| 14:49 | benkay | well, being 'a developer' tends to cap ones a) influence on projects and b) billable rate |
| 14:50 | dissipate | that i agree with |
| 14:50 | benkay | when i'm 'a developer' on a project, it's typically as a favor to someone and i do the best thing for their project. |
| 14:50 | benkay | which, take coinforest.com |
| 14:50 | benkay | john and i are friends |
| 14:51 | benkay | i gently suggested he move to AWS |
| 14:51 | benkay | he said 'lol i r no wat' |
| 14:51 | dissipate | you are doing bitcoin projects?? interesting... |
| 14:51 | benkay | so i wrapped it up in CM over a couple of nights and stood it up elsewhere. but it's just a wordpress site. |
| 14:51 | benkay | and it works for him. |
| 14:52 | benkay | so now it's in CM and backs itself up nightly. |
| 14:52 | benkay | without clojure. 'cause bash is totally sufficient. |
| 14:52 | futile | Is it bad practice to build up a regular expression via raw strings, like (str "(" (join "|" options) ")") ? |
| 14:52 | benkay | eh. if only there were real capital seeking to deploy itself in the bitcoin space. |
| 14:53 | dissipate | benkay, why did you pick wordpress over drupal? |
| 14:53 | benkay | again with the assumptions |
| 14:53 | benkay | it's his site |
| 14:53 | benkay | he stood it up first |
| 14:53 | benkay | i helped him insure it against falling over. |
| 14:54 | dissipate | i don't know about 'real' capital, but i personally made a boatload off my bitcoin investment |
| 14:54 | benkay | want to fund the development of an options exchange? |
| 14:54 | benkay | it'd only take about 120k by our estimation. |
| 14:55 | benkay | we'd be doing it in clojure and you could work on it too :) |
| 14:55 | benkay | came up with a sweet hack to get around the infinite downside problem. |
| 14:55 | dissipate | maybe... depends on how it is executed. |
| 14:56 | benkay | how would you want it executed? |
| 14:57 | dissipate | benkay, one of two ways, either all lawyered up and compliant with the feds, or set up in a way that makes it difficult/costly to shut down |
| 14:57 | benkay | those are the options, yes ;) |
| 14:58 | tbaldridge | dnolen: did we ever fix that timeout bug? I think I'm hitting it in my testing |
| 14:58 | dnolen | tbaldridge: sorry we didn't! |
| 14:58 | dnolen | tbaldridge: I think those tests are broken, I forget to mention this |
| 14:58 | devn | what do people use for debugging in the repl these days? |
| 14:58 | dnolen | tbaldridge: let's just comment them out for now and I'll address later |
| 14:58 | arcatan | executed with java -jar exchange.jar |
| 14:59 | tbaldridge | dnolen: yeah, and in my tests I'm creating a (timeout 500) and it's never closing |
| 14:59 | dnolen | tbaldridge: the timeout tests are just badly designed, they shouldn't check for count because that's tied to behavior of dispatcher |
| 15:00 | dnolen | tbaldridge: should check that the timeouts-map is purged of particular timeout |
| 15:00 | dnolen | instead |
| 15:02 | dnolen | tbaldridge: if it's actually never closing that's a different problem |
| 15:02 | dnolen | tbaldridge: never encountered that before |
| 15:02 | hyPiRion | my, wrapped booleans are still behaving weirdly |
| 15:02 | hyPiRion | ,(and (Boolean. false) true) |
| 15:02 | clojurebot | true |
| 15:03 | hiredman | hyPiRion: they always will, clojure doesn't change the wackiness that is Boolean |
| 15:04 | hyPiRion | hm =/ |
| 15:05 | hiredman | clojure canonizes literals, but if you construct random Booleans you are on your own |
| 15:07 | hyPiRion | so the trick is just to know that the primitives false and nil are falsey, and that false? and true? return true if the input is the primitive false/true then |
| 15:12 | lynaghk | bbloom: Reading up on react- |
| 15:12 | lynaghk | bbloom: this stuff reminds me a lot of what I was doing with Singult/C2 |
| 15:13 | lynaghk | though they seem to be doing a lot more optimization on your behalf (rather than complete DOM-subtree walking) |
| 15:13 | bbloom | lynaghk: they basically diff at the sibling level |
| 15:13 | bbloom | lynaghk: which can be problematic for some cross-hierarchy stuff, but in general is pretty rare & easy to work around |
| 15:14 | bbloom | lynaghk: but your render functions don't return full sub trees. they return descriptions of sub trees |
| 15:14 | bbloom | [:button {:id "my-button"} "With some text on it"] |
| 15:14 | bbloom | that's what you return & the evaluator will later look up the button rendering code & recurse |
| 15:14 | lynaghk | bbloom: right. |
| 15:14 | bbloom | it's a good design |
| 15:15 | lynaghk | conceptually it's similar to function composition in hiccup, no? |
| 15:15 | bbloom | yes |
| 15:15 | bbloom | ie functional :-) |
| 15:16 | bbloom | if the render finds that you give it a description of an object that already exists (ie has the same hierarchy path, element type, and optionally a string-key for matching up moving elements in a list view or something like that) then it will preserve the state & transfer over any new parameterization |
| 15:16 | lynaghk | bbloom: yeah, I liked writing UIs in that style with C2 and singult---the only issue was perf. |
| 15:16 | bbloom | otherwise, it will throw away the state of that widget & detatch handlers & all that |
| 15:16 | bbloom | lynaghk: sure, perf sucks if you do the naive implementation |
| 15:16 | bbloom | and i mean naive as in the technical sense, not as in you're stupid :-) |
| 15:16 | lynaghk | bbloom: of walking the subtree on each call to render |
| 15:16 | bbloom | what react does is aggressive memoization |
| 15:16 | lynaghk | (In singult it's called "merge") |
| 15:17 | bbloom | you can stop walking a subtree if you ever discover the parameters are not different |
| 15:17 | bbloom | and if you only ever walk data & never touch the dom, it's much faster |
| 15:17 | lynaghk | bbloom: https://github.com/lynaghk/singult/issues/3 |
| 15:17 | bbloom | react fully virtualizes the dom. it never looks in the real dom for anything unless it HAS TO for a browser quirk or whatever |
| 15:17 | bbloom | lynaghk: ok so then yeah, you get this :-) |
| 15:17 | bbloom | you should like this then! :-P |
| 15:17 | lynaghk | bbloom: = ) |
| 15:18 | lynaghk | bbloom: I love having ideas and then finding out smarter people implemented them better. |
| 15:18 | bbloom | haha |
| 15:19 | bbloom | yeah, your thing sounds just like react |
| 15:19 | bbloom | where you screwed up was exposing the render function :-) |
| 15:19 | bbloom | ie the one returning a live dom node |
| 15:20 | lynaghk | bbloom: I dunno about this JSX preprocessor stuff though; conceptually it seems like we're all on the same page---the real question now is the tradeoffs of html-ish syntax vs a richer format like hiccup or this react data stuff where you can have explicit references to shit besides strings |
| 15:20 | lynaghk | bbloom: you mean react sounds just like my thing from 12 months ago =P |
| 15:20 | bbloom | lol whatever |
| 15:21 | bbloom | i'm not a big fan of the JSX idea in general b/c i hate xml notation & such an extension procludes use of other syntax extensions… you know… like coffeescript :-) |
| 15:21 | lynaghk | bbloom: The one place where this doesn't work out super great is when you want to compose with other libs that don't know about this style |
| 15:21 | bbloom | but in clojure w/ hiccup-style notation, it's basically the same idea |
| 15:21 | lynaghk | bbloom: e.g., for a client project I had to add this "ignore" special type to singult so that in a subtree I could throw a jQuery drag and drop thing |
| 15:21 | bbloom | lynaghk: react's escape hatch for that is here: http://facebook.github.io/react/docs/working-with-the-browser.html |
| 15:22 | lynaghk | yeah, damn. this react thing is very similar to Singult. |
| 15:22 | lynaghk | "in memory representation of the DOM" <=> hiccup. |
| 15:22 | bbloom | lynaghk: cool now explain it to dnolen :-) |
| 15:22 | lynaghk | though in their case you can have special tags |
| 15:23 | bbloom | yeah, the special tags is critical. it's your abstraction mechanism |
| 15:23 | coventry | I find the Ritz debugger a bit awkward to use. It's slow to start up, and the need for break-on-exception to use breakpoints means you break on lots of irrelevant exceptions. Would there be any value to an in-clojure debugger which works like edebug? That is, a special reader which instruments forms with debugging calls as it evals them? |
| 15:23 | bbloom | custom tags == functions, not objects |
| 15:23 | lynaghk | wheras in hiccup if you do something like [:ol (my-special-list-item-template data)] then you lose the semantic info |
| 15:23 | bbloom | STATEFUL custom tags == functions w/ loops in them that break out of the loop when the parent function stops including that ID in the dom |
| 15:23 | lynaghk | compared to [:ol [:my-list-element {:data data}]] |
| 15:24 | bbloom | lynaghk: yeah, that's something i'm trying to solve. unfortunately i think there are only two solutions: 1) explicitly defer execution by using vectors & keywords (my current solution) |
| 15:24 | bbloom | lynaghk: and 2) totally custom language/evaluator |
| 15:24 | bbloom | react is basically doing #1 with a sprinkling of #2 for using xml notation instead of vectors & keywords |
| 15:25 | futile | Does Clojure or Java have an analog to Core Data for local programs? |
| 15:25 | dnolen | bbloom: lynaghk: I dunno about this tree walking stuff |
| 15:26 | dnolen | bbloom: lynaghk: why not compile templates ahead time + core.match |
| 15:26 | bbloom | dnolen: what does core.match have to do with anything? |
| 15:26 | futile | Maybe core.logic or Datomic makes sense for this. |
| 15:26 | dnolen | bbloom: why do you need tree walking? |
| 15:27 | lynaghk | dnolen: in Singult the tree walking was naive and done on fully-rendered DOM elements. There are situations where this is useless (e.g., if you want to change the type of an element at a given position---the walker has no idea what it's supposed to do). |
| 15:27 | dnolen | bbloom: throw that out the window think about precompiled templates + matching |
| 15:27 | dnolen | bbloom: convert the data into paths, push through a template that uses pattern matching |
| 15:27 | bbloom | dnolen: you only need tree walking when your backend renderer is a tree. in my prototype, i use this model & there are two possible backends: one that returns a dom-like tree & one that returns a list of java2d/canvas-style draw commands |
| 15:28 | bbloom | dnolen: the dom backend walks a tree, but the tree is an implementation detail for updating the dom via a diff |
| 15:28 | bbloom | dnolen: the java2d backend just does full re-rendering & that's fast enough for small apps. in larger apps, it will need to memoize layers in to textures |
| 15:29 | bbloom | i don't see how precompiled templates help, since you're building dynamic UIs. the template will need just as much branching & looping as your render functions that return javascript data structures instead of html snippets |
| 15:31 | mimieux | duck1123: Does exist a ciste tutorial? |
| 15:31 | duck1123 | mimieux Not really. I've been meaning to write one for the longest time, but never have |
| 15:32 | lynaghk | bbloom: in this scheme, how do you imagine event handlers working? |
| 15:32 | lynaghk | bbloom: that your custom components handle the low-level events, and they have some way of emitting them back upstream as application-semantic events? |
| 15:33 | bbloom | lynaghk: i'm planning on using a multi-pass model |
| 15:34 | bbloom | lynaghk: even though there are two backends for *rendering* (dom + canvas) there are other backends for other use cases too |
| 15:34 | bbloom | lynaghk: for example, event processing or hit testing |
| 15:34 | bbloom | lynaghk: you can think of the code you write as being a traversal over a data structure & then you parameterize your traversal with different evaluators |
| 15:34 | bbloom | have you ever done any 3d/game/graphics programming? |
| 15:35 | lynaghk | bbloom: not a ton outside the web |
| 15:35 | bbloom | ever heard of a shaddow map? |
| 15:35 | lynaghk | bbloom: actually, lets step back from events real quick---I'm trying to explain to my designer what this approach would look like compared to frankenstein string attributes in HTML for templating. |
| 15:36 | lynaghk | since if he wants to control the markup/CSS, he'll need to use something closer to hiccup than to slim. |
| 15:37 | lynaghk | (hiccup having clojure's richer data structures to play with, compared to stringifying everything in HTML for a runtime evaluator based on the HTML) |
| 15:37 | bbloom | well, ignoring event handling, it would look a lot like react: you just write a pure render function that looks at some args, does normal code branch/loop code & then returns some dom-like node thinggies |
| 15:38 | mimieux | duck1123: ok, now reading jiksnu. |
| 15:38 | lynaghk | bbloom: my question is what the dom-like thing looks like--does it have higher-level semantic info in special tags/attributes? |
| 15:38 | bbloom | it's just data, make it look however you like |
| 15:38 | duck1123 | mimieux, if you have any questions, let me know. I love getting feedback |
| 15:38 | lynaghk | bbloom: like, you have a [:unify {:data data :mapping-fn ...}] tag instead of a fully rendered [:container element1 element2 ...] |
| 15:39 | mimieux | duck1123: sure! |
| 15:39 | lynaghk | i.e., you pass the unevaluated fn as a tag to the renderer so that it can more intelligently handle the dom |
| 15:39 | bbloom | lynaghk: you could create a thunk, but you're probably better off returning some data structure w/ a name & some arguments |
| 15:40 | lynaghk | bbloom: right, that's my question |
| 15:40 | bbloom | [:widgets/tab-controls {:tabs […]}] |
| 15:40 | bbloom | or something like that |
| 15:40 | bbloom | if the renderer sees divs & spans & shit, it draws them or updates the dom. otherwise, it expands the widget |
| 15:41 | lynaghk | right |
| 15:41 | lynaghk | bbloom: how are you controlling scope? |
| 15:41 | bbloom | ok so on to the event handling idea :-) |
| 15:41 | bbloom | scope of what? |
| 15:41 | bbloom | everything is lexical |
| 15:41 | bbloom | except the tag names |
| 15:42 | lynaghk | you don't want everything to have access to the toplevel scope, otherwise if anything changes up there you have to re-render everything |
| 15:42 | bbloom | yeah, you have to thread data down the views as arguments |
| 15:42 | lynaghk | you want the minimum scope per subtree---an explicit list of what data that subtree depends on, so that you can memoize effectively |
| 15:42 | lynaghk | bbloom: okay, right. |
| 15:43 | bbloom | yeah, look at how react does that: it divides data in to two halfs: 1) props 2) state |
| 15:43 | lynaghk | bbloom: so is it that each tag is basically a fn call |
| 15:43 | bbloom | yeah, just deferred until the renderer decides if it needs to call |
| 15:43 | bbloom | there is a 3rd pseudo set of data, which are the children, so you can write <Tabs><Tab>asdfasdf</Tab></Tabs> |
| 15:43 | lynaghk | the children are opaque to the parent? |
| 15:43 | bbloom | but that's just sugar for a "children" key in prop |
| 15:43 | bbloom | s |
| 15:44 | bbloom | you have to explicitly render your children |
| 15:44 | lynaghk | bbloom: can we schedule a time to pair-program a whitepaper example of what todoMVC looks like with this approach? |
| 15:45 | bbloom | lynaghk: here's my non-functioning example that is surely bugged: |
| 15:45 | bbloom | https://gist.github.com/brandonbloom/0acd45c60860e4dd562f |
| 15:46 | bbloom | lynaghk: that's an approximate goal for my code. i have something about 5x as verbose as that working & i'm adding the features i need to get it to work properly. i'm focusing on the java2d backend for now tho, since i know that this approach works in react & i want to prove it's more general |
| 15:46 | bbloom | whoops copy paste fail |
| 15:46 | bbloom | refresh |
| 15:48 | lynaghk | bbloom: are you using keywords as a shortcut for clasess? |
| 15:48 | lynaghk | (section :main ...) |
| 15:48 | lynaghk | bbloom: you've seen my singult todomvc, yeah? https://github.com/lynaghk/todoFRP/blob/master/todo/c2/src/cljs/todo/list.cljs |
| 15:49 | lynaghk | well, c2+singult. |
| 15:49 | lynaghk | (same thing; c2 uses singult under the hood) |
| 15:49 | bbloom | lynaghk: maybe a long time ago? :-) |
| 15:49 | lynaghk | bbloom: are these actually fn applications per tag? It seems like you should have a separate evaluator, not Clojure's |
| 15:50 | bbloom | lynaghk: yes, i need a separate evaluator |
| 15:50 | bbloom | s/defn/defview/ |
| 15:50 | lynaghk | okay. |
| 15:50 | bbloom | the definition of a view is basically `[~fn-name ~@args] |
| 15:50 | bbloom | heh |
| 15:50 | lynaghk | I think namespaced keywords as tag names would work fine |
| 15:50 | lynaghk | yeah. |
| 15:50 | bbloom | yup |
| 15:50 | bbloom | now, two interesting things: |
| 15:51 | bbloom | 1) i mixed event handling directly in there |
| 15:51 | bbloom | which can be a bit ugly, but i haven't designed yet a more general aspect-oriented system for injecting concerns like that |
| 15:51 | lynaghk | aspect-oriented? |
| 15:52 | bbloom | yeah, so like if i want to have some bit of behavior that runs before the behavior of every button, i should be able to (defaspect :before ::widgets/button ...) |
| 15:52 | bbloom | or something like that |
| 15:52 | bbloom | which would let me separate arbitrary logic, rather than just separating event handling from rendering |
| 15:52 | bbloom | i think for simple cases & non-abstract components, strict separation of concerns is a waste of time |
| 15:52 | bbloom | sometimes, you really do have a ONE OFF component. hell, MOST of the time |
| 15:53 | bbloom | in that case, it's fine to couple things & just do whatever works. you can always refactor & abstract/parameterize later |
| 15:54 | lynaghk | bbloom: I wonder if you could implement that using CSS-style selectors on the vDOM |
| 15:54 | lynaghk | vDOM = virtual DOM (or whatever you want to call the pile of vectors) |
| 15:55 | bbloom | lynaghk: yeah, that's the idea, but CSS has a lot of DOM-warts & it's both too flexible & not flexible enough for my needs. so i punted on that & just did the concrete, non-separated thing for now |
| 15:55 | bbloom | 1 step at a time :-) |
| 15:55 | bbloom | now you wanna hear how events work? :-) |
| 15:55 | lynaghk | yes. |
| 15:55 | lynaghk | = ) |
| 15:55 | bbloom | http://www.cs.unc.edu/~zhangh/technotes/shadow/onebigfig.jpg |
| 15:55 | bbloom | ok so that's an example of how shadow mapping works in a 3d game |
| 15:56 | bbloom | notice that the final image is produced by composing a texture from the camera's view & a texture from the light's view |
| 15:56 | bbloom | there are two "renderers": the color view & the depth view |
| 15:57 | bbloom | and there are two "observers" the camera & the light |
| 15:57 | bbloom | conceptually, you evaluate the scene from both observer's views & with both renderers |
| 15:57 | bbloom | in reality, you don't need the light's color view, only it's depth (notice no arrow from it) that's just there for illustration |
| 15:57 | bbloom | you have some data set which represents all the things in your scene |
| 15:58 | bbloom | and you have a "query" on that database |
| 15:58 | bbloom | "give me all the things in the view frustum" |
| 15:58 | bbloom | and you pass the results of that query to the renderer along with the observer as a parameter |
| 15:59 | bbloom | similarly, i might query that database & say "give me all the things that intersect this line" or "give me all the flowers" or whatever |
| 15:59 | bbloom | you can conceive of many queries |
| 15:59 | bbloom | and many ways to process those queries |
| 15:59 | bbloom | so one way to think of UI rendering is to think of it like a query on your view data structure "give me all my view objects" |
| 16:00 | bbloom | you can encode that strictly as data or you can write an explicit traversal |
| 16:00 | bbloom | and if you swap in a different "renderer" which is, more generally, a different "evaluator" then you can perform different tasks |
| 16:00 | bbloom | so each traversal pass, i parameterize with a different evaluator: one for rendering & another one for event processing! |
| 16:01 | bbloom | so when rendering, (clicked? :whatever) => false |
| 16:01 | bbloom | but when event processing, it might return true |
| 16:02 | bbloom | make sense? |
| 16:03 | bbloom | ideas shamelessly stollen from here: http://mollyrocket.com/forums/viewforum.php?f=10 |
| 16:03 | lynaghk | hmm |
| 16:05 | bbloom | hopefully i explained that clearly, it's kinda a heady idea |
| 16:06 | bbloom | but notice how nice the resulting code looks :-) it's super terse & to the point |
| 16:06 | bbloom | it will be *slow as hell* to start, but it's actually really straightforward to optimize b/c you can memoize/cache at pretty much any level |
| 16:08 | bbloom | like for games, imagine nothing in the view of the spot light ever moves. you don't need to re-render the texture! |
| 16:08 | bbloom | :-) |
| 16:13 | lynaghk | So in general the scenegraph for view rendering can be completely different than the event scenegraph |
| 16:13 | lynaghk | ? |
| 16:20 | dnolen | bbloom: yeah not yet convinced about traversal stuff, nor diff'ing stuff, nor how templates are traditionally handled - I've got some ideas I'm poking around with |
| 16:20 | bbloom | dnolen: looking forward to seeing your approach :-) |
| 16:21 | dnolen | tbaldridge: were you able to sort out the bug? |
| 16:21 | tbaldridge | yeah, it was a bug in close! |
| 16:21 | dnolen | tbaldridge: cool will give it a spin then |
| 16:22 | tbaldridge | dnolen: something breaks for me with advanced compilation, it's like MessageChannel is super slow in adv more. Perhaps if you hit that bug you can help me figure it out. |
| 16:23 | dnolen | tbaldridge: seems strange will poke around |
| 16:25 | zeitue | is there anything like codecademy for clojure? |
| 16:28 | callen | zeitue: that's a really good idea. |
| 16:28 | callen | zeitue: 4clojure is pretty close. |
| 16:28 | zeitue | callen: that's what I was looking for cause I'm teaching a few the language |
| 16:29 | dnolen | tbaldridge: what are you running that looks slow? |
| 16:29 | tbaldridge | dnolen: https://gist.github.com/halgari/6323472 |
| 16:29 | zeitue | thanks for the recommendation I've seen that though now sure on it callen: |
| 16:30 | dnolen | tbaldridge: is that what you added to the tests, I see you're timing something now? |
| 16:30 | tbaldridge | dnolen: In chrome that takes 3000ms to run in simple, with adv it takes ~1000ms to run, the first time, if I reload the page it takes 70000ms, and continues to be that slow until close the tab and load it up in a different tab |
| 16:32 | tbaldridge | dnolen: yeah, I need to remove that from the tests, but yes, it's timing total time to put/take 1mil items from a (chan) |
| 16:32 | dnolen | tbaldridge: ok will try running tests in advanced |
| 16:35 | dnolen | tbaldridge: I can't reproduce your problem, neither in Chrome nor Chrome Canary |
| 16:35 | dnolen | tbaldridge: I can't believe that runs so quickly! |
| 16:35 | tbaldridge | dnolen: okay, I'm fine with that perhaps we're good then |
| 16:39 | dnolen | tbaldridge: Huzzah! |
| 16:39 | tbaldridge | dnolen: it's faster for you? |
| 16:39 | dnolen | tbaldridge: Node.js Go daisy chain benchmarks takes 732ms! |
| 16:40 | tbaldridge | dnolen: down from? |
| 16:40 | dnolen | tbaldridge: setImmediate alone by itself takes ~350ms |
| 16:40 | dnolen | tbaldridge: 100000 calls to setImmediate, so we're adding just a little bit of overhead to that. |
| 16:41 | tbaldridge | dnolen: yeah, a ring benchmark is like the worst case for the new dispatcher. Assuming only one message is being passed around the ring. |
| 16:43 | callen | tbaldridge: is this supposed to be like the thread ring benchmark on the shootout? |
| 16:43 | dnolen | tbaldridge: it's about ~250ms improvement over old perf |
| 16:43 | tbaldridge | dnolen: eh, not too bad then. |
| 16:46 | tbaldridge | callen: yeah, a ring benchmark is like a recursive fibonacci benchmark, all you're doing is benchmarking overhead that wouldn't be a problem in real life code. |
| 16:47 | dnolen | tbaldridge: there are still some boolean things but if you merge master I can patch that stuff up |
| 16:47 | tbaldridge | dnolen: kk, if you're not seeing any bugs then I'll merge. |
| 16:48 | dnolen | tbaldridge: lemme test my autocompleter real quick |
| 16:49 | dnolen | tbaldridge: works like a charm, go for it |
| 16:50 | tbaldridge | done |
| 16:50 | tbaldridge | and hey! 200 commits to core.async! |
| 16:51 | callen | tbaldridge: I know that. I was just asking if it was comparable to thread ring or not. |
| 16:51 | tbaldridge | callen: I'd imagine so, I haven't seen the code dnolen was running |
| 16:52 | callen | tbaldridge: do you guys squash commits for clean bisect in core.async? |
| 16:52 | callen | (asking because of the 200 commits #, which sounds low to me) |
| 16:52 | dnolen | callen: it's basically a thread ring yes |
| 16:52 | dnolen | callen: 100000 channels linked together, benchmarking put something in at one end reading it at the other. |
| 16:52 | tbaldridge | callen: no I haven't seen that done with this project |
| 16:52 | callen | dnolen: very cool. I've been using the ability to write things like core.async as a library, as a way to demonstrate the value of Clojure at work :) |
| 16:53 | callen | tbaldridge: sounds like very few commits for a project of that scope. *takes a look* |
| 16:54 | tbaldridge | callen: actually, I developed the go macro over a week in a different repo, so that does skew things a bit. |
| 16:55 | callen | tbaldridge: it's not totally clear to me who's responsible for what parts of core.async. |
| 16:57 | avishai | anybody here using appengine-magic? |
| 16:57 | tbaldridge | callen: Rich did the channels, and I wrote the IOC stuff, the rest of it was collaboration between Relevance people, Rich and dnolen. |
| 17:00 | callen | tbaldridge: thanks. Is there a good primer on getting into the headspace behind how it works somewhere? |
| 17:01 | srruby | I'm a Rubyist/former Java programmer looking for Clojure work. Any tips ? I'm glad that Lisp is getting more popular! |
| 17:01 | callen | srruby: contracting with clients that trust you to do what makes sense. |
| 17:01 | callen | srruby: if you're in the bay area, there are companies that use Clojure. |
| 17:02 | srruby | callen: Thanks, and yes I'm in the bay area. I'm starting to send out resumes locally. |
| 17:02 | callen | srruby: you really should be working on stuff of your own accord though. |
| 17:03 | callen | It's not really fair or reasonable to expect an employer to pay you to learn Clojure on the job. |
| 17:03 | gtrak | srruby: Joy of Clojure is worth the time/effort investment. |
| 17:03 | tbaldridge | callen: not that I'm aware of, the best thing I can point out to you now is to read both channels.cljs and async.cljs. Today I rewrote this CLJS code so it's a bit easier to understand. The thing is, you can cancel callbacks, so every callback has to have commit executed against, and that makes things a bit harder to understand. |
| 17:04 | srruby | callen: I am and getting pretty good at it. I'm porting one of my open source projects from Javascript to Clojure. |
| 17:04 | tbaldridge | callen: once you grasp that, think "now how would I do this with multiple threads", and then read channels.clj. |
| 17:04 | tbaldridge | callen: rich spent a ton of time figuring out all the lock stuff on the JVM, and that's something I hope I never have to do. |
| 17:04 | callen | tbaldridge: I understand systems like core.async conceptually, it's the state machine rewriting that is more puzzling to me. |
| 17:04 | tbaldridge | ah |
| 17:04 | callen | oh, the lock stuff would be interesting too I suppose. |
| 17:05 | callen | srruby: if you need something to hack on in Clojure, I've always got a long list of things on my open source to-do list. |
| 17:05 | tbaldridge | callen: have you seen this? http://hueypetersen.com/posts/2013/08/02/the-state-machines-of-core-async/ |
| 17:05 | callen | I have now, thanks. |
| 17:06 | tbaldridge | callen: that goes through the output of the macro. For the actual guts I always suggest that people read this: http://en.wikipedia.org/wiki/Static_single_assignment_form and then just view the go macro as a micro compiler. |
| 17:06 | tbaldridge | callen: I hope that helps a bit |
| 17:07 | srruby | callen: Could I see the list? |
| 17:07 | callen | tbaldridge: I knew SSA was involved. this should help tie everything together, thank you very much :) |
| 17:10 | callen | srruby: https://www.refheap.com/17988 |
| 17:10 | callen | `cbp: wakie wakie, eggs-n-bakie. |
| 17:11 | duck1123 | That's quite a list for someone learning clojure |
| 17:12 | callen | `cbp: this is the current to-do list: https://www.refheap.com/17988 are you still working on sync! for Pomegranate? |
| 17:12 | callen | duck1123: he asked for my to-do list, not for a learner's primer. |
| 17:12 | callen | duck1123: half the stuff on there is pretty doable for a new person anyway. |
| 17:12 | srruby | callen: Looks pretty daunting. I better finish my project first :) |
| 17:13 | callen | the only really tricky one might be proxy+ |
| 17:13 | callen | that might be horrific if not impossible. I don't really know. Depends on how usable the Annotation(Visitor/Writer).java stuff is. |
| 17:20 | `cbp | callen: hihi |
| 17:20 | `cbp | callen: technically no because i've been extremely busy but I was hoping to do more this weekend |
| 17:20 | callen | `cbp: sounds awesome. Thanks :) |
| 17:23 | dnolen | tbaldridge: wow, thread ring in Chrome takes 200ms, same as Clojure |
| 17:23 | tbaldridge | nice! |
| 17:23 | callen | dnolen: n of what? |
| 17:23 | callen | 100k or 1mm? |
| 17:24 | dnolen | http://gist.github.com/swannodette/6323988 |
| 17:24 | dnolen | callen: 100k |
| 17:24 | dnolen | tbaldridge: that is pretty amazing |
| 17:25 | tbaldridge | dnolen: I was hoping we could get to this point. There was a ton of crap in the channels that was multithread specific. |
| 17:27 | dnolen | tbaldridge: a lot of fun stuff I want to try now :) |
| 17:31 | bbloom | cool stuff guys! |
| 17:35 | shaungilchrist | well that was odd, not sure why but ioc_helpers.run_state_machine_wrapped stopped being added to compiled cljs. lein cljsbuild clean fixed it but it would be nice to know why |
| 17:36 | callen | shaungilchrist: I assume by default that anything involving cljsbuild (however very nice it is) involves vague gesturing and magic incantations :P |
| 17:37 | dnolen | shaungilchrist: probably stale stuff in your target directory, often happens if you pull in a new version of some lib |
| 17:40 | tbaldridge | I always do cljsbuild clean after an upgrade |
| 17:40 | callen | tbaldridge: that pattern/habit probably merits documenting. |
| 17:40 | tbaldridge | docs? what is this, ruby? |
| 17:40 | shaungilchrist | hahaha |
| 17:41 | callen | I'm documenting the cargo cult right now. Somebody else can confirm/repro. |
| 17:41 | shaungilchrist | the upside of it was walking through the core.async source and compiled output which was (seriously) a thing of beauty |
| 17:42 | callen | https://github.com/emezeske/lein-cljsbuild/pull/223 |
| 17:42 | callen | tbaldridge: I'm in Klishin's camp. Documentation uber alles. |
| 17:43 | tbaldridge | well yes I was being sarcastic |
| 17:43 | callen | I'm perpetually serious. |
| 17:45 | dnolen | tbaldridge: wow flame graph profiles, memory profiles for core.async are GORGEOUS now in chrome |
| 17:45 | bbloom | dnolen: screen cap? :-) |
| 17:45 | bbloom | maybe even a before/after? :-P |
| 17:46 | dnolen | bbloom: haha, I'll put something together but my push 1 millions items in a range into a channel + read them out use to involve a incredible long tail before GC kicked |
| 17:46 | dnolen | now it's like goddamn CLIFF |
| 17:46 | dnolen | BOOM memory reclaimed |
| 18:03 | dnolen | tbaldridge: you're queuing dispatcher is sweet :), I believe it's the reason we're seeing such good GC behavior |
| 18:03 | tbaldridge | I wonder why that is. I wouldn't have though it would have a impact on memory. |
| 18:04 | tbaldridge | dnolen: BTW, we probably want to update the ring buffer at some point to set old slots to nil after they are popped, that should help the GC in some cases as well. |
| 18:04 | tbaldridge | dnolen: unless you know of a reason why we shouldn't |
| 18:05 | dnolen | tbaldridge: no that sounds like a good idea to me |
| 18:08 | dnolen | tbaldridge: I'm pretty it's because we don't pound the browser with dispatches now esp in the case of (chan), they aren't cheap |
| 18:09 | tbaldridge | ah yeah, I could see that |
| 18:09 | dnolen | tbaldridge: it used to take 16 seconds to do 1000000 events with (chan) in Chrome |
| 18:09 | dnolen | tbaldridge: now 1.5seconds |
| 18:09 | tbaldridge | :-D |
| 18:09 | callen | good lord. what'd you change to create such an improvement? |
| 18:09 | shaungilchrist | wow that is awesome |
| 18:10 | tbaldridge | callen: rewrote channel from scratch, switched from arrays to a ring buffers, implemented a custom event queue. and a ton of CLJS magic |
| 18:10 | callen | very cool. :) |
| 18:11 | callen | tbaldridge: I take it you've read about LMAX Disruptor? |
| 18:11 | futile | dnolen: whoa. |
| 18:11 | dnolen | tbaldridge: definitely blown away that (chan) is this efficient now |
| 18:11 | tbaldridge | callen: yeah, sadly it doesn't work at all for the JVM stuff, but we're using something like that in CLJS now. Of course there's only one thread in CLJS so it's basically a ring buffer at that point. |
| 18:12 | callen | That makes sense. |
| 18:12 | bbloom | i'm available any time you need me to just say the name of a data structure & then sit back & let you guys do all the work :-) |
| 18:13 | bbloom | really, good stuff guys. thanks for being awesome w/ that stuff |
| 18:37 | clj_newb_2345 | anyone know of a good resource for "Clojure Pedestal" for people whose IQs aren't 4 digits? |
| 18:39 | nDuff | clj_newb_2345: have you walked through the tutorial? |
| 18:39 | nDuff | clj_newb_2345: it's several hours, but it's hours well-spent. |
| 18:39 | callen | clj_newb_2345: are you working on a complicated web application? |
| 18:39 | callen | clj_newb_2345: or are you just trying to learn to do web dev in Clojure? |
| 18:42 | arkh | clj_newb_2345: in addition to the pedestal app-tutorial, samples and pedestal.io documentation (not in that order) I'd recommend https://github.com/taylorSando/pedestal-todo/blob/master/beginners.md |
| 18:43 | callen | clj_newb_2345: if you're just learning how to do web dev in general with Clojure, Pedestal isn't a very good fit. It's better for more experienced Clojure users making web apps that are complicated in a particular way. |
| 18:44 | ucb | callen: I'm sure you've seen https://github.com/drcode/webfui before. What do you think of it? |
| 18:44 | ucb | also hi! |
| 18:46 | callen | ucb: yeah I've seen webfui before. no opinions. Seems like a plausible way to do things. |
| 18:46 | callen | ucb: hi! how are you? |
| 18:46 | callen | I've mostly been learning more Datomic lately. |
| 18:46 | ucb | callen: good stuff, thanks. I'm well, how you? |
| 18:47 | callen | Very good, looking forward to testing Clojure/Datomic at work for a project. |
| 18:47 | ucb | nice |
| 18:47 | callen | Didn't take long at all to find an excuse. :) |
| 18:47 | ucb | datomic on the browser mayhaps? |
| 18:47 | callen | it does map nicely to the problem. |
| 18:47 | callen | ucb: nah, this is backend stuff. |
| 18:47 | ucb | hammers and nails |
| 18:47 | callen | need to aggregate data from a bunch of different sources and have a traversable history of the universe. |
| 18:47 | callen | ideally with efficient aggregations and relationships. |
| 18:47 | callen | which datomic fits neatly. |
| 18:48 | ucb | nice |
| 18:49 | ucb | and having said that, zzz |
| 18:53 | agumonkey | hey clojurists |
| 18:53 | agumonkey | I just wrote a weird take-like function |
| 18:54 | agumonkey | taking overlapping frames of a list |
| 18:54 | agumonkey | (frame (range 6) 3) |
| 18:54 | agumonkey | ((0 1 2) (1 2 3) (2 3 4) (3 4 5)) |
| 18:54 | agumonkey | is there a common name for this function ? I'm sure it exists already |
| 18:55 | hyPiRion | agumonkey: partition |
| 18:55 | agumonkey | partition do overlaps ? |
| 18:55 | hyPiRion | ,(partition (range 6) 3 1) |
| 18:55 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long> |
| 18:55 | hyPiRion | br, wrong way |
| 18:55 | ChongLi | ,(partition 3 1 (range 6)) |
| 18:55 | clojurebot | ((0 1 2) (1 2 3) (2 3 4) (3 4 5)) |
| 18:55 | hyPiRion | ^ |
| 18:55 | agumonkey | I'll be damned |
| 18:55 | agumonkey | thanks a ton of lots |
| 18:55 | tbaldridge | agumonkey: careful.... |
| 18:55 | agumonkey | with the partitioning or the daming ? |
| 18:55 | tbaldridge | , (partition 3 1 (range 7)) |
| 18:55 | clojurebot | ((0 1 2) (1 2 3) (2 3 4) (3 4 5) (4 5 6)) |
| 18:56 | tbaldridge | partition drops partial segments |
| 18:56 | tbaldridge | , (partition-all 3 1 (range 7)) |
| 18:56 | clojurebot | ((0 1 2) (1 2 3) (2 3 4) (3 4 5) (4 5 6) ...) |
| 18:56 | tbaldridge | bleh, I'm failing here |
| 18:56 | tbaldridge | , (partition 2 (range 3)) |
| 18:56 | clojurebot | ((0 1)) |
| 18:56 | agumonkey | alright, that's what my unnecessary `frame` was doing anyway |
| 18:56 | tbaldridge | , (partition-all 2 (range 3)) |
| 18:56 | clojurebot | ((0 1) (2)) |
| 18:57 | tbaldridge | just be aware of the difference, I've lost some time on that oddity |
| 18:57 | hyPiRion | what tbaldridge means is that the last two partitions are removed (the (5 6) and (6)) when using partition |
| 18:57 | agumonkey | And I actually remember reading these partition* functions in dash.el emacs lib ... I can't even reuse prior lisp knowledge |
| 18:57 | hyPiRion | they are kept with partition-all |
| 18:57 | tbaldridge | hyPiRion: yeah, what he said |
| 18:57 | rasmusto | or with #(partition % 1 someseq) |
| 18:58 | rasmusto | that I happen to use a lot |
| 18:59 | magnars | agumonkey: partition and partition-all work the same in dash as in clojure - just that there is no optional step argument. There's a separate partition-in-steps and partition-all-in-steps instead. |
| 19:04 | agumonkey | magnars: hey, well then I don't know where I got this idea |
| 19:05 | agumonkey | magnars: is there a lot of clojure in dash ? or is it more mainstream/vintage lisp ideas ? |
| 19:05 | magnars | it borrows heavily from clojure |
| 19:05 | agumonkey | ok |
| 19:15 | clj_newb_2345 | nDuff, callen: arkh: I've already played with ClojureScript / ring / moustache / enlive |
| 19:15 | clj_newb_2345 | this is basically "Pedestal, nothign else will do" |
| 19:15 | clj_newb_2345 | I like their model of updates |
| 19:15 | clj_newb_2345 | and how it updates the DOM |
| 19:16 | callen | clj_newb_2345: there is a Pedestal channel on FreeNode, might be a better resource than this one. |
| 19:19 | seangrov` | After tinkering for awhile, I'm ready to ask for help |
| 19:20 | seangrov` | I'm making a toy battleship implementation in cljs, and I would like to have multiple implementation of the board - a single array, and array of arrays, maybe something else |
| 19:20 | seangrov` | Is this a use case for defprotocol and deftype? |
| 19:20 | callen | seangrov`: single array being partitioned according to row/col? |
| 19:20 | seangrov` | callen: Yeah, by calculating the offset |
| 19:21 | callen | seangrov`: the protocol is the API for interacting with the boards, the deftypes are the boards themselves, no? |
| 19:21 | seangrov` | Whereas the second implementation would be [[row-1][row2]...] |
| 19:21 | seangrov` | Yeah |
| 19:21 | seangrov` | Trying to make sure my understanding isn't too far off here |
| 19:25 | `cbp | seangrov`: maybe a multimethod and your dispatch fn can tell what kind of board it is based on the structure? |
| 19:27 | llasram | Note to self: do not write macro-writing macros |
| 19:28 | llasram | I've apparently had a library with `(~~fname ...) for years where I really needed `(~'~fname ...) |
| 19:28 | `cbp | seangrov`: I would probably model it as a set of occupied coordinates + possibly a set of checked coordinates though. |
| 19:29 | seangrov` | `cbp: Yeah, I have one implementation that works just fine, but I would like to separate it form the e.g. rendering code that's going to be consuming it and the game logic that'll be interacting with it |
| 19:38 | eric_normand | anyone using liberator 0.9.0? |
| 19:38 | eric_normand | I have a question about responses. |
| 19:54 | clj_newb_2345 | callen: ha, nice, thanks! |
| 19:55 | seangrov` | It seems like protocols lend themselves towards mutable state |
| 19:55 | seangrov` | I'm probably using them incorrectly though |
| 19:56 | bbloom | seangrov`: why do you feel that they lead you that way? |
| 19:58 | seangrov` | bbloom: I'll post the code in a bit and ask for some review, it's pretty small |
| 20:04 | callen | llasram: nice. |
| 20:11 | clj_newb_2345 | is there any wrappers of the _git api_ as a clojure library? |
| 20:11 | clj_newb_2345 | actually, wait |
| 20:11 | clj_newb_2345 | if I want a database with git like "DAG" structure |
| 20:11 | clj_newb_2345 | if I want adatbase with "DAG" like forking / remembering of history, is Datomic what I want? |
| 20:13 | bbloom | clj_newb_2345: not really. Datomic is more like git with only a master branch, plus a fast query engine |
| 20:13 | bbloom | a multi-master version of datomic w/ a different set of trade offs would be awesome for a different set of use cases, though |
| 20:14 | clj_newb_2345 | bbloom: so "datomic", roughly, is "CVS + fast query engine" |
| 20:14 | clj_newb_2345 | or rather, it's a "line" with a fast query engine, not a DAG |
| 20:14 | bbloom | clj_newb_2345: well no b/c CVS stores diffs |
| 20:15 | bbloom | clj_newb_2345: datomic works like git, but the only shared branch is master. you can have local, uncommitted branches |
| 20:15 | clj_newb_2345 | doesn't datomic store diffs? how else does it story the history? |
| 20:15 | bbloom | git doesn't store diffs |
| 20:15 | bbloom | how else does it store history? :-) |
| 20:15 | hiredman | (which is amazing, btw) |
| 20:16 | clj_newb_2345 | how does git store history? |
| 20:16 | bbloom | clj_newb_2345: http://vimeo.com/14629850 |
| 20:16 | clj_newb_2345 | oh, git blobs |
| 20:16 | clj_newb_2345 | that's what the hashes are for, no? |
| 20:16 | bbloom | the hashes are version numbers b/c you can have multiple committed masters in a distributed manner |
| 20:17 | bbloom | datomic just uses an incrementing number for the basis time (ie version number) |
| 20:18 | clj_newb_2345 | first world problem: the video is too big to play nicely n my nexus 7 |
| 20:20 | hiredman | I wonder if datomic does a cas like thing |
| 20:21 | bbloom | hiredman: my understanding is that it's strictly serialized |
| 20:21 | bbloom | hiredman: the server may be multithreaded, but transactions go in to a queue & a single consumer processes them linearly |
| 20:21 | bbloom | no need for cas then |
| 20:21 | hiredman | bbloom: ah, I mean content addressable storage, wrong cas |
| 20:22 | bbloom | oh haha |
| 20:22 | bbloom | hm, yeah, i imagine it must right? |
| 20:22 | bbloom | it stores large chunks of indexes in block storage |
| 20:22 | hiredman | I dunno |
| 20:22 | bbloom | what else would it call the blocks? |
| 20:23 | hiredman | actually I guess it must |
| 20:23 | bbloom | i mean it *could* name regions of the indexes & store those names |
| 20:23 | bbloom | but seems like a waste |
| 20:23 | hiredman | dunno, makes sense, I was going to say "oh, I assume a cas would have to be based on hashing" and then thought "oh, right" |
| 20:24 | bbloom | hiredman: i bet you can find out quite easily if you set up a store & peek in it |
| 20:24 | bbloom | maybe somebody here has a store set up that they can run a sub-datomic level query & see what keys they got in there:-) |
| 20:24 | hiredman | meh, seems like a lot of work |
| 20:25 | clj_newb_2345 | besides datomic and fleetdb; are there any other databses implemented _in_ clojure? |
| 20:25 | clj_newb_2345 | i'm more curious in how implementations work rather than raw performance |
| 20:36 | callen | clj_newb_2345: https://github.com/ninjudd/jiraph sorta. |
| 20:36 | callen | same pluggable backend type design as Datomic. |
| 20:58 | bbloom | dnolen: hey perf man. question for you |
| 20:58 | dnolen | bbloom: what's up? |
| 20:58 | bbloom | dnolen: any reason vector nodes don't have cached hash values? seems odd that (hash (conj v :x)) is always going to be linear |
| 20:59 | dnolen | bbloom: huh, no particular reason no - I'm surprised we don't cache the value. |
| 20:59 | muhoo | ~cas |
| 20:59 | clojurebot | Excuse me? |
| 20:59 | dnolen | bbloom: I'm also up for the incremental hash calculation that people have brought up |
| 20:59 | muhoo | what is cas? |
| 20:59 | callen | muhoo: compare and swap |
| 20:59 | muhoo | thx |
| 20:59 | bbloom | callen: except not above |
| 20:59 | muhoo | ~cas is compare and swap |
| 20:59 | clojurebot | 'Sea, mhuise. |
| 21:00 | bbloom | muhoo: it also means "content addressable storage" |
| 21:00 | bbloom | which is what hiredman was talking about |
| 21:00 | muhoo | ~cas s compare and swap or content addressable storage |
| 21:00 | clojurebot | Huh? |
| 21:00 | muhoo | ~cas is compare and swap or content addressable storage |
| 21:00 | clojurebot | In Ordnung |
| 21:00 | muhoo | ~cas |
| 21:00 | clojurebot | cas is compare and swap or content addressable storage |
| 21:00 | callen | nice. |
| 21:00 | muhoo | (inc clojurebot) |
| 21:00 | lazybot | ⇒ 30 |
| 21:00 | callen | (inc muhoo) |
| 21:00 | lazybot | ⇒ 1 |
| 21:00 | bbloom | dnolen: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentVector.java#L140-L145 |
| 21:00 | callen | asking questions is goooooood |
| 21:00 | bbloom | :-( sad |
| 21:00 | muhoo | ~frp |
| 21:00 | clojurebot | It's greek to me. |
| 21:01 | callen | muhoo: functional reactive programming |
| 21:01 | muhoo | ~frp is functional reactive programming, or fiberglass reinforced plastic |
| 21:01 | clojurebot | Alles klar |
| 21:01 | dnolen | bbloom: oh, you're asking about CLJ, yeah this would be nice enhancement no? :) |
| 21:01 | bbloom | dnolen: it's also true of cljs |
| 21:01 | callen | ~frp |
| 21:01 | clojurebot | frp is functional reactive programming, or fiberglass reinforced plastic |
| 21:01 | bbloom | dnolen: i checked both |
| 21:01 | muhoo | ~java logging |
| 21:01 | clojurebot | java logging is clown shoes |
| 21:01 | muhoo | :-) |
| 21:01 | callen | Perfekt. |
| 21:01 | dnolen | bbloom: ok you're asking about incremental hashing |
| 21:01 | muhoo | ok back to work for me |
| 21:02 | callen | I love it when people break servers dev environments depend on. |
| 21:02 | dnolen | bbloom: yes this is a good idea, up for a patch to CLJS |
| 21:03 | bbloom | dnolen: ok :-) |
| 21:03 | dnolen | bbloom: Mark Engelberg brought this up with respect to CLJ, probably just need to submit a patch and bug one of the core devs |
| 21:08 | bbloom | dnolen: ok thx. i dunno if i'll bother to patch it, but good to know i'm not crazy for wanting that |
| 21:09 | dnolen | bbloom: if you feel so inclined feel to free to open a ticket for it. Michal might take it. |
| 21:09 | bbloom | dnolen: on clj or cljs or both or what? |
| 21:10 | coventry | I just watched Stuart Halloway's Clojure Tips talk from earlier in the year, where he said that debugging facilities in clojure are lacking, but traditional debugging tools are probably not what's needed. Has he written anything about what's needed instead? |
| 21:10 | bbloom | dnolen: oh haha http://dev.clojure.org/jira/browse/CLJ-15 |
| 21:10 | bbloom | dnolen: apparently rich himself reported this in 2008 |
| 21:10 | dnolen | bbloom: ok, yeah Christophe's point is interesting |
| 21:11 | bbloom | dnolen: i know that we do a mix of hash code caching strategies. sometimes caching on use w/ mutation, sometimes cashing on construction. is there any reason not to universally cache on construction? |
| 21:11 | dnolen | bbloom: how can you can cache lazy values? (maybe there's a fancy way?) |
| 21:12 | bbloom | dnolen: ignore christophe's comment for a moment, i'll return to that |
| 21:12 | bbloom | dnolen: i mean for vectors, PAM, PHM, etc |
| 21:13 | dnolen | bbloom: for literals makes sense, not sure about anything else, would need to benchmark |
| 21:13 | dnolen | bbloom: nice to avoid that cost until needed |
| 21:13 | dnolen | bbloom: if you do it for conj you're probably good anyway |
| 21:13 | bbloom | dnolen: right, but pay a test against -1 later. not sure how that balances out in practice |
| 21:14 | dnolen | bbloom: so literals + conj covers most cases I think. |
| 21:14 | dnolen | bbloom: not sure about assoc ..., nor pop, or stuff like that though? |
| 21:14 | dnolen | bbloom: anyways fancy hashing tricks is outside my knowledge |
| 21:14 | bbloom | dnolen: nah, i think the mutation thing makes the most sense |
| 21:15 | bbloom | anytime you do anything, you create new nodes w/ -1 |
| 21:15 | bbloom | dnolen: and then you just decorate all the interior nodes of the tree w/ that caching/hashing strategy |
| 21:15 | bbloom | so if you conj, you get a -1 hash again, but you only need to walk the top level of the tree, and the modified branch |
| 21:16 | dnolen | bbloom: ok right, so this why not done, a lot of work for every data structure? |
| 21:16 | dnolen | we have a lot |
| 21:16 | bbloom | dnolen: yeah, it's just a big change |
| 21:16 | bbloom | seems like it could be a big win for some use cases tho |
| 21:17 | bbloom | in particular, i've had to twist my code a little bit to avoid "changing" things |
| 21:17 | bbloom | partly because of GC concerns, but more b/c equality gets slow again |
| 21:17 | bbloom | hell, i'd really love to wrap every persistent structure in a mutable cell, then garbage collect and compact things :-) |
| 21:20 | bbloom | dnolen: i ran in to an issue once where i had a largely redundant data structure (like the cljs namespaces atom) and printing/reading it used absurd amounts of memory |
| 21:21 | bbloom | dnolen: would be super awesome if you could recover lost structural sharing |
| 21:22 | clj_newb_2345 | if everything is value |
| 21:22 | clj_newb_2345 | can't you recover structural sharing by calculating the sha256 sum of every node |
| 21:22 | clj_newb_2345 | then having a hash table of those hashes ? |
| 21:22 | bbloom | clj_newb_2345: you can do something like that, but the particular approach would be a bit different in order to perform well |
| 21:23 | clj_newb_2345 | bbloom: indeed, on every object construction, looking up "does this hash exist" is probably a bit too much |
| 21:24 | bbloom | dnolen: oh, i realized why incremental hashing is a bit tricky: you need a hash algorithm that will compose correctly. if you have PAM and PHM interior nodes w/ non composing hash functions, then you wouldn't be able to do proper cross-implementation comparisons |
| 21:24 | bbloom | clj_newb_2345: there are systems that do that: http://www.meta-environment.org/Meta-Environment/ATerms |
| 21:24 | bbloom | clj_newb_2345: but not ideal, i think |
| 21:25 | clj_newb_2345 | though given CLojure's meta data support, this is tempting |
| 21:25 | clj_newb_2345 | this also does make sense to go into the gc layer |
| 21:25 | clj_newb_2345 | the gc has to touch all the objects anyway; so while there, why not look for structural sharing |
| 21:25 | dnolen | bbloom: it just sounded tricky to me period, but OK |
| 21:26 | bbloom | dnolen: you need an associative hash function |
| 21:26 | clj_newb_2345 | there is the downside that this requires all "hashed" objects to be immutable; since changing object -> changing hash -> might have to change a chain of hashes |
| 21:26 | bbloom | after that, i think it's relatively straightforward |
| 21:26 | bbloom | clj_newb_2345: i consider that an advantage :-) |
| 21:27 | clj_newb_2345 | I like immutable too |
| 21:27 | clj_newb_2345 | but occasionally, I like mutability |
| 21:27 | clj_newb_2345 | i.e. why I use clojure rather than, say Haskell |
| 21:32 | callen | 90% of the time I've seen somebody say they needed mutability or mutable global state for something, they haven't. |
| 21:32 | callen | but the 10% is still there. |
| 21:33 | bbloom | see also http://en.wikipedia.org/wiki/Hash_consing |
| 21:54 | ddellacosta | good morning |
| 22:01 | callen | ddellacosta: morning. |
| 22:01 | ddellacosta | callen: morning, how goes it? |
| 22:01 | ddellacosta | er, evening? I guess |
| 22:02 | ddellacosta | I SEND YOU GREETINGS FROM THE FUTURE |
| 22:02 | seangrov` | ugt |
| 22:02 | seangrov` | ~ugt |
| 22:02 | clojurebot | ugt is Universal Greeting Time: http://www.total-knowledge.com/~ilya/mips/ugt.html |
| 22:04 | mmarczyk | dnolen: bbloom: re: incremental hashing, cgrand's comment on CLJ-15 about needing to force lazy seqs placed in vectors or maps applies; if that's unacceptable in general, something like Mark Engelberg's wrapper (in instaparse) can be used where it is; anyway, I've wanted incremental hashing of all PDSs for a while now and I'm totally up for implementing it in whichever fashion (and before that, spending time to figure out a |
| 22:04 | mmarczyk | "cancellable" hash combiner) |
| 22:04 | ddellacosta | seangrov`: that's awesome, didn't know about that. I guess I was right in the first place. |
| 22:05 | bbloom | mmarczyk: aah now i understand his comment |
| 22:05 | bbloom | hmmm |
| 22:05 | bbloom | yeah, that is a pickle |
| 22:05 | mmarczyk | finishing sentence above, that's right after I finish my current secret PDS impl project, which I'm hoping will be of use to certain implementers of pretty printing libraries :-) |
| 22:06 | mmarczyk | it is, unfortunately |
| 22:06 | bbloom | mmarczyk: :-D |
| 22:06 | mmarczyk | :-) |
| 22:06 | mmarczyk | it is, unfortunately |
| 22:06 | mmarczyk | for example it means no infinite seqs in vectors |
| 22:07 | bbloom | mmarczyk: yeaaah… i've always been kinda conflicted about how vectors & seqs work w/ respect to equality |
| 22:07 | mmarczyk | of course if anybody ends up hashing a vector with lazy stuff inside they'll force it anyway, but apparently often enough that doesn't happen |
| 22:07 | bbloom | mmarczyk: it's convenient as hell that seqs = vectors |
| 22:07 | bbloom | but also kinda strange & wrong feeling |
| 22:08 | mmarczyk | notably split-at / split-with couldn't possibly work the way they do now |
| 22:08 | bbloom | yeah, it's kinda this weird compromise |
| 22:09 | bbloom | lazy seqs are not always "values" |
| 22:09 | bbloom | in fact, they are explicitly non-values, since they contain thunks |
| 22:09 | mmarczyk | yes, Clojure's notion of equality is a bit funny |
| 22:09 | mmarczyk | well, I don't know if the fact there's a thunk inside makes it a non-value |
| 22:10 | mmarczyk | but the potential infinity sort of sounds like a it's on the co- side of the relevant foo / cofoo divide :-P |
| 22:10 | ddellacosta | Is there any benefit to (or even any method for) using austin over piggieback if you are connecting to an already-started-app from an already started repl, the two being in different threads (that is, in contrast to the default example in the austin docs for connecting to an app)? |
| 22:10 | bbloom | mmarczyk: heh yeah |
| 22:10 | bbloom | ddellacosta: cemerick is the man to ask |
| 22:11 | ddellacosta | bbloom: true, thanks |
| 22:11 | ddellacosta | figured I'd throw it out there though, in case anyone else had an idea |
| 22:12 | cemerick | ddellacosta: didn't you just describe the "browser-connected REPL" use case, described in the README (vs. the "project REPL")? |
| 22:13 | cemerick | (all this nomenclature needs serious work) :-P |
| 22:13 | mmarczyk | bbloom: thanks for the anf link btw, love the function names :-) I'll read it properly this weekend, along with the Flanagan et al paper hopefully |
| 22:13 | bbloom | mmarczyk: my pleasure! i haven't read the flanagan stuff at all :-/ |
| 22:14 | ddellacosta | cemerick: um, yes, exactly--the big difference between your example and my use-case being that I have a script which starts up my app |
| 22:15 | mmarczyk | bbloom: re: lazy seqs, we'd have to give up value-based equality completely, not just equality with vectors, to avoid forcing to hash, which I guess is a complete no-go given the pervasive hidden (as in not explicitly asked for) laziness in the seq library |
| 22:15 | cemerick | ddellacosta: well, cljs' stock browser-REPL has a number of limitations that I used to hit regularly. Can't run multiple REPLs out of the same backend, need to shuffle port numbers around frequently, :cljs/quit shuts down the HTTP server until the next REPL session is created, etc. |
| 22:15 | ddellacosta | cemerick: and as far as what I've been able to figure out, it seems like I need to be running in the same thread to get the nrepl configuration working right, in terms of how values are set and where they are accessible. So I wondered if there was any value in it, since the default piggieback config is working pretty damn well (did you make that more robust? Haven't dug into the code yet). |
| 22:16 | cemerick | ddellacosta: not sure what you mean re: in the same thread? |
| 22:16 | bbloom | mmarczyk: yeah, i think it's past the point of no return. there isn't any way to solve this problem (that i can think of) that wouldn't involve dramatic sweeping changes to how laziness & evaluation works |
| 22:16 | dnolen | wow after core.async, the Promise/Rx dichotomy is JS is truly painful |
| 22:16 | dnolen | s/is/in |
| 22:16 | bbloom | dnolen: i believe you, but i'm curious what motivated you to say that |
| 22:17 | mmarczyk | dnolen: you mean core.async is a sort of a de-numbing agent? :-P |
| 22:17 | ddellacosta | cemerick: so, it's entirely likely I'm confused about something. But the example you have for the browser-connected repl assumes you are starting your app from the repl, so you have access to the loaded namespaces/values in that repl |
| 22:17 | dnolen | bbloom: I was just toying around with some benchmarks between core.async and when.js one of the fastest Promises/A+ libraries |
| 22:17 | dnolen | bbloom: and realizing so many of the things I've done are nearly impossible to express in terms of Promises. |
| 22:18 | dnolen | and how wasteful Promises are, it's a one off |
| 22:18 | bbloom | dnolen: yeah, i found that you needed a pretty large promise library for common patterns. things that are pretty easy with multiplexing |
| 22:19 | bbloom | dnolen: when i had no choice but to do js/coffee, i preferred async.js (which is callback combinator functions) |
| 22:19 | cemerick | ddellacosta: that's just the simple base case, where the REPL server port and session number are in-process, and so can be super-easily templated into your app |
| 22:19 | bbloom | it was basically the same as promises, but without the refied objects & with saner error handling semantics |
| 22:19 | cemerick | Nothing there is thread-related, tho. |
| 22:19 | seangrov` | ,(take 5 (iterate 10)) |
| 22:19 | clojurebot | #<ArityException clojure.lang.ArityException: Wrong number of args (1) passed to: core$iterate> |
| 22:20 | seangrov` | ,(take 5 (iterate inc 10)) |
| 22:20 | clojurebot | (10 11 12 13 14) |
| 22:22 | ddellacosta | cemerick: hmm, okay, I must be getting confused. To try to explain more completely, following the example for the browser-connected repl, when I call browser-connected-repl-js from cemerick.austin.repls in my routing, I get nil. I thought this was because I wasn't setting cemerick.austin.repls/browser-repl-env from within the same thread--my loaded ring app was not started via repl. |
| 22:22 | cemerick | ddellacosta: Just FWIW, if what you're doing now is working, carry on :-) Austin is by no means intended to be a the end-all-be-all of cljs REPLs. |
| 22:23 | ddellacosta | cemerick: oh, no--I just wanted to see if I wasn't mistaken about the use case! piggieback is definitely working, but I want to explore all the options so I can figure out what is possible, and also try to help if I can provide another way to smoothly get more use-cases working for the CLJS eco-system. |
| 22:24 | ToBeReplaced | cemerick: is there progress on strint/<< making it into core? |
| 22:24 | ddellacosta | cemerick: I figure, the more I am doing some yak-shaving to get my specific way of working going, if I can even just contribute some feedback and docs it will be useful to everyone. |
| 22:24 | cemerick | ddellacosta: if b-c-r-js is returning nil, then you haven't set the cemerick.austin.repls/browser-repl-env atom yet/properly |
| 22:25 | cemerick | definitely nothing thread-related there |
| 22:26 | cemerick | ToBeReplaced: Nope, not going to happen. I've been meaning to start distributing it in its own library, since right now it's basically marooned in incubator |
| 22:28 | ToBeReplaced | cemerick: is there discussion somewhere? anything going to happen in its place? |
| 22:28 | ddellacosta | cemerick: right, but it seems like, based in the example, it is assumed that you load repl-env in your running app from the same thread that you connect your repl, and therefore they have access to the same values. Because browser-repl-env is an thread-specific atom, if you don't start your app from the same thread you've set cemerick.austin.repls/browser-repl-env in, you can't access it when generating a script |
| 22:28 | ddellacosta | in the app. Does that make sense, or am I totally off? |
| 22:30 | ddellacosta | cemerick: argh, wait, I'm realizing the flaw in what I'm saying, hold on |
| 22:30 | cemerick | ToBeReplaced: The last discussion of string interpolation being in core was here in irc years ago. I would be very surprised if something like it ever landed in core. |
| 22:30 | cemerick | ddellacosta: yeah, you're thinking of vars and binding |
| 22:30 | ddellacosta | cemerick: yes, not atoms. D'oh. Sorry for the confusion! |
| 22:30 | ToBeReplaced | cemerick: thanks |
| 22:33 | cemerick | ddellacosta: gots to run. Ping later if you're still having issues :-) |
| 22:33 | ddellacosta | cemerick: thanks for being my sounding-board so as to let me talk myself into figuring out my mistake…haha. Thanks, cheers! I think I'm good for now. ;-) |
| 22:49 | seangrov` | Should ISeqable be extended to [object NodeList]? |
| 22:58 | dnolen | seangrov`: don't do it. just pass array likes into prim-seq |
| 23:02 | seangrov` | dnolen: Ah, that works nicely, thanks |
| 23:08 | dnolen | seangrov`: yeah it's just too easy to miss something, prim-seq covers the bases |
| 23:08 | cgag | anyone seen "peerUri undefined" when trying to connect the clojuresript browser repl? |
| 23:08 | dnolen | cgag: you cannot use file:// protocol, are you going to localhost:9000/foo.html ? |
| 23:09 | cgag | i am |
| 23:13 | cgag | https://www.refheap.com/17991 |
| 23:13 | cgag | basically all i have |
| 23:13 | cgag | the alert goes off |
| 23:13 | cgag | the first one at least |
| 23:14 | dnolen | quick post on latest core.async perf enhancements http://swannodette.github.io/2013/08/23/make-no-promises/ |
| 23:30 | dnolen | cgag: sounds like you're not specifying a version of ClojureScript in your project.clj |
| 23:31 | cgag | i just have lein-cljsbuild 0.3.2 and have been using that |
| 23:37 | cgag | it does seem to have generated a repl/clojure/browser folder |
| 23:37 | dnolen | cgag: specify a version, you can never trust what cljsbuild pulls in |
| 23:37 | cgag | i wonder if this is making some invalid assumptions about my directory structure |
| 23:37 | dnolen | cgag: 1859 is the latest |
| 23:43 | shaungilchrist | dnolen: awesome article noticed a typo in last sentence though - extra "the" after "providing" |
| 23:44 | dnolen | shaungilchrist: thx |
| 23:44 | shaungilchrist | your blog is a beacon of hope in a sea of callbacks |
| 23:48 | Apage43 | i.. |
| 23:48 | Apage43 | man. |
| 23:50 | cgag | dnolen: no dice :\ |
| 23:55 | cgag | my project file: http://pastebin.com/TiVVmDSB |