2014-03-17
| 00:00 | stcredzero | bbloom: Since I started using pmap, I |
| 00:00 | bbloom | stcredzero: there's practically zero chance pmap is a good idea in a game ever |
| 00:00 | stcredzero | I've started seeing strange errors |
| 00:00 | l1x | SegFaultAX: sorry to bother you, how could i filter with some in a nested structure where my collection is a vector of maps |
| 00:00 | bbloom | maybe clojurebot has something... |
| 00:00 | dnolen_ | seangrove: your basic idea isn't completely off base in my opinion - I haven't considered the transformer/path thing in the yr particularly context |
| 00:00 | bbloom | ~pmap |
| 00:00 | clojurebot | pmap is not what you want |
| 00:00 | bbloom | there we go ^^ lol |
| 00:00 | l1x | :) |
| 00:01 | stcredzero | bbloom: even if you use (vec) to force evalutation in well defined stages? |
| 00:01 | dnolen_ | seangrove: but I have considered how often the data you have is not in the form that a component needs yet you don't want to polluteyour app w/ logic about data transforms |
| 00:01 | bbloom | stcredzero: have you benchmarked pmap for your use case? |
| 00:01 | stcredzero | bbloom: I'm using pmap to handle execution in sub-grids. |
| 00:01 | dnolen_ | seangrove: I was mostly thinking about :instrument + some transformer fn, but it seems like you're interested in this making less of a edge case and more central |
| 00:02 | bbloom | stcredzero: i'm willing to bet that pmap is making your game slower, try it and see |
| 00:02 | stcredzero | bbloom: the purpose is to be able to handle over 90% of the game loop in parallel, with only the leftovers that need global coordination in a normal serial game loop |
| 00:02 | seangrove | dnolen_: It makes it highly amenable to static analysis + really fantastic tooling |
| 00:02 | seangrove | dnolen_: You can get highly-functional apps with all the goodies going through this |
| 00:03 | stcredzero | bbloom: It's probably making it slower now, but I'm hoping to support 1000's of entities/players |
| 00:03 | bbloom | stcredzero: benchmark. benchmark. benchmark. |
| 00:03 | seangrove | The danger is I might be going down the angular route and recreating basic concepts in a declarative way and introducing a bunch of complexity |
| 00:03 | bbloom | seangrove: that's my fear :-P |
| 00:03 | seangrove | bbloom: It's on my mind, certainly ;) |
| 00:03 | bbloom | seangrove: declarative UI doesn't work for programmers, it works for tools |
| 00:04 | bbloom | seangrove: which is OK if that's your goal, but you have to be clear about that |
| 00:04 | stcredzero | bbloom: the global world thing and the sub-grid thing are polymorphic, and except for boundary crossings, everything can execute with utter independence |
| 00:04 | seangrove | bbloom: The iterative bootstrapping process so far has been very promising in that regar |
| 00:04 | stcredzero | bbloom: I don't have to benchmark an architectural/algorithmic choice. The point is to have multi-core concurrency |
| 00:05 | bbloom | stcredzero: you're not hearing me.... or clojurebot :-P how many cores do you have? 2? 4? the overhead of communicating between them is likely to dwarf any benefit you get if you have thousands of game elements and they are small enough jobs to run every frame |
| 00:05 | bbloom | stcredzero: i've worked in games, if you want multi-core concurrency, you're much much better off parallelizing your stages: ie have rendering and gameplay running in parallel |
| 00:05 | stcredzero | bbloom: you're not hearing me. Except for boundary crossings, there *is no coordination* between subgrids. |
| 00:06 | bbloom | stcredzero: pmap has coordination |
| 00:06 | bbloom | (doc pmap) |
| 00:06 | clojurebot | "([f coll] [f coll & colls]); Like map, except f is applied in parallel. Semi-lazy in that the parallel computation stays ahead of the consumption, but doesn't realize the entire result unless required. Only useful for computationally intensive functions where the time of f dominates the coordination overhead." |
| 00:06 | bbloom | note the "only useful for" message |
| 00:06 | dnolen_ | seangrove: need to think about it some more - but it seems worth exploring. |
| 00:06 | bbloom | stcredzero: by definition, that's not true if you have thousands of entities |
| 00:06 | seangrove | dnolen_: It's all PoC still, but pretty excited about it. |
| 00:07 | stcredzero | bbloom: also, the game loop comes in stages which are parallelized. You're leaving out a step somewhere. As far as I know, things are going to be CPU bound. |
| 00:09 | stcredzero | bbloom: http://www.reddit.com/r/roguelikes/comments/1xa9rj/i_have_been_writing_a_pseudoroguelike_mmorpg_with/ -- for one thing, all entities are going to have interpreted source code that other entities can fsck with in real-time. Will be CPU-bound. |
| 00:09 | bbloom | stcredzero: even if that were the case, you don't want pmap |
| 00:10 | bbloom | stcredzero: pmap will create a ton of garbage, incur significant synchronization costs, and generally cost you far more CPU time than it will save you |
| 00:10 | stcredzero | bbloom: sub-grid game loops are basically conventional serial game loops. Things are architected so that the sub-grid loops *are not coordinating* (as much as possible) pmap just fires off each independent serial game loop in parallel |
| 00:11 | bbloom | stcredzero: i understand why you think it will be faster, but unless you benchmark it and tell me i'm wrong (i'm not) then we're both wasting our time |
| 00:11 | stcredzero | bbloom: however, it does make sense that pmap is creating a ton of garbage. |
| 00:12 | SegFaultAX | stcredzero: You're not understanding bbloom's point. pmap itself has inherent coordination overhead irrespective of what you might be using it for. |
| 00:12 | stcredzero | SegFaultAX: You can say the same for Erlang Actors. All of these things have inherent coordination overhead. |
| 00:12 | bbloom | stcredzero: except that that's a wildly different thing |
| 00:13 | SegFaultAX | stcredzero: That... has aboslutely nothing to do with what we're talking about. |
| 00:13 | bbloom | b/c erlang actors have independent GC heaps and run N-to-M threading |
| 00:13 | SegFaultAX | stcredzero: You can visualize a pmap as firing off a bunch of futures then joining on all of them. |
| 00:14 | stcredzero | bbloom: My understanding is that pmap is going to give me n to m threading. Yes, firing off a bunch of futures then joining. I don't have to have 100% utilization across time. If it looks like a sawtooth or square wave, that will be fine |
| 00:14 | bbloom | stcredzero: looking at your screenshots... is the game logic in cljs? or just the renderer? |
| 00:14 | SegFaultAX | stcredzero: Go measure, come back to us when you have a better sense of what's going on. |
| 00:14 | stcredzero | Just the renderer. |
| 00:15 | stcredzero | I can't really benchmark 1000's of entities until I have much more of the system built. |
| 00:15 | SegFaultAX | Then you're prematurely optimizing anyway. |
| 00:15 | bbloom | yes, that ^^ |
| 00:16 | bbloom | stcredzero: you probably don't need the game entities to remain sorted, if that's the case you're paying significant overhead for the atomic operations done by the futures in the pmap impl |
| 00:16 | stcredzero | I can just change all of those pmap to map. |
| 00:16 | bbloom | core.async is likely to provide proper multi-threaded improvements |
| 00:16 | stcredzero | bbloom: remain sorted? |
| 00:16 | SegFaultAX | stcredzero: But you've got a bunch of things in your head that you're mixing together. |
| 00:16 | bbloom | stcredzero: pmap preserves the sequence's order |
| 00:17 | stcredzero | bbloom: why should that incur a significant overhead? |
| 00:17 | bbloom | go to your repl and type (source pmap) |
| 00:17 | stcredzero | SegfaultX: what things? |
| 00:17 | bbloom | maybe you'll understand then, if you don't you have a lot more to learn about multithreading performance |
| 00:17 | bbloom | and you're only going to learn that from BENCHMARKING |
| 00:18 | devn | free idea: wiki-style editing of docstrings |
| 00:18 | devn | collaborative docstring writing, with a more wikipedia-like interface for editing what the code does |
| 00:18 | SegFaultAX | devn: I wish that's what clojuredocs became. |
| 00:19 | devn | SegFaultAX: you know, i keep sitting around wondering how we ended up where we are |
| 00:19 | SegFaultAX | Instead it's a relic which high google ranking that hasn't been updated in years. :( |
| 00:19 | bbloom | stcredzero: sorry to be harsh, really just trying to help |
| 00:19 | stcredzero | bbloom: so you're saying it's the when that's the source of the overhead? |
| 00:19 | devn | clojuredoc is good, clojuredocs is ok |
| 00:19 | devn | but it's sad no one has just sit down and replaced clojuredocs |
| 00:19 | devn | i need to make that my mission. |
| 00:19 | SegFaultAX | I wonder if the maintainer would be willing to yield control of the domain. |
| 00:20 | stcredzero | bbloom: That pmap is polling over a bunch of things to see when they are all done? |
| 00:20 | bbloom | stcredzero: i'm saying that pmap is rarely appropriate and even if you custom-tailor a solution for your problem, you'll likely have a hard time getting a perf win |
| 00:20 | devn | apparently that was discussed at some point |
| 00:20 | devn | i dont know the details |
| 00:20 | bbloom | stcredzero: no, it's not polling, it's blocking in order. |
| 00:20 | bbloom | stcredzero: also, since your game is going to have a server component, you're better off running GAMES in parallel |
| 00:20 | bbloom | stcredzero: ie different game world instances run on different cores |
| 00:20 | devn | SegFaultAX: do you want to remake clojuredocs? |
| 00:20 | bbloom | stcredzero: that will yield dramatically better CPU utilization and even more dramatically simpler code |
| 00:21 | devn | AKA do you have time to work on it? |
| 00:21 | SegFaultAX | devn: Update it with 1.4 1.5 1.6 |
| 00:21 | stcredzero | bbloom: so if I have 6 or so processors -- yes. I do plan on having different instances. That's part of the point I was making that you weren't paying attention to. |
| 00:21 | devn | SegFaultAX: forget the old site. let's just rewrite it and extract the content |
| 00:22 | devn | actually, you know what? i take back that idea. what we have is a rails application that could easily be updated |
| 00:22 | bbloom | pmap is still not the answer |
| 00:22 | stcredzero | bbloom: everything you've said fits in with my expectations, so unless yo ucan give me some big-O figures that aren't n(log32(n)) I don't think you quite have a point. |
| 00:22 | SegFaultAX | bbloom: Not worth the effort, dude. |
| 00:22 | bbloom | SegFaultAX: agreed |
| 00:22 | SegFaultAX | stcredzero: Go measure. |
| 00:23 | seangrove | Yeah, just benchmark, work from that |
| 00:23 | SegFaultAX | stcredzero: Show us that we're wrong with data. |
| 00:23 | devn | can someone catch me up on this conversation? |
| 00:24 | SegFaultAX | devn: Just some deep misunderstandings about how threads work (and pmap in particular) |
| 00:24 | trap_exit | is there a version of for, which takes two lists, as their _zip_, but not a cross product, i.e. lst1 = [1 2 3] lst2 = [1 2 3], I want [1 1], [2 2], [3 3], rather than [[1 1], [1 2], [1 3], [2 1], [2 2] [2 3], [3 1] [3 2] [3 3]] |
| 00:24 | stcredzero | if pmap is a good idea for independent CPU bound things, someone needs to give me a coordination cost that's worse than O(n*log32(n)) |
| 00:24 | stcredzero | devn: no, that's wrong. These guys don't understand what I'm proposing. |
| 00:24 | devn | ,(zipmap [1 2 3] [1 2 3]) |
| 00:25 | clojurebot | {3 3, 2 2, 1 1} |
| 00:25 | stcredzero | devn: as evidenced by their bringing up separate instances. I will have separate instances. |
| 00:25 | SegFaultAX | (map vector [1 2 3] [:a :b :c]) |
| 00:25 | SegFaultAX | ,(map vector [1 2 3] [:a :b :c]) |
| 00:25 | clojurebot | ([1 :a] [2 :b] [3 :c]) |
| 00:25 | devn | stcredzero: that too :) |
| 00:25 | devn | ,(repeat 2 [1 2 3]) |
| 00:25 | clojurebot | ([1 2 3] [1 2 3]) |
| 00:25 | trap_exit | so (for [ [a b] (map vector lst1 lst2)] ... ) ? |
| 00:26 | trap_exit | well, [1 2 3], [1 2 3] were specific lists; I want it work with generic lst1, lst2 |
| 00:26 | SegFaultAX | trap_exit: (fn [a b] (map vector a b)) |
| 00:26 | stcredzero | devn: I'm not after 100% parallelism. I'm looking for limited parallelism that looks like a sawtooth or square wave over time. Then the OS can coordinate between different instances to get me near 100% CPU utilization. |
| 00:26 | devn | are the same length? |
| 00:26 | trap_exit | not same length |
| 00:26 | bbloom | stcredzero: read the docstring again. you said thousands of items. the doc string literally explains that f needs to be expensive to justify it. if you are running f on thousands of items and you have less than tens of cores, and need real time responses, then pmap won't help you |
| 00:26 | trap_exit | but I only want to take pairs up to the shorter of the two |
| 00:27 | SegFaultAX | trap_exit: Then that's what you want. |
| 00:27 | bbloom | stcredzero: 100% CPU utilization isn't what you want... |
| 00:27 | SegFaultAX | trap_exit: What I just typed, that is. |
| 00:27 | stcredzero | bbloom: you re not p[aying attention. I'm running f on dozens of items to support 1000's of entities. |
| 00:27 | devn | stcredzero: i know we're typing into this thing that is supposed to contain smart people |
| 00:27 | devn | but i think we are just having a hard time communicating |
| 00:28 | devn | it sounds like there are reasons why you are choosing this approach |
| 00:28 | devn | but we dont know everything about your problem |
| 00:28 | SegFaultAX | ,((fn [a b] (map vector a b)) [1 2 3] [:a :b :c :d]) |
| 00:28 | clojurebot | ([1 :a] [2 :b] [3 :c]) |
| 00:28 | SegFaultAX | trap_exit: ^ |
| 00:29 | devn | ,(zipmap [1 2 3] [4 5 6 7]) |
| 00:29 | clojurebot | {3 6, 2 5, 1 4} |
| 00:29 | devn | it might work... just saying... |
| 00:29 | SegFaultAX | devn: I think he wants a list of pairs. |
| 00:29 | stcredzero | bbloom: f is expensive -- damn expensive in CPU. The parallelism isn't for each entity. It's for a much smaller number of chunks of the world that are independent. Each f is just a serial game loop running over many entities, which you seem all fired to tell me is going to be so efficient. I'm *counting on it*! |
| 00:29 | bbloom | stcredzero: i scrolled up and find no mention of you making that point :-P |
| 00:29 | devn | SegFaultAX: sure, but im just saying that's close enough for jazz |
| 00:29 | stcredzero | bbloom: search for where I talk about sub-grids. |
| 00:30 | devn | heh |
| 00:30 | bbloom | stcredzero: i'm looking at it, but i'm not a mindreader |
| 00:30 | devn | "ask me about the time i cured world hunger" |
| 00:30 | bbloom | stcredzero: still, even with dozens, i don't think you want pmap |
| 00:30 | stcredzero | bbloom: admit it, you were taling the whole time assuming I'm talking about paralleism per-entity. |
| 00:30 | devn | kidding of course, just sounded funny |
| 00:31 | devn | stcredzero: dude, this isn't a conspiracy |
| 00:31 | bbloom | stcredzero: i did think that, however, i still don't think pmap is what you want |
| 00:31 | bbloom | stcredzero: for every single reason i've listed |
| 00:31 | SegFaultAX | stcredzero: Why are you still not measuring? |
| 00:31 | stcredzero | bbloom: show me where pmap is costlier than O(n*log32(n)) and you win. Instantly |
| 00:31 | stcredzero | bbloom: I can't measure yet. |
| 00:31 | devn | algorithm designs are meant to be tested |
| 00:31 | bbloom | stcredzero: if you can't measure yet, you can't optimize yet |
| 00:31 | bbloom | stcredzero: and constants matter |
| 00:31 | bbloom | a lot |
| 00:31 | stcredzero | bbloom: I can design. |
| 00:31 | bbloom | especially in threading |
| 00:32 | devn | stcredzero: see my previous comment |
| 00:32 | bbloom | stcredzero: i've been writing multithreaded web services AND games for years and i'd like to think i'm pretty good at it. not once has my first design been within many orders of magnitude of the winning design |
| 00:32 | devn | amen |
| 00:33 | bbloom | hell, i've fixed multithreading bugs in the tools for finding multithreading bugs in xbox games |
| 00:33 | bbloom | and even that took a few tries :-P |
| 00:33 | stcredzero | bbloom: I used to say that stuff to meetup audiences. |
| 00:34 | bbloom | stcredzero: i don't know why you think we're out to get you |
| 00:34 | bbloom | we're trying to help |
| 00:34 | stcredzero | bbloom: also in your commentary, are you assuming there's any coordination between f's? |
| 00:34 | bbloom | nope |
| 00:34 | stcredzero | bbloom: so you're telling me that the coordination is O(n*log(n)) but that the constant factors are ungodly huge. |
| 00:35 | bbloom | stcredzero: i'm done arguing until you come back with numbers |
| 00:35 | SegFaultAX | stcredzero: No, he's telling you that it isn't worth it if the overhead of `f` applied to each chunk isn't greater than the coordination overhead of pmap. |
| 00:35 | kras | HI Again. Any recommendations for network/graph library in clojure? Something equivalent to networkx in python. |
| 00:35 | seangrove | stcredzero: bbloom is a good guy, worht listening to, even if he comes across as borderline crazy ;) |
| 00:36 | bbloom | seangrove: surely you know i'm full on crazy by now! |
| 00:36 | stcredzero | I'm suspecting that no one knows what the ovehead of pmap is. |
| 00:36 | trap_exit | SegFaultAX: noted, thanks! |
| 00:36 | SegFaultAX | stcredzero: Well, that's because it depends on lots of stuff. |
| 00:37 | bbloom | stcredzero: no one is guessing b/c we're explicitly telling YOU not to guess |
| 00:38 | SegFaultAX | stcredzero: Mind it could be possible that pmap nets you a gain in performance (unlikely, but possible) but some very specific conditions have to be met before that's at all likely. |
| 00:38 | SegFaultAX | And even if those conditions are met, pmap is still probably not the tool you need for a tight game loop. |
| 00:38 | SegFaultAX | (It's too broad a hammer) |
| 00:38 | stcredzero | SegFaultAX: That informatino would be much more useful than the catch-22 you're presenting me with. I'm trying to come up with a new architecture. |
| 00:39 | SegFaultAX | pmap is a sledge and you need a ball pene to have consistent processing time per frame. |
| 00:39 | SegFaultAX | stcredzero: How is "go measure and come back with data" a catch 22? |
| 00:39 | stcredzero | SegFaultAX: So you guy's position is that I shouldn't even try/that I should benchmark something I don't have completed to benchmark, and that I'm damned because I'm prematurely optimizing. Of course I'm going to measure the thing! |
| 00:40 | SegFaultAX | stcredzero: Then why are we arguing? It's not like s/pmap/map/g is that hard to type. |
| 00:41 | stcredzero | But I'm ddamned for trying it in the first place as a premature optimizer. You're telling me you have a good a-priori guess that I should just have serial game loops. I'm arguing because I don't feel like you were inclined to listen and just wanted to play the "inform the noob" game and so overlayed a bunch of noob assumptions over what I was doing instead of actually listenting to my proposal. |
| 00:42 | SegFaultAX | stcredzero: Ok. Let us know when you have measurements. Good luck! |
| 00:42 | stcredzero | As evidenced by the assumptsions that f would be cheap, that parallelism was per-entity, etc. |
| 00:44 | stcredzero | What would be actually helpful is to let me know what things pmap is not going to like in more detail. |
| 00:50 | technomancy | stcredzero: answering questions on IRC is largely a matter of pattern matching |
| 00:57 | kras | HI Again. Any recommendations for network/graph library in clojure? Something equivalent to networkx in python. |
| 00:58 | kras | I don't require many algorithms, performance is the prime criterion |
| 00:59 | kras | titanium, loom??? |
| 00:59 | lazybot | kras: Yes, 100% for sure. |
| 00:59 | stcredzero | technomancy: I have it when people keep insisting I'm saying something I'm not, especially in the face of my informing them I'm saying what I'm actually saying. |
| 00:59 | stcredzero | "have it" is mistyped v = t |
| 01:00 | technomancy | stcredzero: haven't been paying attention to the discussion, just throwing that out there |
| 01:00 | beamso | kras: https://github.com/prismatic/plumbing ? |
| 01:00 | technomancy | I know my first instinct when I hear newcomers to Clojure ask about records is just to tell them not to use them |
| 01:01 | stcredzero | technomancy: I think your comment was very apt. |
| 01:01 | technomancy | (even if I have no idea what the actual answer is) |
| 01:02 | stcredzero | technomancy: because they were pattern matching, getting the details of my proposal wrong, then arguing from their pattern-match based assumptions |
| 01:03 | technomancy | hey, it's a 95%-effective approach |
| 01:03 | stcredzero | technomancy: then when I tried to inform them of their incorrect assumptions, they used that as evidence that I don't know what things are...like threading. |
| 01:03 | stcredzero | My esoteric projects are 5% ideas. |
| 01:03 | technomancy | (this is why we have bots) |
| 01:06 | stcredzero | technomancy: People are behaving more like bots, and the implicit assumptions is that everyone just mechanically falls into cubbyholes that are even more efficiently delineated for us through the information dissemination power of the INternet |
| 01:08 | technomancy | everyone does it |
| 01:08 | technomancy | the real world is too complicated to function any other way |
| 01:08 | technomancy | you see someone dress a certain way and you make assumptions about their personality |
| 01:09 | technomancy | because it's far more efficient than finding out for yourself |
| 01:09 | amalloy | technomancy: he left after cubbyholing everyone |
| 01:09 | technomancy | amalloy: well you know what they say about people who leave in the middle of IRC conversations |
| 01:10 | amalloy | they rarely get answers they're happy with? |
| 01:10 | technomancy | that they bloody well should learn how bouncers work |
| 01:10 | zspencer | ZNC + irsssi |
| 01:11 | technomancy | kind of annoyed that he ended up thinking I was just encouraging him |
| 01:11 | beamso | or screen + irssi |
| 01:12 | zspencer | ZNC allows multi-client so you can limechat in when you're afk |
| 01:12 | technomancy | tmux allows mosh though |
| 01:12 | technomancy | |
| 01:12 | zspencer | But yes, a screen/tmux terminal is good stuff |
| 01:19 | bbloom | technomancy: he just switched to defensive mode instantly and then demanded answers to questions that showed that we had correctly cubby holed him :-P |
| 02:14 | stcredzero | What's the fastest way to go from a map that contains a bunch of defrecord objects as values to a collection that contains futures executing functions on those values? |
| 02:53 | noidi | if you want to retain the keys, then (into {} (for [[k v] m] [k (f v)]) is a common approach to mapping over a map's values |
| 02:54 | noidi | if you only need the values then (map f (vals m)) |
| 02:54 | noidi | AFAIK that's fastest as in fastest to type in the editor :) |
| 03:09 | antonv | hi |
| 03:09 | antonv | any cider users here? |
| 03:10 | wink | even if it's St. Patrick's Day, I'll wait a few hours with that :) |
| 03:11 | antonv | when I execute an expression with C-x C-e and the expression has error, then a stack trace buffer shows up |
| 03:11 | antonv | is there a shortcut to close it quickly, without havign to switch to that buffer by C-o first? |
| 03:12 | antonv | C-x o I mean |
| 03:12 | antonv | in SLIME I can just press q |
| 03:12 | antonv | and the debugger buffer closes |
| 03:13 | antonv | but in cider I must switch to the buffer - tedious |
| 03:15 | antonv | OK, added (setq cider-auto-select-error-buffer t) to the .emacs |
| 03:15 | antonv | not the error buffer is selected automatically, I just press q and it closes |
| 05:43 | chare | do you guys use intellij |
| 05:43 | chare | or use just cursive? |
| 05:51 | wink | LightTable for Clojure and Lua, IDEA for all other languages |
| 05:58 | clgv | eclipse/counterclockwise |
| 07:11 | Pate_ | how is Clojure's multimethod support implemented, specifically the dispatch function? |
| 07:12 | nightfly | probably with a hashmap and lambdas |
| 07:12 | Pate_ | found this: https://github.com/clojure/clojure/blob/0b73494c3c855e54b1da591eeb687f24f608f346/src/jvm/clojure/lang/MultiFn.java |
| 07:13 | Pate_ | these is an IPersistentMap methodTable that caches the "preferred method" for a given dispatch. |
| 07:14 | Pate_ | sorry, the methodTable has all the possible methods and preferTable caches the preferred method. |
| 07:35 | clgv | Pate_: why do you ask for implementation details? just for learning and understanding? |
| 07:35 | Pate_ | yes. |
| 07:36 | Pate_ | I wanted to know how dispatch methods are implemented, because I felt they were functionally equivalent to an if...else on some type condition. And basically they are, but the result is cached. |
| 07:43 | pepijndevos | What is the relation between :gen-class, :aot and :main? Do I need all 3 to get a class with public static void main in it? |
| 07:45 | sm0ke | pepijndevos: gen-class is one way for defining java classes in clojure, :aot and :main are leinigen specific |
| 07:46 | clgv | Pate_: yeah in prinziple they are like a "cond" or "case" but open for dynamic extension |
| 07:46 | pepijndevos | sm0ke, right, but if I want to do lein uberjar, I'll need both aot, and gen-class with a (def -main), right? |
| 07:46 | sm0ke | pepijndevos: in clojure evrything is compiled to bytecode at the moment it is required, :aot is for doing it ahead of time |
| 07:46 | pepijndevos | runnable uberjar that is |
| 07:46 | clgv | pepijndevos: yes. :gen-class in the namespace of the -main method and :main and :aot in project.clj |
| 07:46 | sm0ke | pepijndevos: yes that is correct, if you want to invoke it like 'java -jar myjar.jar' |
| 07:47 | pepijndevos | cool. thanks |
| 07:48 | pepijndevos | Was unsure if gen-class was still needed with :aot. I guess ahead of time compilation does not nececerily mean generating classes. |
| 08:00 | gfredericks | well it doesn't mean generating the particular class that gen-class generates |
| 08:00 | gfredericks | it does generate lots of other classes |
| 08:02 | gfredericks | usually the point of using gen-class is to make a class with a .main method |
| 08:02 | gfredericks | and you don't have one of those otherwise |
| 08:38 | jespada | any hint/example on how to use log4j triggering-policy (SizeBasedTriggeringPolicy) trying to add that to https://github.com/aphyr/riemann/blob/master/src/riemann/logging.clj#L82 |
| 08:39 | jespada | failing..https://gist.github.com/jespada/729531b539ff6d556c1e |
| 08:51 | AeroNotix | w00t just bought my EuroClojure ticket! |
| 08:52 | AeroNotix | http://euroclojure.com/2014/ |
| 08:52 | AeroNotix | anyone else going? |
| 09:55 | wagjo | AeroNotix: I'm going |
| 09:55 | AeroNotix | wagjo: in KRK already or ? |
| 09:56 | wagjo | AeroNotix: 3 hours by car from my place |
| 09:56 | wagjo | AeroNotix: It was an offer I could not refuse :) |
| 09:57 | AeroNotix | wagjo: indeed :) Our office is going (3 clojure people!) woot |
| 09:57 | AeroNotix | looking forward to it |
| 09:57 | hyPiRion | I'm tempted, but money |
| 09:58 | AeroNotix | hyPiRion: where you at? |
| 09:58 | mpenet | going too, not sure from where yet though |
| 09:58 | AeroNotix | Norway iirc? hyPiRion |
| 09:58 | hyPiRion | Oh hey I'm still a student at that moment I guess |
| 09:58 | hyPiRion | yeah |
| 09:58 | mpenet | ppl going are staying where (hotel)? |
| 09:58 | wagjo | AeroNotix: Well you have it like 15 minutes, it would be shame not to go :) |
| 09:58 | AeroNotix | hyPiRion: dude, 70EUR |
| 09:58 | AeroNotix | wagjo: it's right down the road from my flat |
| 09:58 | AeroNotix | :D |
| 09:58 | hyPiRion | AeroNotix: that's not the costly part though. Planes and hotel is the main issue |
| 09:59 | mpenet | Hotel are kind of cheap there |
| 09:59 | AeroNotix | but yeah, places are cheap |
| 10:00 | hyPiRion | ah, you guys |
| 10:01 | mpenet | planes on the other hand... not sure a lot of low cost go to Krakow |
| 10:03 | hyPiRion | dang, I'm planning to move around that time too. hnggg |
| 10:17 | AeroNotix | n_b-: |
| 10:17 | AeroNotix | oops |
| 10:17 | AeroNotix | depends where you're coming from in EU |
| 10:17 | AeroNotix | from the UK, really, reall cheap. |
| 10:18 | hyPiRion | Yeah, it wasn't that expensive. I'm just scarred after the conj plane ticket I guess |
| 10:19 | AeroNotix | hyPiRion: where are you coming from? |
| 10:19 | hyPiRion | TRH |
| 10:20 | hyPiRion | Trondheim |
| 10:20 | AeroNotix | aha |
| 10:21 | hyPiRion | It's like 160-180 € for a return ticket |
| 10:24 | AeroNotix | Not too bad, but still. |
| 10:40 | devn | ticket prices were bad for me |
| 10:40 | devn | I think I paid 630USD |
| 10:40 | AeroNotix | devn: you're coming from the US? |
| 10:40 | devn | and I'm in the US |
| 10:40 | AeroNotix | to KRK? |
| 10:40 | devn | no, to SFO |
| 10:40 | AeroNotix | ah |
| 10:40 | devn | sorry, i caught the tail end of this conversation |
| 10:40 | devn | i saw "conj plane ticket" |
| 10:40 | devn | and assumed you were talking about clojure/west |
| 10:40 | AeroNotix | well, we were just talking generally :) |
| 10:41 | AeroNotix | primarily about euroclojure |
| 10:41 | devn | i realllllly want to go |
| 10:41 | AeroNotix | then do! |
| 10:41 | devn | im going to have to submit a CFP |
| 10:41 | devn | when does the CFP end? |
| 10:41 | devn | poland looks beautiful. |
| 10:41 | AeroNotix | I don't know what a CFP is |
| 10:41 | devn | Call For Proposals |
| 10:41 | AeroNotix | ohh April 16th |
| 10:41 | devn | I'd need to give a talk if I want to go |
| 10:41 | AeroNotix | iirc |
| 10:41 | devn | my company will pay if I go that route |
| 10:42 | AeroNotix | awesome, do eeet |
| 10:42 | devn | otherwise, I've spent too much on conferences this year already |
| 10:42 | AeroNotix | : |
| 10:42 | devn | yeah man, im thinking about giving a hoplon talk |
| 10:42 | katratxo | cemerick: ping? |
| 10:42 | BartAdv | hoplon talk would be great |
| 10:42 | clojurebot | Pardon? |
| 10:43 | devn | BartAdv: yeah, i've been getting into it. My friend Matt was working on this: https://github.com/mathias/gnar |
| 10:43 | devn | He built that in like a day with no hoplon experience |
| 10:43 | devn | "Rapid Prototyping in Hoplon" |
| 10:43 | devn | something like that is kind of what I'm thinking |
| 10:46 | devn | so, now that we're talking about /that/ plane ticket... 1,622 USD |
| 10:46 | AeroNotix | yikes |
| 10:46 | AeroNotix | I just take a walk and boom I'm there :) |
| 10:46 | devn | not a big surprise honestly |
| 10:47 | devn | haha |
| 10:47 | devn | travel time is like 13hours |
| 10:47 | AeroNotix | ouch >< |
| 10:47 | devn | probably more like 16 including getting to the airport and all of that |
| 10:48 | devn | but that's fine. i'd love to see poland |
| 10:48 | AeroNotix | luckily in KRK the airport is 10 minutes away from the centre |
| 10:48 | devn | i think i'll probably go for an extra week |
| 10:48 | AeroNotix | and there's a train which comes directly from the terminal |
| 10:48 | devn | AeroNotix: are you in poland? |
| 10:48 | AeroNotix | I am, yeah. |
| 10:48 | AeroNotix | I'm not Polish, though. |
| 10:48 | devn | ah, cool. hi! :) |
| 10:48 | AeroNotix | hi :) |
| 10:49 | devn | i'd love to chat more, but i need to get some work done. slow morning for me so far. |
| 10:49 | devn | see you poland! :) |
| 10:49 | AeroNotix | you too, cya! |
| 11:36 | katox | just opened mwjs to see pete hunt citing rich hickey ;) http://mtnwestjs.org/live |
| 11:37 | arrdem | oh awesome, we got accepted for GSoC 14 :D |
| 11:37 | mdrogalis | arrdem: :) |
| 11:38 | arrdem | mdrogalis: :P it's internship applciation season so I'm not entirely neutral here |
| 11:38 | arrdem | haxxing clojure for a summer would be pretty sweet. |
| 11:40 | mdrogalis | arrdem: Hah, nice |
| 11:43 | ambrosebs | arrdem: are you a student? |
| 11:44 | arrdem | ambrosebs: yarp |
| 11:44 | arrdem | ambrosebs: junior at U of Texas at Austin |
| 11:45 | ambrosebs | arrdem: about 4 days left until student applications close FYI |
| 11:45 | arrdem | ambrosebs: I'm well aware. |
| 11:45 | eric_normand | ambrosebs: how's the mentor search going? |
| 11:45 | arrdem | ambrosebs: that's one of the reasons I'm mentioning it here :P |
| 11:46 | ambrosebs | eric_normand: picked up a few helpers :) |
| 11:46 | ambrosebs | eric_normand: thanks for the help |
| 11:46 | seubert | arrdem: congrats, you survived SXSW for another year |
| 11:46 | seubert | :P |
| 11:46 | arrdem | seubert: meh... two of my friends got hit in the "accident". |
| 11:46 | seubert | arrdem: :( :( :( |
| 11:46 | arrdem | are okay, but met. |
| 11:46 | eric_normand | ambrosebs: you're welcome. that's what the gazette is for |
| 11:46 | arrdem | *meh |
| 11:47 | seubert | arrdem: i was really close to going down there that night, glad i didn't |
| 11:47 | seubert | glad your friends are ok |
| 11:47 | seubert | brutal shit |
| 11:48 | ambrosebs | arrdem: are you applying this year? |
| 11:48 | arrdem | ambrosebs: probably. just pinged deepbluelambda to chat about his lightweight clojure idea |
| 11:49 | arrdem | ambrosebs: looking for an excuse to play with Clojure compilers over the summer tbh :P |
| 11:49 | ambrosebs | arrdem: great |
| 11:58 | cemerick | dnolen_: FYI, https://github.com/clojure/clojurescript/commit/0c7b31ada01237de33cef77b817ccef3f2b3576d changed closure/build so that it never returns a string containing the compilation output; (output-one-file ...) isn't in a return position. |
| 12:00 | katratxo | cemerick: do yo think this friend change makes sense? https://gist.github.com/iperdomo/9596103 |
| 12:01 | cemerick | katratxo: I have it open in a tab, but haven't looked at it yet. |
| 12:02 | katratxo | cemerick: ok, no problem it's not urgent ;) |
| 12:03 | dnolen_ | cemerick: fixed in master now, thanks |
| 12:04 | cemerick | dnolen_: thanks; new patch on 656 coming your way right after I rebase and check against master again |
| 12:18 | juxovec | What you would do if function has too many args? http://stackoverflow.com/questions/22459629/what-to-do-when-function-has-too-many-arguments |
| 12:21 | bbloom | juxovec: much more info needed about your problem |
| 12:23 | dpritchett_ | i'm no clojure expert but my first thought is "write functions that don't need six parameters". I'm sure your actual problem is more complicated than that though |
| 12:23 | juxovec | bbloom: right now my controller gives to view results from model + actual data for form + data for grid orderby orderbydirection. |
| 12:24 | juxovec | It goes slowly, in the beginning only one argument was needed but it grows over time. |
| 12:26 | clgv | juxovec: do you need something like that? https://github.com/guv/clojure.options |
| 12:28 | juxovec | clgv: what would help can be named non-optional args which are checked on compile time |
| 12:29 | dnolen_ | juxovec: #1 is the only acceptable solution in my opinion. If you really want compile time checking you should look at Typed Clojure |
| 12:31 | juxovec | dnolen_: I tried to add Typed Clojure to the project and my productivity went down maybe 60 %. Now I use only schema where I check most important dataflows. But thanks. |
| 12:34 | S11001001 | “its called FAIL LOUD DESIGN... its designed to attract human admin attention if this fails” |
| 12:35 | S11001001 | "200 lines of code and zero added features beats 100 lines of code and 5 features" |
| 12:42 | shep-werk | juxovec: In OO world, we usually find collections of parameters can be wrapped into a cohesive object |
| 12:42 | clojurebot | Gabh mo leithscéal? |
| 12:43 | shep-werk | so, stick them all into a map :-) |
| 12:44 | Raynes | juxovec: You measure your productivity in actual percentages? |
| 12:44 | Raynes | Also, https://stackoverflow.com/questions/22459629/what-to-do-when-function-has-too-many-arguments is you? |
| 12:44 | dpritchett_ | Yeah as a Rubyist I was tempted to recommend using a closure to store a pre-configured object and manipulating it directly |
| 12:44 | dpritchett_ | but I am not gonna contradict dnolen_ |
| 12:45 | juxovec | Raynes: it just seems to me that with Typed Clojure I need three times more time to do anything |
| 12:52 | bbloom | juxovec: when you have too many arguments, you have to first decide if you need to simplify your problem or simplify your solution (or both!) |
| 12:52 | bbloom | juxovec: are the arguments related to the problem domain or the solution domain? |
| 12:53 | juxovec | as I wrote, I pass arguments from controller to view, its couple of results from models + some data for ordering and filtering data in datagrid (all are validated and modified query params) |
| 13:16 | mdrogalis | Can someone please help me write a little macro to do this? https://gist.github.com/MichaelDrogalis/9603819 |
| 13:16 | mdrogalis | I'm stuck on figuring out how to be able to use x by name in the body. |
| 13:17 | justin_smith | mdrogalis: ~'arg iirc |
| 13:17 | justin_smith | ~'x in your case |
| 13:17 | clojurebot | Gabh mo leithscéal? |
| 13:17 | justin_smith | now to actually try writing that macro |
| 13:18 | mdrogalis | Thanks, justin_smith. |
| 13:19 | danno1 | If strings are interned already aren't keywords irrelevant? |
| 13:20 | llasram | danno1: Not all strings are interned, and interned string != identical object |
| 13:21 | llasram | ,((juxt = identical?) '^:a foo '^:b foo) |
| 13:21 | clojurebot | [true false] |
| 13:21 | danno1 | liasram: Oh so, so strings can be instantiated? |
| 13:21 | technomancy | plus strings are final |
| 13:21 | llasram | Yeah, that too... |
| 13:21 | technomancy | so you can't make them ifn |
| 13:21 | justin_smith | mdrogalis: (defmacro guarded [val & body] `(when-let [~'x ~val] (when (not= ~'x ::poison-pill) ~@body))) |
| 13:21 | justin_smith | works for me in my repl |
| 13:22 | llasram | mdrogalis, justin_smith: Why not just use an autogensym? |
| 13:22 | justin_smith | llasram: (guarded 2 (+ x 1)) |
| 13:22 | llasram | Oh, specifically for evil. Got it |
| 13:22 | justin_smith | should return 3 |
| 13:22 | clojurebot | Excuse me? |
| 13:22 | justin_smith | that's what I assumed, at least :) |
| 13:23 | mdrogalis | Hmm |
| 13:25 | mdrogalis | Works great, thanks justin_smith! |
| 13:25 | justin_smith | np, I made something similar for an ill-considered DSL ages ago |
| 13:25 | justin_smith | I reconsidered the technique, but will never forget how it was done |
| 13:25 | justin_smith | lol |
| 13:26 | justin_smith | next time someone asks I should just be like "I know how to do that, but I'm a changed man general, I don't do that kind of work any more" |
| 13:27 | justin_smith | the evils I have commited against hygeine will haunt me forever |
| 13:27 | mdrogalis | Yeahhh. |
| 13:27 | llasram | Mmm, context |
| 13:27 | justin_smith | heh |
| 13:28 | mdrogalis | I was stuck on trying to pass the entire bindings vector to the macro. |
| 13:28 | mdrogalis | Obviously couldn't unroll it easily. |
| 13:29 | justin_smith | yeah, that's what I was doing, basically making a custom bindings vector |
| 13:30 | mdrogalis | Ah |
| 13:37 | dnolen_ | seangrove: ping |
| 13:38 | seangrove | dnolen_: pong |
| 13:39 | dnolen_ | seangrove: so read over your copy from yesterday a few more times - it is very close to some ideas I had floating around (I was getting thrown off the code since there are some types :) |
| 13:39 | seangrove | dnolen_: It's all shambolic right now, I don't expect to keep much code from this phase, but the ideas are panning out really well for tooling. |
| 13:39 | dnolen_ | seangrove: for higher level tooling your approach makes sense - breaking the relationship between the structure needed by a component and what actually appears in the app state. definitely something I allude to in my tutorials - but your taking it a bit further. |
| 13:40 | dnolen_ | seangrove: in any case, I like how simple the idea is really - I would probably just write a couple more drafts to make the point clearer |
| 13:41 | dnolen_ | seangrove: your org file made much more sense to me than the other materials |
| 13:41 | seangrove | dnolen_: Cheers, appreciate it. I think if I remove serializable notes from the code, it can simplify it further (no need for the registry, etc.). I can introduce that later. |
| 13:44 | upwardindex | Is performance and java interop the two most important reasons for protocols? |
| 13:44 | justin_smith | upwardindex: they also help a lot with the fact that clojure namespaces cannot be recursive |
| 13:45 | technomancy | upwardindex: yeah |
| 13:45 | justin_smith | ie. a.b cannot require a.c while a.c also requires a.b |
| 13:45 | justin_smith | with a protocol that both can see, you can flatten out the cyclic dep |
| 13:46 | technomancy | eh; you can also do that with multimethods and resolve |
| 13:46 | technomancy | s/and/or/ |
| 13:46 | justin_smith | which brings us back to performance of course |
| 13:46 | justin_smith | fair enough :) |
| 13:47 | llasram | upwardindex: And the fact that protocols may be `reify`d |
| 13:47 | upwardindex | technomancy: justin_smith: thanks! I'll keep using multimethods and not worry too much about not feeling the need for protocols :D |
| 13:51 | gf3 | Is there cool pattern matching to match any item? e.g.: |
| 13:51 | gf3 | (remove #{[:b _]} [[:a 1] [:b 2] [:c 3]]) |
| 13:52 | gf3 | for _ |
| 13:52 | rasmusto | gf3: https://github.com/clojure/core.match ? |
| 13:52 | amalloy | gf3: (remove (comp #{:b} first)) |
| 13:52 | rasmusto | amalloy: hah, or that |
| 13:53 | gf3 | amalloy: Balls, was hoping for something a bit more declarative |
| 13:53 | gf3 | amalloy: Thank you |
| 13:54 | dnolen_ | gf3: you could write a little function sugar over core.match |
| 13:54 | amalloy | more declarative? i hereby declare that elements whose first item is :b shall not be permitted in this list! |
| 13:54 | llasram | heh |
| 13:54 | gf3 | amalloy: haaah haaahahaha |
| 13:54 | amalloy | seriously though i don't see how #{[:b _]} would be any more "declarative" |
| 13:55 | amalloy | it's more...recognizable, in that the shape of the solution hints at the shape of the problem |
| 13:55 | dnolen_ | (pat [:b _]) -> (fn [x] (match [x] [:b _] true :else false)) or whatever |
| 13:56 | gf3 | dnolen_: Cool |
| 13:57 | dnolen_ | gf3: you get all the fancy matching stuff for free o' course, maps etc. |
| 13:57 | gf3 | dnolen_: Indeed, and it works ootb if I specify an exact match which is neat |
| 14:02 | dbasch | is there a tried-and-true way to do user/pass management in a compojure web app? |
| 14:03 | justin_smith | dbasch: basic auth, or setting a cookie, or? |
| 14:03 | dbasch | justin_smith: mostly the db side of things |
| 14:03 | Raynes | I use environment variables for pretty much all configuration of my web apps. |
| 14:04 | dbasch | the one thing I don't want to reinvent if possible is storing/looking up users and hashed passwords |
| 14:04 | justin_smith | dbasch: use a method that checks a hash, store the login and hash in the db |
| 14:04 | justin_smith | there is not much to reinvent there |
| 14:05 | justin_smith | unless what you are really asking about is a db schema dsl / lib |
| 14:05 | dbasch | justin_smith: that's what I'll do, I just wondered if there was a small library that did it already |
| 14:05 | technomancy | ...and by hash he means bcrypt |
| 14:05 | dbasch | technomancy: or scrypt |
| 14:05 | technomancy | right; just not sha1 or md5 |
| 14:05 | technomancy | just so we're clear on that |
| 14:06 | dbasch | technomancy: exactly |
| 14:06 | justin_smith | technomancy: unless you mean basic auth, bcrypt is not appropriate for basic auth, it is good for log in once and store a "logged in" cookie |
| 14:06 | technomancy | ~guards |
| 14:06 | clojurebot | SEIZE HIM! |
| 14:06 | dbasch | seangrove: retweeted |
| 14:07 | seangrove | dbasch: Looks like there might be something in lib-noir http://www.luminusweb.net/docs/security.md |
| 14:07 | seangrove | I don't think I'd bother with it too much, but who knows |
| 14:07 | dbasch | seangrove: I'll just do it myself, it's fun anyway |
| 14:07 | justin_smith | we had a minor debacle where I set up what was supposed to be a "generic authentication field" for our modeling system, and someone decided to attach it to basic auth (which gets checked on every single request) and performance was really really bad. |
| 14:08 | technomancy | ouch |
| 14:08 | dbasch | justin_smith: I'm giving the user a token that lasts for a while, so that's not an issue for me. This is an api |
| 14:09 | justin_smith | great, then bcrypt is awesome for that |
| 14:09 | firefaux | does anybody know how I would go about making a "pointer" in a data structure node on disk to another node? |
| 14:09 | firefaux | I know I could use filenames, but those would vary in length |
| 14:09 | justin_smith | sounds like you want a synthetic identifier |
| 14:10 | justin_smith | http://en.wikipedia.org/wiki/Surrogate_key |
| 14:10 | justin_smith | uuid is good for that kind of thing, that can be portable across boxes / db engines if need be |
| 14:11 | firefaux | isn't UUID for identifying disc partitions? |
| 14:11 | justin_smith | it is for anything that needs to be universally unique |
| 14:11 | firefaux | ok |
| 14:11 | firefaux | and java has an API for that? |
| 14:11 | firefaux | ah yes |
| 14:12 | firefaux | java.util.UUID |
| 14:12 | justin_smith | ie. you know two different systems / components won't generate conflicting ones, so you can refer to them seamlessly on distributed setups |
| 14:12 | justin_smith | yeah, it has a method to create random ones |
| 14:12 | justin_smith | and they are big enough that conflicts are vanishingly unlikely |
| 14:13 | justin_smith | ,(java.util.UUID/randomUUID) |
| 14:13 | clojurebot | #uuid "796d597c-3204-4854-b218-43ea2a710cd0" |
| 14:13 | justin_smith | ,(str (java.util.UUID/randomUUID)) |
| 14:13 | clojurebot | "d2e164c6-c08f-4756-84a1-9f25af3183eb" |
| 14:14 | firefaux | cool |
| 14:14 | firefaux | but then how do I actually assign a UUID to a file? |
| 14:15 | justin_smith | probably via a relational db? |
| 14:16 | firefaux | so doesn't that mean the relational db would have to store all of the filenames? |
| 14:17 | firefaux | along with their associated UUID? |
| 14:17 | justin_smith | it sounds like it would be a good idea for you to step back and design the data schema / architecture before solidifying things though (not really knowing any of your details of course) |
| 14:17 | justin_smith | right |
| 14:17 | firefaux | okay |
| 14:17 | justin_smith | or you could have a function from filename to UUID - it really depends on your constraints |
| 14:17 | justin_smith | ie. what kind of dir structure / naming convention limits you can / should impose etc. etc. |
| 14:18 | firefaux | well this is for an assignment, creating a BTree which maps String keys to URLs |
| 14:18 | firefaux | and I can set a reasonable limit on the key size |
| 14:19 | firefaux | but obviously URLs must be variable length |
| 14:19 | firefaux | of course, I could always use something like tinyurl... |
| 14:19 | justin_smith | also a URL does not have to map directly to the directory structure (though that is of course simpler) |
| 14:19 | firefaux | I was thinking I would put URLs in their own files |
| 14:20 | firefaux | and have a "pointer" in the datastructure to those files |
| 14:20 | justin_smith | you could also use a hashing system of some sort (which is what tinyurl is doing) |
| 14:21 | justin_smith | and of course their urls are not referring to a directory structure directly, there is a db in the middle, mapping hashes to strings |
| 14:23 | amalloy | what are the cool kids using for oauth these days? |
| 14:25 | TimMc | amalloy: Clients, or providers? |
| 14:26 | justin_smith | clj-oauth here for clients, dunno if we are cool |
| 14:26 | justin_smith | https://github.com/caribou/twitter-api |
| 14:26 | firefaux | maybe I'll just keep my whole database in one randomaccessfile, so I can just use offsets and not worry about files |
| 14:26 | justin_smith | firefaux: do you have a reason not to use a real db? |
| 14:27 | amalloy | TimMc: client |
| 14:27 | firefaux | justin_smith: well I have to implement everything myself, pretty much |
| 14:27 | justin_smith | firefaux: oh, because it is an assignment? |
| 14:27 | amalloy | goes to show how clueless i am about oauth - don't even know how to ask my questions right :P |
| 14:28 | firefaux | justin_smith: right. I can use whatever resources I want, but the whole assignment is basically making a database |
| 14:35 | augustl | what's a good way to get everyting in a file from after a blank line? I have a file with "header\nheader\nheader\n\nbody here\nhello, world", I want to extact the body |
| 14:36 | augustl | currently I do a line-seq and join afterwards, seems a bit wasteful.. |
| 14:36 | dpritchett_ | drop-while ? |
| 14:36 | amalloy | augustl: maybe you don't want it all as one giant string anyway, if you're worried about the waste of using line-seq+join |
| 14:36 | augustl | dpritchett_: yeah, that's what I use on the line-seq |
| 14:36 | rasmusto | I was going to say line-seq and drop-while +join |
| 14:37 | augustl | amalloy: hmm, good point. I'll look into not joining it at all |
| 14:37 | augustl | the reason I make it into a single string is so I can put it into hiccup |
| 14:37 | amalloy | hiccup is happy to take lists |
| 14:38 | augustl | makes sense :) I'll investigate. |
| 14:39 | gf3 | dnolen_: Where can I find more info on undo managers and snapshottable UI w/ OM/React? |
| 14:39 | gf3 | dnolen_: Finding mostly twitter threads :) |
| 14:39 | gf3 | (Sorry if double post, my VPN died) |
| 14:40 | dnolen_ | gf3: there's really not much to read - you get it for free |
| 14:45 | mr-foobar | gf3: In github.com/sgrove/omchaya there is an example history player. The impln basically made every state change as an event, which could be acted on. |
| 14:47 | gf3 | mr-foobar: Cool thx |
| 14:50 | augustl | does it make sense to (doall (map fn an-io-seq)), to ensure that the map happens immediately, not lazily after the io stream object is closed? |
| 14:50 | rasmusto | augustl: that works, but you may want to use doseq for side-effects |
| 14:51 | augustl | rasmusto: my map is pure, I just have to ensure it evaluates while the IO object is open |
| 14:51 | amalloy | augustl: that is one of the few defensible uses of doall. there are other approaches worth considering too, though |
| 14:51 | rasmusto | er, s/side-effects/reading |
| 14:51 | augustl | amalloy: I'd love to hear about some of the other approaches :) |
| 14:51 | rasmusto | augustl: ah, nm. Doall makes more sense. I had everything mixed up :p |
| 14:52 | augustl | rasmusto: ah :) |
| 14:52 | amalloy | eg, instead of returning a sequence from your function, pass a "continuation" sort of function *into* it: "here's what to do with the seq of things, please do it before you return [and thus close the iostream]" |
| 14:53 | augustl | amalloy: I see, that makes sense |
| 14:53 | augustl | that also enables the memory usage benefits of lazy seqs |
| 14:53 | amalloy | it kinda turns things inside out, so it's a bit awkward. but at some point you'll have to realize the results of the map, and this lets you do it inside the resource's dynamic scope |
| 14:54 | amalloy | that's really how with-open works, in a way. (with-open [r (foo)] (f r)) is a macro, but it could have been a function: (with-open* f (foo)) |
| 14:55 | hiredman | augustl: http://ce2144dc-f7c9-4f54-8fb6-7321a4c318db.s3.amazonaws.com/reducers.html |
| 14:56 | augustl | hiredman: thanks! I never use reducers, since I'm not familiar with them.. Will read. |
| 15:00 | augustl | hmm, I currently run a multi-line regex on my joined multi-line string. I don't suppose there are any ways to match a regexp over a seq as if it was one string.. |
| 15:00 | augustl | a seq of strings that represent lines |
| 15:08 | augustl | I'm screwed.. My syntax highlighter wants (multi-line) strings, so I can't just use the lines from line-seq directly. |
| 15:15 | aaronj1335 | hey folks is (into {} ...) the fastest way to make a hash map from a long sequence? |
| 15:16 | aaronj1335 | my quick little benchmarks suggest `into` and (apply hash-map ...) are the best |
| 15:20 | Cr8 | into will do (persistent! (reduce conj! (transient orig-coll) input-coll)) on transientable types |
| 15:21 | Cr8 | hash-map calls Persistent |
| 15:21 | Cr8 | hash-map calls PersistentHashMap's create method |
| 15:21 | Cr8 | which is basically the java equivalent of the above https://github.com/clojure/clojure/blob/1798b449b84c86a9b243bd79929a3a619194aa24/src/jvm/clojure/lang/PersistentHashMap.java#L52-L59 |
| 15:24 | Cr8 | so I'd just consider them equivalent. |
| 15:26 | aaronj1335 | Cr8 cool thanks |
| 15:27 | aaronj1335 | i'm trying to convert a python program that does some nlp stuff to clojure |
| 15:27 | aaronj1335 | and the clojure version is 4-5x slower |
| 15:27 | aaronj1335 | and i'm trying to figure out why |
| 15:29 | bbloom | aaronj1335: is the code small enough to gist? |
| 15:29 | aaronj1335 | bbloom yea, it's a bit confusing tho because it's reading files from a weird format, so it may be a bit tough to understand. i'll gist it up, and see if it makes any sense |
| 15:30 | bbloom | aaronj1335: don't do that yet |
| 15:30 | bbloom | aaronj1335: first, decomplect the file loading and the logic |
| 15:30 | aaronj1335 | ok |
| 15:30 | bbloom | so that you can benchmark apples against apples |
| 15:30 | ptcek | How can I find what port the repl is running on? |
| 15:30 | aaronj1335 | i've got that logic separated |
| 15:30 | bbloom | aaronj1335: the just post that part |
| 15:30 | aaronj1335 | cool |
| 15:30 | sdegutis | ptcek: what repl? |
| 15:30 | clojurebot | Huh? |
| 15:31 | sdegutis | ptcek: there is usually an .nrepl-port file created in the dir you're in |
| 15:31 | Pate_ | ptcek, are you running `lein repl` ? |
| 15:31 | Pate_ | second sdegutis. |
| 15:31 | Pate_ | also, `lein repl` will output the the host and port it is running on. |
| 15:32 | ptcek | lein repl will... and .nrepl-port are good suggestions... |
| 15:32 | ptcek | I just opened datomic tutorial and started repl using the script there... but it does not necessarily listen on any port right? (i want to connect from emacs/vim) |
| 15:33 | ptcek | It will be simpler to just create a new lein project I guess. |
| 15:35 | seangrove | dnolen_ bbloom https://www.dropbox.com/s/8nroaf6dfa0a7ak/zenrise_barebones_app.mov wherein we make a barebones, unstyled, no-layout chat app. The next version of the tooling will replace the typing with a popup app-state inspector, so you can visually glue the transformer inputs to nodes in the tree. After that, there's no competition about building more maintainble UI's/client apps :) |
| 15:35 | aaronj1335 | bbloom here's the code: https://gist.github.com/aaronj1335/9606615 |
| 15:36 | bbloom | seangrove: is this not the same video as before? what's different? |
| 15:36 | seangrove | A developer hands the designer a snapshot of the app-state, and the designer can then glue that to the components independently |
| 15:37 | bbloom | seangrove: that's how it should work :-) |
| 15:37 | bbloom | aaronj1335: and you're saying that python is dramatically faster at this simple task? |
| 15:37 | seangrove | bbloom: Not enough yet, except that it's a functioning chat app with multiple components interacting and reading/updating the app state |
| 15:37 | bbloom | aaronj1335: even after warming up the jit by running it many times? |
| 15:37 | aaronj1335 | bbloom 4-5 times yes |
| 15:37 | seangrove | But of course doing it all in a closure to functionally-pure way |
| 15:37 | aaronj1335 | yea, i basically paste the snippet into the repl several times |
| 15:38 | bbloom | aaronj1335: you can't get a realistic benchmark that way |
| 15:38 | aaronj1335 | usually takes ~31 secs for clojure, only 4.5ish for python |
| 15:38 | bbloom | aaronj1335: use (time (dotimes [i n] ... |
| 15:38 | seangrove | That's a pretty big difference |
| 15:39 | aaronj1335 | (also i added the python snippet i'm using) |
| 15:39 | bbloom | aaronj1335: is "labeled tokens" a particularly big sequence? |
| 15:39 | aaronj1335 | around a million items |
| 15:39 | seangrove | $seen noprompt |
| 15:39 | lazybot | noprompt was last seen quitting 2 days and 20 hours ago. |
| 15:40 | bbloom | aaronj1335: then your problem is lines 4 and 5 vs python lines 4/5/6 |
| 15:40 | bbloom | aaronj1335: you're walking the sequence twice in the clojure version |
| 15:40 | aaronj1335 | bbloom that was faster than a (reduce) call where i incrementally built the sets |
| 15:41 | aaronj1335 | only one loop in the reduce call |
| 15:41 | bbloom | aaronj1335: i'd have to see that code too |
| 15:41 | aaronj1335 | one sec... |
| 15:41 | bbloom | for a million items, memory access time is going to dominate the loop time for such simple transformations |
| 15:42 | Morgawr | http://i.imgur.com/J7hlC0t.png |
| 15:42 | Morgawr | sounds relevant |
| 15:43 | bbloom | seangrove: looking forward to seeing what UI you come up with for the transformer business |
| 15:44 | seangrove | bbloom: Probably going to be a bit small-talk-ish. Would be fantastic to have cljs-in-cljs at this point, heh. But ultimately, the transformer code (and probably controller code) should be written in javascript |
| 15:45 | seangrove | bbloom: Open up a small window (in terms of where they extend the app) for normal js developers to work in, tell them, "This function will receive these inputs, and must return the new state at the end. No side effects are allowed in this function." Let them write the javascript to handle that, and now they're plugging into a functionally-written cljs app |
| 15:46 | seangrove | But that's all later. Going to try to get the UI for the transformer glue done tonight, and then go for a long walk. |
| 15:49 | dbasch | technomancy: do you see any obvious issues with my password validation? https://www.refheap.com/60118 |
| 15:50 | aaronj1335 | bbloom ok i replaced the double loop in the gist w/ a reduce call. now it's running at like ~39ish seconds |
| 15:50 | Frozenlock | cemerick: I'm trying your clojurescript.test, which seems to be exactly what I was looking for. However, I get a weird error... would you mind checking it out? https://www.refheap.com/60117 (and yes, I'm using (:require cemerick.cljs.test) like suggested) |
| 15:51 | bbloom | aaronj1335: need to see the code. also, you should benchmark simply no-op walking the file to see if you have an issue there |
| 15:51 | cemerick | Frozenlock: https://github.com/cemerick/clojurescript.test/issues/53 |
| 15:52 | aaronj1335 | bbloom i updated the gist w/ the reduce call if you'd like to look at it. walking the file alone is ~7 seconds. |
| 15:52 | aaronj1335 | thnx for your help, btw, this is very kind of u |
| 15:53 | dnolen_ | aaronj1335: also make sure you are running Clojure w/ adequate memory + JVM -server option |
| 15:53 | Frozenlock | cemerick: Ah! Thanks! Would you suggest to add the js file, or use SlimerJS? |
| 15:53 | aaronj1335 | dnolen_ i'm giving it 2G |
| 15:53 | dnolen_ | aaronj1335: and -server? |
| 15:54 | cemerick | Frozenlock: I'd follow @noprompt on this, I've not had to think about it |
| 15:54 | bbloom | aaronj1335: this is one of those rare situtations where you actually want transients |
| 15:54 | aaronj1335 | dnolen_ one sec... |
| 15:54 | aaronj1335 | dnolen_ that goes in the :jvm-opts array of my project.clj? |
| 15:54 | Frozenlock | cemerick: understood. Thank you very much. |
| 15:55 | bbloom | aaronj1335: also the code you pasted me is invalid |
| 15:55 | bbloom | you're reducing over "tokens" which is not defined |
| 15:55 | aaronj1335 | (in order to have the -server option for my repl) |
| 15:55 | dnolen_ | aaronj1335: yes :jvm-opt ^:replace [...] |
| 15:55 | dnolen_ | aaronj1335: lein has bad defaults for benchmarking |
| 15:55 | aaronj1335 | cool thnx |
| 15:56 | dnolen_ | aaronj1335: :jvm-opts ^:replace ["-Xmx512m" "-server"] |
| 15:56 | dnolen_ | or something like that |
| 15:56 | aaronj1335 | bbloom sorry, that was just a bad paste, i'll update it, but that should be labeled-tokens |
| 15:57 | aaronj1335 | i'm running some unit tests before i bench mark to keep my sanity, but i can't do that on the gist stuff |
| 15:58 | bbloom | aaronj1335: try loop/recur with http://clojure.org/transients |
| 15:58 | bbloom | you definitely want transients for that many objects |
| 15:58 | bbloom | memory access and GC are going to dominate the code as you have it now |
| 15:58 | bbloom | the mutability in python actually spares you a ton of garbage overhead, doubly true when you do one loop instead of two |
| 15:58 | bbloom | the reason the reduce is SLOWER is b/c into uses transients internally |
| 15:58 | aaronj1335 | right on |
| 15:59 | dnolen_ | bbloom: aaronj1335: even that said I would be surprised if you see a 4X boost from running w/ the right JVM settings |
| 15:59 | aaronj1335 | yea i was wondering if there was a good way of using mutable stuff w/o having to make a bunch of java method calls |
| 15:59 | bbloom | dnolen_: wouldn't? |
| 16:00 | dnolen_ | bbloom: oops yes |
| 16:00 | dnolen_ | aaronj1335: I would first get the fastest idiomatic Clojure, should compete w/ Python |
| 16:00 | dnolen_ | if you want to get much faster than that, it's definitely possibly but a bit fiddly / tedious |
| 16:01 | bbloom | dnolen_: even with a 4x improvement, he'd still not be competitive with python b/c the work each program is doing is so wildly different |
| 16:01 | bbloom | entertainingly, his code is a pathological case for the intersection of persistent data structures and lazy sequences :-) |
| 16:02 | aaronj1335 | bbloom u think the lazy-seq's hurt perf here? |
| 16:02 | bbloom | aaronj1335: absolutely |
| 16:02 | bbloom | aaronj1335: again, increased allocation and garbage preasure |
| 16:02 | dnolen_ | bbloom: the comparison is fair insofar as Clojure gives good performance for functional patterns compared to imperative approaches in imperative "scripting" languages |
| 16:05 | aaronj1335 | well bummer... i was using lazy-seqs all over the place (esp. in the other code that reads the files) b/c i thought that similarly to python generators, they actually save memory pressure by never realizing the full array/list in memory |
| 16:05 | bbloom | aaronj1335: so generally lazy seqs are faster b/c you don't always do all the work |
| 16:05 | bbloom | especially if you CAN'T do all the work (ie infinite lazy seqs) |
| 16:05 | bbloom | but when you're traversing an entire file and never backtracking, then you're paying for stuff you don't need, like all the intermediate values |
| 16:06 | bbloom | python generators don't capture past states in anyway |
| 16:06 | bbloom | they are ephemeral |
| 16:06 | aaronj1335 | but lazy seq's do? |
| 16:07 | dnolen_ | aaronj1335: uh, I strongly suggest not getting lost in the performance assumption weeds just yet. Just make your code pretty and run it w/ the right JVM settings first. |
| 16:07 | bbloom | aaronj1335: you can hold on to a lazy seq and it won't change |
| 16:08 | bbloom | aaronj1335: reducers let you keep the pretty functional style and eliminate the overhead of the lazy seqs b/c you can only get at the final answer, not the intermediate results |
| 16:08 | bbloom | aaronj1335: you can get exceptionally good performance in both space and time for the same style of code |
| 16:09 | bbloom | but (sadly) i don't think that clojure exposes a reducable data type for files as lines |
| 16:10 | TheMoonMaster | I'm horrible with macros, I have a macro that defines an anonymous function that takes 1 argument, how can I make that argument available to the body passed to the macro? |
| 16:10 | aaronj1335 | cool... i've got something to run to now, but i'll clean up the perf comparisons and jvm settings and may be back later tonight w/ more questions and fuller examples. thnx again dnolen_ and bbloom for your time |
| 16:10 | gtrak | TheMoonMaster: you should take the captured symbol as input |
| 16:10 | TheMoonMaster | I have no idea what that means. |
| 16:11 | TheMoonMaster | I have something like this in there right now, `(fn [msg#] ~@body)` |
| 16:11 | TheMoonMaster | I need msg# available in body, but I'm totally clueless. |
| 16:11 | gtrak | right, so msg# is a gensym, which is the opposite of what you want. |
| 16:11 | TheMoonMaster | Ah |
| 16:12 | mschuene | do ¯'msg if you want to call it msg inside the body |
| 16:12 | gtrak | guaranteed to be unique and not clash with what's in ~@body. but don't do 'msg instead, the client should pass into the macro the desired symbol. |
| 16:12 | mschuene | yes |
| 16:13 | gtrak | like (defmacro somemacro [sym & body] `(fn [~sym] ~@body)) |
| 16:13 | gtrak | (somemacro msg (do-crap-to msg)) |
| 16:13 | TheMoonMaster | In this case it doesn't really make sense to have it passed in. |
| 16:14 | gtrak | not the value, just the name |
| 16:14 | TheMoonMaster | Right, still makes sense as just msg. |
| 16:14 | mschuene | ~' is the quoting you want here |
| 16:14 | clojurebot | Ik begrijp |
| 16:14 | gtrak | yea, it's just ill-advised to invisibly do stuff like that |
| 16:14 | gtrak | in general |
| 16:14 | TheMoonMaster | Yeah, if it were a library or something more than what it is, I'd totally do that. |
| 16:15 | gtrak | just so you know :-) |
| 16:15 | mschuene | it is OK if the client can specify how an anaphoric symbol will be named imo |
| 16:15 | TheMoonMaster | I appreciate the heads up and the help |
| 16:15 | amalloy | mschuene: if the client says how to name it, that's the opposite of anaphoric |
| 16:16 | seangrove | dnolen_: What's the state of meta in cljs? Is it readable at run-time (e.g. getting the metadata of a function at runtime)? |
| 16:17 | gtrak | seangrove: what's the use-case? |
| 16:17 | gtrak | I implemented something like that off analyzer data |
| 16:17 | seangrove | gtrak: Deciding on where to put the parameters for functions for introspection by a end-user tool |
| 16:18 | gtrak | hrm... |
| 16:19 | gtrak | so this is runtime-wiring or is the cljs compiler available? |
| 16:20 | dnolen_ | seangrove: metadata on the function var you cannot get at runtime |
| 16:20 | dnolen_ | seangrove: functions do support adding meta at runtime though |
| 16:20 | seangrove | gtrak: Right now run-time, could possibly push it into the compilation stage. Not the biggest deal for the time being |
| 16:21 | gtrak | maybe a macro could bridge the gap |
| 16:22 | gtrak | there's a dynamic var that stores the analyzer env, not sure about lifecycles and timing of these things. |
| 16:23 | mdrogalis | I've been looking for this forever. Stu Halloway on abstraction/encapculation Clojure's state perception model. http://vimeo.com/45136215 |
| 16:23 | mdrogalis | Now I just wish I remembered who was asking for it D: |
| 16:23 | mdrogalis | 4:50 - 8:00 ^ |
| 16:41 | shiranaihito | is there an idiomatic approach to throwing exceptions from Clojure code? i'd like to produce some specific type of exception in a specific situation, but it feels a bit unwieldy so far |
| 16:42 | amalloy | clojure is pretty lax about exception types |
| 16:43 | amalloy | people usually just throw any old garbage, and if you want to be specific you can use ex-info and ex-data to convey a lot more information than just a type |
| 16:53 | shiranaihito | amalloy: do you think that common habit is.. alright? |
| 16:53 | shiranaihito | i'm still new to clojure, but somehow i feel like trying to take care to produce clear, situational errors from clojure code is unwieldy |
| 16:54 | shiranaihito | maybe i'm missing something.. or maybe that's why people just throw any old garbage, whatever that means exactly :p |
| 16:55 | arohner | isn't there an official clojure 'contrib' lib w/ a better version of clojure.walk? |
| 16:55 | amalloy | it has its pluses and its minuses. i'd say there are more important things to figure out, for a new clojure programmer, than how to throw intricate exceptions |
| 16:55 | shiranaihito | amalloy: what's your take on the unwieldiness though? |
| 16:56 | amalloy | i don't try to throw fancypants exceptions. i try to return data that indicates what went wrong |
| 16:57 | technomancy | ex-info is a beautiful thing |
| 16:57 | technomancy | probably my favourite new feature since 1.1 |
| 16:57 | shiranaihito | technomancy: .. meaning? :p |
| 16:58 | gtrak | exceptions are annoying, but at least we have macros to deal with them better :-) |
| 16:58 | shiranaihito | amalloy: well, i'm not trying to be fancy - just clear and informative, but do you have some kind of typical approach to returning data that indicates what went wrong? |
| 16:58 | technomancy | shiranaihito: dunno, I like it a lot? I find it adds a lot of expressivity. |
| 16:59 | shiranaihito | technomancy: well, i was wondering how you use it, but i guess that doesn't really matter because i'm not even familiar with the function itself :p |
| 16:59 | technomancy | if there's ever any reason a caller would need to make decisions based on what went wrong, ex-info is the way to go |
| 16:59 | shiranaihito | hmm |
| 16:59 | technomancy | (unless the caller is a java program or something) |
| 16:59 | rasmusto | ,(ex-data (ex-info "blah" {:who 'what})) |
| 17:00 | clojurebot | {:who what} |
| 17:00 | shiranaihito | ohh alright |
| 17:01 | zuzkins | Hello guys. Does anybody know, if there is a protocol to extend on 3rd party type in clojurescript to alter the way prn-str prints it. I can't find it. Thanks |
| 17:05 | dnolen_ | zuzkins: -pr-writer |
| 17:10 | zuzkins | dnolen_: thank you |
| 17:10 | dnolen_ | zuzkins: np |
| 17:37 | Nnel | Does Clojure support cyclical(?) definitions? E.g. A includes calls to B, B also includes a recursion into A. |
| 17:37 | francis_wolke | Nnel: no |
| 17:37 | brehaut | (doc declare) |
| 17:37 | clojurebot | "([& names]); defs the supplied var names with no bindings, useful for making forward declarations." |
| 17:37 | amalloy | Nnel: it's possible with letfn or declare, but most of the time there's a better approach |
| 17:37 | brehaut | (doc letfn) |
| 17:37 | clojurebot | "([fnspecs & body]); fnspec ==> (fname [params*] exprs) or (fname ([params*] exprs)+) Takes a vector of function specs and a body, and generates a set of bindings of functions to their names. All of the names are available in all of the definitions of the functions, as well as the body." |
| 17:38 | francis_wolke | I misspoke - you can use declare, but you can't do async loads of other namespaces. |
| 17:39 | Nnel | amalloy: brehaut , cheers, yeah there are better ways for sure.. just using clojure to lazily go through a scheme book :P |
| 17:39 | amalloy | ,(letfn [(even? [x] (or (zero? x) (odd? (dec x)))) (odd? [x] (and (not (zero? x)) (even? (dec x))))] (even? 10)) |
| 17:39 | clojurebot | true |
| 17:43 | Nnel | amalloy: Thanks |
| 17:45 | chare | you guys know how with ruby on rails it automatically compresses js files and puts them all into one big file |
| 17:45 | chare | when using clojure with ring, compojure, etc... what is the equivalent |
| 17:47 | justin_smith | use an asset minification step, this is built into clojurescript, but you can also use grunt or the closure compiler directly if it is plain js |
| 17:47 | chare | justin_smith so you're saying there is no framework already setup I gotta set it up myself |
| 17:48 | justin_smith | there may be, none that I use |
| 17:48 | justin_smith | unless you are using clojurescript, there are setups for that |
| 17:48 | seangrove | There's dieter, and I think there's also a successor |
| 17:48 | seangrove | time to dance! |
| 17:51 | chare | justin_smith you also know how ruby on rails does more than minification it also does a kind of versioning by dealing with md5 |
| 17:51 | chare | don't i need that too? |
| 17:51 | justin_smith | I don't know what you need |
| 17:52 | justin_smith | I think hlship is working on some kind of asset pipeline solution, but I don't know the details |
| 17:52 | chare | justin_smith so you're saying you're not familiar with rails asset pipeline? |
| 17:52 | chare | damn it |
| 17:56 | bbjva | hi all |
| 17:57 | bbjva | I have a question about fucntions in Clojure, can someone pm me if you feel like helping |
| 17:57 | rasmusto | ~anyone |
| 17:57 | clojurebot | anyone is anybody |
| 17:57 | rasmusto | ~anybody |
| 17:57 | clojurebot | Just a heads up, you're more likely to get some help if you ask the question you really want the answer to, instead of "does anyone ..." |
| 17:58 | amalloy | ~clojurebot is constantly polluting useful triggers like ~anyone by learning other irrelevant factoids to repeat instead |
| 17:58 | clojurebot | In Ordnung |
| 17:59 | rasmusto | ~anyone |
| 17:59 | clojurebot | Just a heads up, you're more likely to get some help if you ask the question you really want the answer to, instead of "does anyone ..." |
| 17:59 | rasmusto | wait, hm? |
| 18:00 | amalloy | rasmusto: he has multiple hits and chooses one at random |
| 18:00 | seangrove | botsnack |
| 18:00 | rasmusto | amalloy: ah, gotcha |
| 18:00 | rasmusto | ~snotback |
| 18:00 | seangrove | clojurebot: botsnack |
| 18:00 | clojurebot | Titim gan éirí ort. |
| 18:00 | clojurebot | Thanks, but I prefer chocolate |
| 18:01 | amalloy | makes it impossible to reliably use ~anyone or ~anybody |
| 18:01 | seangrove | It's not clojurebot's fault |
| 18:01 | amalloy | i've tried un-teaching him the relation between those two, but it doesn't have any effect |
| 18:01 | brehaut | amalloy: if only there was another bot you could program to reliably respond to a set of facts |
| 18:02 | amalloy | despite how unreliable clojurebot's factoid system is, it's still so much more convenient than lazybot's |
| 18:03 | technomancy | it's part of the deranged charm |
| 18:03 | technomancy | like how you have to smack the tardis control panel a few times before it goes |
| 18:11 | justin_smith | or blowing on the cartridge to make it work |
| 18:12 | justin_smith | technomancy: that's called percussive maintenance btw http://en.wiktionary.org/wiki/percussive_maintenance |
| 18:12 | rasmusto | i guess you were supposed to use IPA and a q-tip |
| 18:13 | rasmusto | i always blew the dust out (because my carts were in my tree fort) |
| 18:13 | technomancy | you put beer on your NES carts? |
| 18:13 | rasmusto | isopropyl |
| 18:13 | bbjva | I am trying to write a function that accepts keyboard input (which is then stored as a var) I surely need some pointers! |
| 18:13 | technomancy | oh that makes more sense |
| 18:14 | justin_smith | technomancy: the hops help mario jump higher, duh |
| 18:14 | amalloy | ((juxt inc dec) justin_smith) ;; i wish this worked |
| 18:14 | justin_smith | hah |
| 18:14 | technomancy | heh |
| 18:14 | amalloy | i mean, i guess it does, right? i left his karma the same |
| 18:15 | brehaut | justin_smith: the blowing dust out of power / usb cables is mostly successfully a social engineering trick for help desk people: nobody wants to believe that they were stupid enoguh to not check something was plugged in before calling the help desk. 'blowing on it' is a good excuse for getting the user to actually check |
| 18:15 | justin_smith | I haven't heard of blowing on the cable |
| 18:15 | justin_smith | *hadn't |
| 18:15 | technomancy | brehaut: I heard it had more to do with the act of disconnecting and reconnecting |
| 18:16 | rasmusto | I like when people twist down harder on the VGA cable screws |
| 18:16 | rasmusto | if video doesn't work |
| 18:16 | amalloy | yeah, that's what i heard too, technomancy. something in the NES connectors didn't always click right, and just taking it out and putting it back was the real solution hidden behind blowing on it |
| 18:16 | brehaut | technomancy: any excuse to get someone to check and have an excuse when it was just not plugged in properly ;) |
| 18:16 | justin_smith | bbjva: pretty much everything in the jvm is a pointer to something in the heap - perhaps you mean a reference type that can be updated (like an atom or ref or agent)? |
| 18:17 | bbjva | tyeah |
| 18:17 | bbjva | yeah |
| 18:17 | dbasch | how do I redirect the output of clojure.tools.logging so that it appears in the slf4j output from "lein ring server"? |
| 18:17 | bbjva | sorry |
| 18:17 | brehaut | amalloy, technomancy: and pulling it out might scrap off some of the rust accumulating on the pins due to blowing |
| 18:17 | bbjva | I am coming from a java/c background |
| 18:17 | amalloy | hah |
| 18:17 | bbjva | trying to figure it out |
| 18:17 | justin_smith | bbjva: also, most processes that require mutation in an imperative language can be translated to a functional form working on an immutible stream of input (lazy seqs or a reduction across some input) |
| 18:17 | bbjva | thanks |
| 18:18 | bbjva | no mutation in fp |
| 18:18 | bbjva | is taking me a bit of time to get used to |
| 18:18 | justin_smith | it is possible, but less often needed |
| 18:18 | bbjva | yeah |
| 18:19 | bbjva | picking it up for work, loving the language lots so far, just changing my way of thinking is taking time |
| 18:19 | bbjva | i was an object head, but no longer |
| 18:19 | justin_smith | the general pattern is to ask how the thing that was changing can be a parameter of a strict function (such that the "change" is a changed input, and the same input will always get the same result) |
| 18:19 | bbjva | or at least not after 5 pm |
| 18:19 | bbjva | okay |
| 18:19 | justin_smith | heh, it takes a while, but I think pretty much everyone here would agree it is worth it |
| 18:20 | bbjva | it seems like it |
| 18:20 | gtrak | because everyone else doesn't make it this far :-) |
| 18:22 | justin_smith | heh, like Douglas Adams' puddle |
| 18:22 | gtrak | they stick to their comfy iterators and generics (hard to say with a straight face) |
| 18:22 | justin_smith | Imagine a puddle waking up one morning and thinking, "This is an interesting world I find myself in — an interesting hole I find myself in — fits me rather neatly, doesn't it? In fact it fits me staggeringly well, must have been made to have me in it!" |
| 18:24 | brehaut | gtrak: i have a hard time finding generics to be something detrimental |
| 18:25 | brehaut | gtrak: its about the only part of contemporary big OO type systems that is nice :P |
| 18:25 | gtrak | that's like saying I'd cut my arm off so I can get a prosthetic |
| 18:26 | gtrak | prosthetic nib |
| 18:27 | gtrak | maybe it's not generics that are ugly but generics + classes/inheritance. |
| 18:27 | gtrak | I have rather painful memories. |
| 18:27 | brehaut | yeah classes and inheritance are a pig |
| 18:28 | brehaut | and yes they do make generics bleark |
| 18:28 | brehaut | you need to have good variance constraints (C#4+) |
| 18:28 | amalloy | $dict bleark |
| 18:28 | lazybot | amalloy: Word not found. |
| 18:28 | amalloy | :( |
| 18:28 | brehaut | but then you have to deal with variance constraints which are a mess |
| 18:28 | brehaut | amalloy: onomatopoeia |
| 18:28 | brehaut | a being sick noise |
| 18:29 | amalloy | well, i'm glad it's been a while since i had lunch. that's a pretty specific sound |
| 18:30 | brehaut | sorry about that |
| 18:31 | brehaut | gtrak: generics are also much more useful when used with discriminated unions than interfaces |
| 18:34 | shriphani | hi. I have a weird situation where java reflection confirms that a method exists but I can't seem to invoke it. Here's the trace I got from the repl. Can someone help? https://gist.github.com/shriphani/9609733 |
| 18:35 | gtrak | doesn't seem hard to improve on interfaces :-), we use a language that focuses on dynamic data, after all. |
| 18:35 | amalloy | shriphani: a method that takes varargs like f(String... xs) actually takes a String[], not multiple arguments |
| 18:36 | shriphani | o wow I am an idiot. |
| 18:36 | martinklepsch | in clojure using = is a "referential equality" check right? could anyone explain how this works internally? (or explain what it means) |
| 18:36 | brehaut | s/idiot/unfamiliar with the specifics of java compilation/ |
| 18:37 | gtrak | martinklepsch: referential equality means a pointer check, ie, identical? |
| 18:37 | amalloy | actually it looks like this one doesn't take varargs at all, it explicitly takes a String[] |
| 18:37 | shriphani | yeah |
| 18:37 | shriphani | yeah and I sent in a vector |
| 18:37 | justin_smith | ,(doc =) |
| 18:37 | clojurebot | "([x] [x y] [x y & more]); Equality. Returns true if x equals y, false if not. Same as Java x.equals(y) except it also works for nil, and compares numbers and collections in a type-independent manner. Clojure's immutable data structures define equals() (and thus =) as a value, not an identity, comparison." |
| 18:37 | martinklepsch | gtrak, so it compares where the pointer points to in memory? |
| 18:37 | amalloy | so i'll give him "careless", which is between "idiot" and "java is crazy" |
| 18:37 | justin_smith | man, that doc string looked like it was using an emoticon for a moment |
| 18:38 | shriphani | well, that solves my problem. |
| 18:38 | gtrak | martinklepsch: I think that's what he means, this is om, right? |
| 18:38 | martinklepsch | yeah |
| 18:38 | martinklepsch | gtrak, thanks, think I got it |
| 18:38 | gtrak | referential as in 'reference', which really means pointer.. |
| 18:39 | technomancy | martinklepsch: clojure's = sorta implements operational equivalence, with notable omissions |
| 18:39 | justin_smith | martinklepsch: note the doc string I made clojurebot print above |
| 18:39 | martinklepsch | justin_smith, yeah read that |
| 18:39 | martinklepsch | = != identical? |
| 18:39 | rasmusto | ~= |
| 18:39 | clojurebot | Pardon? |
| 18:40 | justin_smith | special cases for numbers and collections (things where "same structure" could semantically mean "same" even if pointers do not match) |
| 18:40 | rasmusto | ,(= [1 2 3] '(1 2 3)) |
| 18:40 | clojurebot | true |
| 18:40 | justin_smith | ,(= ["a" "b" "c"] '("a" "b" "c")) |
| 18:40 | clojurebot | true |
| 18:41 | gtrak | I think he probably also means in the 'general case' |
| 18:41 | rasmusto | ,(= '(\a \b \c) (seq "abc")) |
| 18:41 | clojurebot | true |
| 18:42 | zer | ,(= '(\a \b \c) "abc") |
| 18:42 | clojurebot | false |
| 18:42 | justin_smith | strings are not treated as sequential collections in general |
| 18:42 | dbasch | so, what's the right way to have configurable debug/info/error logging in compojure? |
| 18:43 | gtrak | dbasch: luminus chose to use timbre |
| 18:43 | SegFaultAX | dbasch: That's not really a compojure thing, but log4j is the standard Java logging utility. Timbre is the best wrapper around for it. |
| 18:43 | technomancy | "it's complicated" |
| 18:44 | technomancy | wait, I thought timbre was independent of log4j |
| 18:44 | dbasch | SegFaultAX: jetty seems to be using slf4j |
| 18:44 | technomancy | dbasch: it depends on whether you want unification with other libs. if not I would use println+binding |
| 18:44 | SegFaultAX | technomancy: Is it? I thought it was a wrapper for it!? |
| 18:45 | gtrak | is timbre actually on-par with java libs? |
| 18:45 | gtrak | seems like it's a dead horse, but they've been beating it for quite a while. |
| 18:45 | chare | ok so making a webapp with clojure I use Ring, Compojure, Hiccup, and what else |
| 18:45 | chare | what is the standard list of stuff to use? |
| 18:46 | SegFaultAX | technomancy: It appears to be using c.tools.logging which uses slf4j. TIL |
| 18:46 | gtrak | chare: luminus is a good starting point, batteries-included. |
| 18:46 | SegFaultAX | chare: Probably friend. |
| 18:46 | technomancy | SegFaultAX: blargh. it started as its own thing. now I don't have anything to recommend for people who can get away with avoiding the java logging quagmire. |
| 18:47 | technomancy | apart from just println+binding of course, which is what I use |
| 18:47 | SegFaultAX | technomancy: Heh. Fortunately c.tools.logging provides a sane interface on top of most of the standard Java loggers. |
| 18:47 | justin_smith | just wrap the process in nohup and you get logging? |
| 18:47 | SegFaultAX | technomancy: So whatever you have available on your CP will be selected by tools.logging and therefore timbre. |
| 18:48 | SegFaultAX | https://github.com/clojure/tools.logging/blob/master/src/main/clojure/clojure/tools/logging/impl.clj#L202 |
| 18:48 | technomancy | SegFaultAX: last I checked changing log level at runtime with log4j was a complete nightmare |
| 18:48 | gtrak | the java stuff brings out the worst problems in dependency management |
| 18:48 | hiredman | technomancy: that is just not true |
| 18:48 | justin_smith | technomancy: the conclusion I came to was that they consider it a security thing so it is intentionally hard to modify dynamically? either that or they are totally out to lunch architecture astronaughts that recoil at the thought of anything simple |
| 18:49 | technomancy | hiredman: maybe it was commons logging. it's been a while. |
| 18:49 | hiredman | you call a static method with the name of the of log level you want |
| 18:49 | justin_smith | or maybe I was just doing it all wrong... |
| 18:49 | amalloy | hiredman: i think he means "changing whether INFO gets written to a file or just ignored, for package X" |
| 18:50 | hiredman | ok, that isn't write, you call a static method to get the level object, then you call a method on the logger to set its level |
| 18:50 | technomancy | lol, at astronaughts |
| 18:50 | justin_smith | weird typo, glad it amused you |
| 18:50 | justin_smith | my fingers seem to go by bizarre phonetic rules sometimes... |
| 18:51 | hiredman | newer stuff like, uh, waht is logback? which is api compatible with log4j, acutally watches the config file and will reload it if there are changes, if I recall |
| 18:51 | amalloy | astronaughts are people in space who nobody cares about |
| 18:51 | SegFaultAX | Well you can always use something else if you don't want to deal with log4j directly... like slf4j |
| 18:53 | technomancy | SegFaultAX: java logging is amazing because there are more abstract interfaces against libraries than actual implementation libraries. |
| 18:53 | technomancy | where "amazing" here is not a good thing |
| 18:53 | SegFaultAX | Heh. Logging is a hard problem, clearly. |
| 18:55 | hiredman | so let's throw fud at it |
| 18:57 | SegFaultAX | hiredman: I wasn't trying to spread FUD! |
| 18:57 | lgs32a | I have a strange problem with friend |
| 18:57 | lgs32a | It simply does not authenticate |
| 18:58 | hiredman | SegFaultAX: sure |
| 18:58 | lgs32a | I also noticed that there is an empty hash-map under the :session parameter in the request of the any handler |
| 18:58 | SegFaultAX | lgs32a: Well need more details than that. gist/refheap some code. |
| 18:59 | lgs32a | SegFaultAX: Would it be possible without? |
| 18:59 | eric_normand | shriphani: answered in the gist |
| 19:00 | SegFaultAX | lgs32a: "It doesn't work" isn't much to go on. ;) |
| 19:00 | lgs32a | I think somebody who knows the friend codebase well could help me significantly |
| 19:00 | hiredman | pedestal service has some nice logback logging settings and some project.clj depednency wrangling to direct other logging frameworks you are likely to encounter to logback |
| 19:00 | lgs32a | SegFaultAX: As I said, the :session parameter is empty |
| 19:00 | SegFaultAX | lgs32a: Also, I'm pretty sure friend stores the authentication map under :session with a namespace qualified key. |
| 19:01 | lgs32a | Yes it stores ::friend/unauthorized-uri |
| 19:01 | lgs32a | But only if I visit a route directly, the redirect from login results in an empty session |
| 19:02 | lgs32a | I am using the interactive-form workflow |
| 19:02 | lgs32a | Also, :credential-fn returns a valid login |
| 19:05 | lgs32a | Even though the login succeeds, current-authentication always returns nil |
| 19:08 | seangrove | Ugh, damnit |
| 19:09 | seangrove | What do I want to check for to see if a value implements lookup, like hashmaps and vectors? |
| 19:10 | amalloy | ILookup |
| 19:10 | seangrove | ,(satisfies? ILookup {}) |
| 19:10 | clojurebot | #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: ILookup in this context, compiling:(NO_SOURCE_PATH:0:0)> |
| 19:10 | amalloy | on the jvm it's an interface, not a protocol, of course |
| 19:10 | SegFaultAX | clojure.lang |
| 19:10 | amalloy | and it's in clojure.lang, right |
| 19:10 | amalloy | ,(instance? clojure.lang.ILookup {}) |
| 19:11 | clojurebot | true |
| 19:11 | seangrove | Hrm, struggling to get it to work in cljs |
| 19:11 | seangrove | Let me see if I can find the right name for it |
| 19:12 | seangrove | cljs.core/ILookup |
| 19:12 | seangrove | That did it, thanks! |
| 19:14 | gnandretta | 3 |
| 19:16 | Morgawr | does anybody know Jamie's handle on irc (if he's even in here)? I wanted to talk to him about GSoC (I posted in the google group for clojure but got no reply) |
| 19:23 | arohner | isn't there a library that is a better version of clojure.walk somewhere? |
| 19:24 | justin_smith | clojure.walk2 which got subsumed into clojure 1.6 iirc? https://github.com/stuartsierra/clojure.walk2 |
| 19:30 | Bronsa | justin_smith: no it hasn't |
| 19:32 | justin_smith | http://dev.clojure.org/jira/browse/CLJ-1239 ah I see still open |
| 19:33 | justin_smith | the only place lein search finds clojure.walk2 is currently the caribou/clojure.walk2 fork |
| 19:33 | Bronsa | what's in 1.6 is support for records |
| 19:33 | justin_smith | ahh OK |
| 19:47 | gfredericks | what am I ought to use to query the data structure that data.xml/parse returns? |
| 19:49 | noonian | according to the readme you should be able to use normal clojure fns |
| 19:50 | noonian | (-> parsed-xml :content println) |
| 19:50 | hiredman | gfredericks: you can do things with zippers, there was a contrib library for slicing it up in teh past |
| 19:52 | hiredman | gfredericks: https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj |
| 19:53 | gfredericks | oh I knew zip had something to do with it |
| 19:53 | gfredericks | hiredman: thanks |
| 20:48 | SegFaultAX | Philsophical question: in an utterly object oriented language like Java, what's the best way to build up objects compositionally vs. through inheritance? As a motivating example, assume we have a User class with all the essential methods for a User. Later, we want to add methods that are logically related to each other, but aren't really part of User itself despite needing a User to do their thing. What's the most common way to accomplish th |
| 20:49 | seangrove | SegFaultAX: I think there's an idea of service-layers for that |
| 20:49 | beamso | for the situation you've mentioned, util classes usually |
| 20:49 | SegFaultAX | In Objective-C world, for example, the answer is delegates all the way down. In Clojure, we can extend new methods over our types via protocols. Haskell has type classes which are functionally similar to protocols. But what about java? |
| 20:49 | SegFaultAX | bailon: So you're thinking the delegate pattern then? Or something similar? |
| 20:50 | hyPiRion | SegFaultAX: Interfaces with default methods I guess |
| 20:50 | SegFaultAX | hyPiRion: Not possible until Java 8. |
| 20:50 | SegFaultAX | So how does modern Java work? Is it just inheritance all over the place? |
| 20:50 | hyPiRion | SegFaultAX: you said it was a philosophical question :p |
| 20:50 | beamso | it's both util classes and service-layers, as seangrove mentioned |
| 20:50 | hyPiRion | But yes, inheritance everywhere, or util classes |
| 20:50 | SegFaultAX | hyPiRion: Well, ok you got me there. :) |
| 20:51 | amalloy | SegFaultAX: just a class that contains a User object, and in addition to the methods you're adding contains a getUser() method? |
| 20:52 | SegFaultAX | amalloy: That's basically what I was thinking. I wouldn't bother to proxy the object (eg forward messages to the delegator) |
| 20:52 | amalloy | indeed not |
| 20:52 | beamso | i was going to say that the types/protocols thing made me curious |
| 20:52 | amalloy | if a thing is not a User, but needs a User to do its stuff, why should it act like a User? |
| 20:53 | beamso | in all of my clojure programming i've used maps instead of types as i'm building up information in the type during computation |
| 20:53 | SegFaultAX | amalloy: It shouldn't. It just defines operations that require a user. |
| 20:54 | amalloy | right. i'm questioning why proxying the object is even under cnosideration. i don't know why you would do that even in a language that makes it easy, like the delegates you were mentioning earlier |
| 20:55 | SegFaultAX | amalloy: So when you start having more complex helper classes, that's where you start using DI. Eg if my helper class needs a User and a Foobar. How does DI work when I need a /specific/ User and a /specific/ Foobar. Like `new MyHelper(new User(2), new Foobar(42))`? |
| 20:55 | amalloy | if it's right in that case, you might as well do it in java, since eclipse makes it like ten keystrokes to generate all the delegators |
| 20:56 | SegFaultAX | Ugh, irccloud keeps dying. |
| 20:56 | amalloy | SegFaultAX: i don't understand that question at all. DI works by passing in the objects you depend on, as in your example |
| 20:57 | amalloy | so, your example seems fine, and i don't know what alternative you're asking for |
| 20:58 | SegFaultAX | I'm not asking for an alternative. I'm wondering what the typical pattern is for asking a DI harness for an instance of MyHelper with parameterized dependencies. |
| 20:58 | beamso | typically for DI you're not relying on a specific instance of something from a database |
| 20:58 | beamso | you're using it to inject a database connection |
| 20:59 | amalloy | i have no idea what asking a DI harness for something is like, i'm afraid |
| 20:59 | SegFaultAX | beamso: That's exactly what I'm asking about. I get DI for those types of things, what I don't get is DI for specific instances of things. |
| 20:59 | beamso | i haven't seen people do DI for specific instances |
| 20:59 | alew | I don't think you should ask the DI harness for anything; the point of DI is that a component receives components without any of their implementation details |
| 20:59 | beamso | like, in a webapp, you might choose to have a thread local or a session variable to hold those context sensitive items |
| 21:00 | alew | If you want DI for specific instances, all you can do is do some sort of reflection/type checking in order to understand what you were given |
| 21:00 | SegFaultAX | amalloy seems to think it can inject specific instances of things. |
| 21:00 | SegFaultAX | And I'm wondering how that would even work, since you can't know until runtime what to inject. |
| 21:00 | SegFaultAX | Whereas a database connection (and all the configuration for it) can be specified ahead of time. |
| 21:01 | amalloy | SegFaultAX: you talked about dependency inversion, which i understand to be a design pattern. i have no idea what a DI harness or framework looks like |
| 21:01 | justin_smith | SegFaultAX: as I understand it Java DI often uses a config file to specify the class that will be loaded at runtime |
| 21:01 | SegFaultAX | justin_smith: Right. |
| 21:01 | beamso | config files, annotations or hard coded java |
| 21:02 | SegFaultAX | amalloy: Um, when I gave the example above of `new MyHelper(new User(2), new Foobar(42))` you seemed to dismiss that as a trivial example. |
| 21:02 | amalloy | indeed, you can trivially write that code yourself, and get a functioning MyHelper |
| 21:03 | SegFaultAX | amalloy: I asked that in the context of DI, though. |
| 21:03 | amalloy | apparently you and i have no common conception of what DI is |
| 21:03 | SegFaultAX | amalloy: Dependency injection? |
| 21:03 | amalloy | so anything i have said in this conversation should be dismissed as meaningless |
| 21:03 | SegFaultAX | amalloy: Were you not talking about dependency injection? |
| 21:04 | amalloy | well, when you started getting confused, i clarified that i meant dependency inversion, the design pattern |
| 21:04 | amalloy | you introduced "DI" without filling in the letters, but apparently you meant dependency injection |
| 21:04 | beamso | inversion of control, you mean |
| 21:05 | SegFaultAX | DI is a relatively standard initialism given the context. My mistake for not clarifying. |
| 21:05 | amalloy | looking them both up, they seem pretty similar, except that you're talking about frameworks that do DI for you in some mystical way |
| 21:06 | SegFaultAX | amalloy: javax.inject is a good example. |
| 21:06 | SegFaultAX | As is Dagger or Guice. |
| 21:06 | amalloy | those are what i know nothing about; DI the technique makes sense to me |
| 21:06 | amalloy | like i said, i have never used any of those, and can't help you with your current goal in getting them to do what you want |
| 21:06 | beamso | javax.inject? oh noes. |
| 21:07 | justin_smith | I suspect much of what is meant by "dependency injection" is some hoops that inflexible languages must jump through to do dependency inversion - but I may be wrong about this |
| 21:08 | SegFaultAX | justin_smith: Not really. Dependency injection is just a technique for constructing, well, dependencies to things. |
| 21:08 | SegFaultAX | AngularJS is a recent example of a framework that uses injection pervasively. |
| 21:09 | beamso | for java it was a kind of way to remove the factory method, singleton and service locator patterns |
| 21:10 | SegFaultAX | Jersey is actually a pretty cool example of DI "Done Right" in Java, imho. |
| 21:10 | justin_smith | http://martinfowler.com/articles/injection.html |
| 21:11 | beamso | i like jersey but for some of the injection the resource classes get instantiated over and over again |
| 21:11 | beamso | i can understand why angularjs has dependency injection but it almost goes too far |
| 21:11 | SegFaultAX | beamso: That might be OK since they're tiny anyway. |
| 21:15 | SegFaultAX | amalloy: So going back to our previous discussion, you group helper methods inside a helper class, then construct that helper class with an instance of its dependency, is that right? |
| 21:15 | hyPiRion | What would you call a set of XML Schemas which defines a "standard"? Some people tends to call it a format, but I'm always confused because I consider XML to be the format, and the schemas to be the interpretation of the data. |
| 21:15 | SegFaultAX | So User has core methods to user, and UserFoobarHelper has all the methods for doing Foobar-like operations on the User (horrible naming aside) |
| 21:15 | dsrx | angularjs dependency injection is hilarious |
| 21:16 | dsrx | but it works |
| 21:16 | amalloy | that sounds right, SegFaultAX |
| 21:16 | dsrx | (modulo the build step you need for it to be minification safe) |
| 21:16 | dsrx | (unless you want to hand-annotate everything, blech) |
| 21:16 | beamso | from a code zealot point of view, your helper class shouldn't require dependency injection |
| 21:16 | SegFaultAX | amalloy: Would you provide methods on the User to construct instances of the helper classes? |
| 21:16 | beamso | requiring dependency injection -> service layer |
| 21:17 | amalloy | i don't think so. why should User know anything about all the classes that need a User? |
| 21:17 | SegFaultAX | amalloy: Dunno, more to just reduce typing? I guess it doesn't matter that much. |
| 21:18 | SegFaultAX | If I used UserFoobarHelper all the time, I wouldn't want to type `new UserFoobarHelper(user)` all over the place if I could avoid it :) |
| 21:18 | amalloy | what, you'd rather type user.makeFooBarHelper()? what does that achieve? |
| 21:19 | hyPiRion | amalloy: just have the functions directly onto the User class I guess |
| 21:19 | amalloy | but this discussion started with "say you have a User class and it's great, and you want a new class that isn't a User but does things with Users" |
| 21:19 | SegFaultAX | amalloy: I'm just throwing out ideas. |
| 21:19 | hyPiRion | although if you need another object for the helper functionality, I'd guess that point is sort of moot |
| 21:20 | SegFaultAX | hyPiRion: The alternative is to make User do everything. Which can be quite a diverse set of concerns given the application. What's a better way to break the logic up? |
| 21:20 | amalloy | SegFaultAX: i think if you want an object that uses a User, at some point you have to pass a User in. either at construction time, or perhaps as the first parameter to some static function |
| 21:20 | hyPiRion | I tend to use Clojure, and that seems to work quite well. |
| 21:21 | hyPiRion | (I tend to use Java for perf. reasons only these days) |
| 21:22 | SegFaultAX | hyPiRion: This whole discussion is a moot point in clj, really. At a minimum we have functions and namespaces, and protocols for when we care about types. (This part was discussed earlier) |
| 21:22 | SegFaultAX | So I can trivially break up my logic into different namespaces. |
| 21:22 | hyPiRion | SegFaultAX: yeah, I know. I just said I used Clojure because I have no idea on how to do it "nicely" in Java, so I fall back to Clojure instead. |
| 21:22 | SegFaultAX | But in a language like Java, how do I break up all the diverse logic for my User or other <insert central object here>? |
| 21:23 | SegFaultAX | I started this as a philosophical debate, anyway. :D |
| 21:23 | hyPiRion | hehe |
| 21:28 | SegFaultAX | But I think this question applies equally to languages like Python and Ruby which are still heavily class-based. |
| 21:28 | beamso | but i have first class functions in both languages |
| 21:29 | beamso | a util class is attempting to paper over the crack that is no first class functions in java |
| 21:37 | SegFaultAX | beamso: I'm not sure how that helps in this case. |
| 21:39 | beamso | a util class is like 'i need to put some code somewhere' |
| 21:39 | beamso | first class function -> that code is already somewhere |
| 21:39 | pdk | at least java 8 is going halfway and giving us lambda!!!1 |
| 21:40 | SegFaultAX | beamso: Yes, I know what a util class is. I'm not sure how that helps in the situation we're discussing. |
| 21:40 | beamso | you asked about ruby and python |
| 21:40 | beamso | ruby does have first class functions |
| 21:40 | beamso | i'm pretty sure that python does too |
| 21:41 | anon_53k8 | it does |
| 21:41 | SegFaultAX | beamso: But how do first-class functions ameliorate the problem I described? |
| 21:41 | beamso | you don't have to put logic into a class? |
| 21:41 | beamso | it can live in a first class function just fine |
| 21:42 | SegFaultAX | beamso: Well the first classness isn't really relevant here then. I could just as easily make a fully static class. |
| 22:08 | gfredericks | ruby has 2nd class functions |
| 22:08 | gfredericks | ruby aims a shotgun at first class functions and hits all around it |
| 22:24 | AmandaC | How can I use lein to reference a jar? An API I wish to use isn’t on mavin or clojars |
| 22:29 | Bronsa | AmandaC: I never used it but https://github.com/kumarshantanu/lein-localrepo might be what you need |
| 22:29 | beamso | you could also install the jar into your local repo using maven |
| 22:29 | beamso | http://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html |
| 22:30 | AmandaC | Hrm, thanks, beamso |
| 22:35 | Frozenlock | Is there a clojure/cljs way to handle internationalization in web apps? I've seen `tower', but this seems to be mostly for clojure. |
| 22:35 | Frozenlock | At this point I think the best approach would be to use tower in the webserver and loading a single language in an atom on the client side. |
| 22:39 | noonian | you could also use an existing js library |
| 23:45 | vimuser21 | This is more of a general programming question, but lets say you wanted to create a bunch of hashs with key/value pairs, and the key is a unique id. how would you do this in a pure functional manner? seems like you would be mutating a counter which is stateful |
| 23:46 | beamso | is the key sequential or unique? |
| 23:46 | amalloy | vimuser21: reduce and recursion are both typical ways to immutably work with state |
| 23:47 | vimuser21 | baemso: either would work =) |
| 23:47 | amalloy | for example, ##(reduce (fn [m [id x]] (assoc m id x)) {} (map list (range) '(a b c d)))) |
| 23:47 | lazybot | ⇒ {3 d, 2 c, 1 b, 0 a} |
| 23:48 | amalloy | which is really just a terrible way of writing (into {} (map-indexed vector '(a b c d))), to demonstrate how reduce can hold state |
| 23:48 | ivan | Raynes: if you are wondering why refheap is full of anonymous forks, it's the crawlers hitting /fork |
| 23:48 | vimuser21 | amalloy: hm let me read the example for a second, i had the idea of passing in the last known value into a function so it can generate a new value |
| 23:49 | ivan | GET is a no-no for mutation |
| 23:49 | beamso | if it was sequential a vector and remembering the offset could suffice |
| 23:49 | amalloy | vimuser21: here, (range) is my standin for an infinite lazy seq of IDs |
| 23:49 | amalloy | ivan: hah. he could add a robots.txt too, right? "plz no fork" |
| 23:53 | vimuser21 | amalloy: hm, well what about throwing in something like async? i had the idea of basically each id is pre-fixed with a number, and you can do async stuff by pre-pending id's with, for a back of a better term, the current "runner", ie runner "0" woild generate 0-1,0-2,0-3, runner "1" would generate 1-0,1-1, etc. |
| 23:53 | vimuser21 | i guess it still fits in though |
| 23:55 | vimuser21 | amalloy: to explain the project i'm working on a bit more, it's an auto flowchart program, so you can type s-expressions and it will flow chart it out |
| 23:56 | vimuser21 | amalloy: so yeah recursion could work, i just would have to be carrying this counter around which is kind of annoying and whish there was a better way…technically a "generator" would work but thats statefull |
| 23:56 | vimuser21 | not sure if i can have my cake and eat it too if you know what i mean =) lol |
| 23:57 | amalloy | well, you can carry around a lazy sequence instead of a counter, which is generally prettier. but you'll still have to manage it by calling first to get a new id, and saving the result of rest to make sure you never see that id again |
| 23:57 | vimuser21 | yeah |
| 23:58 | vimuser21 | the first time i wrote it i didn't need id's, i bascially did "everything at once", parsing, drawing nodes, and connecting..but that code was sloppy |
| 23:58 | yuri_niyazov | I need some help with doseq and transients. So, I have a fairly complicated doseq statement, with a few nested sequences, :let bindings, and :when filtering |
| 23:58 | yuri_niyazov | inside the body, I want to accumulate some values into a transient |
| 23:59 | vimuser21 | was hard to read and wasn't good imo, was mixing side effect code with non side effect stuff |