#clojure log - Mar 17 2014

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

0:00 stcredzero: bbloom: Since I started using pmap, I

0:00 bbloom: stcredzero: there's practically zero chance pmap is a good idea in a game ever

0:00 stcredzero: I've started seeing strange errors

0: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

0:00 bbloom: maybe clojurebot has something...

0: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

0:00 bbloom: ~pmap

0:00 clojurebot: pmap is not what you want

0:00 bbloom: there we go ^^ lol

0:00 l1x: :)

0:01 stcredzero: bbloom: even if you use (vec) to force evalutation in well defined stages?

0: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

0:01 bbloom: stcredzero: have you benchmarked pmap for your use case?

0:01 stcredzero: bbloom: I'm using pmap to handle execution in sub-grids.

0: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

0:02 bbloom: stcredzero: i'm willing to bet that pmap is making your game slower, try it and see

0: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

0:02 seangrove: dnolen_: It makes it highly amenable to static analysis + really fantastic tooling

0:02 dnolen_: You can get highly-functional apps with all the goodies going through this

0:03 stcredzero: bbloom: It's probably making it slower now, but I'm hoping to support 1000's of entities/players

0:03 bbloom: stcredzero: benchmark. benchmark. benchmark.

0: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

0:03 bbloom: seangrove: that's my fear :-P

0:03 seangrove: bbloom: It's on my mind, certainly ;)

0:03 bbloom: seangrove: declarative UI doesn't work for programmers, it works for tools

0:04 seangrove: which is OK if that's your goal, but you have to be clear about that

0: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

0:04 seangrove: bbloom: The iterative bootstrapping process so far has been very promising in that regar

0:04 stcredzero: bbloom: I don't have to benchmark an architectural/algorithmic choice. The point is to have multi-core concurrency

0: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

0:05 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

0:05 stcredzero: bbloom: you're not hearing me. Except for boundary crossings, there *is no coordination* between subgrids.

0:06 bbloom: stcredzero: pmap has coordination

0:06 (doc pmap)

0: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."

0:06 bbloom: note the "only useful for" message

0:06 dnolen_: seangrove: need to think about it some more - but it seems worth exploring.

0:06 bbloom: stcredzero: by definition, that's not true if you have thousands of entities

0:06 seangrove: dnolen_: It's all PoC still, but pretty excited about it.

0: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.

0:09 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.

0:09 bbloom: stcredzero: even if that were the case, you don't want pmap

0:10 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

0: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

0: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

0:11 stcredzero: bbloom: however, it does make sense that pmap is creating a ton of garbage.

0: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.

0:12 stcredzero: SegFaultAX: You can say the same for Erlang Actors. All of these things have inherent coordination overhead.

0:12 bbloom: stcredzero: except that that's a wildly different thing

0:13 SegFaultAX: stcredzero: That... has aboslutely nothing to do with what we're talking about.

0:13 bbloom: b/c erlang actors have independent GC heaps and run N-to-M threading

0:13 SegFaultAX: stcredzero: You can visualize a pmap as firing off a bunch of futures then joining on all of them.

0: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

0:14 bbloom: stcredzero: looking at your screenshots... is the game logic in cljs? or just the renderer?

0:14 SegFaultAX: stcredzero: Go measure, come back to us when you have a better sense of what's going on.

0:14 stcredzero: Just the renderer.

0:15 I can't really benchmark 1000's of entities until I have much more of the system built.

0:15 SegFaultAX: Then you're prematurely optimizing anyway.

0:15 bbloom: yes, that ^^

0:16 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

0:16 stcredzero: I can just change all of those pmap to map.

0:16 bbloom: core.async is likely to provide proper multi-threaded improvements

0:16 stcredzero: bbloom: remain sorted?

0:16 SegFaultAX: stcredzero: But you've got a bunch of things in your head that you're mixing together.

0:16 bbloom: stcredzero: pmap preserves the sequence's order

0:17 stcredzero: bbloom: why should that incur a significant overhead?

0:17 bbloom: go to your repl and type (source pmap)

0:17 stcredzero: SegfaultX: what things?

0:17 bbloom: maybe you'll understand then, if you don't you have a lot more to learn about multithreading performance

0:17 and you're only going to learn that from BENCHMARKING

0:18 devn: free idea: wiki-style editing of docstrings

0:18 collaborative docstring writing, with a more wikipedia-like interface for editing what the code does

0:18 SegFaultAX: devn: I wish that's what clojuredocs became.

0:19 devn: SegFaultAX: you know, i keep sitting around wondering how we ended up where we are

0:19 SegFaultAX: Instead it's a relic which high google ranking that hasn't been updated in years. :(

0:19 bbloom: stcredzero: sorry to be harsh, really just trying to help

0:19 stcredzero: bbloom: so you're saying it's the when that's the source of the overhead?

0:19 devn: clojuredoc is good, clojuredocs is ok

0:19 but it's sad no one has just sit down and replaced clojuredocs

0:19 i need to make that my mission.

0:19 SegFaultAX: I wonder if the maintainer would be willing to yield control of the domain.

0:20 stcredzero: bbloom: That pmap is polling over a bunch of things to see when they are all done?

0: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

0:20 devn: apparently that was discussed at some point

0:20 i dont know the details

0:20 bbloom: stcredzero: no, it's not polling, it's blocking in order.

0:20 stcredzero: also, since your game is going to have a server component, you're better off running GAMES in parallel

0:20 stcredzero: ie different game world instances run on different cores

0:20 devn: SegFaultAX: do you want to remake clojuredocs?

0:20 bbloom: stcredzero: that will yield dramatically better CPU utilization and even more dramatically simpler code

0:21 devn: AKA do you have time to work on it?

0:21 SegFaultAX: devn: Update it with 1.4 1.5 1.6

0: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.

0:21 devn: SegFaultAX: forget the old site. let's just rewrite it and extract the content

0:22 actually, you know what? i take back that idea. what we have is a rails application that could easily be updated

0:22 bbloom: pmap is still not the answer

0: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.

0:22 SegFaultAX: bbloom: Not worth the effort, dude.

0:22 bbloom: SegFaultAX: agreed

0:22 SegFaultAX: stcredzero: Go measure.

0:23 seangrove: Yeah, just benchmark, work from that

0:23 SegFaultAX: stcredzero: Show us that we're wrong with data.

0:23 devn: can someone catch me up on this conversation?

0:24 SegFaultAX: devn: Just some deep misunderstandings about how threads work (and pmap in particular)

0: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]]

0: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))

0:24 devn: no, that's wrong. These guys don't understand what I'm proposing.

0:24 devn: ,(zipmap [1 2 3] [1 2 3])

0:25 clojurebot: {3 3, 2 2, 1 1}

0:25 stcredzero: devn: as evidenced by their bringing up separate instances. I will have separate instances.

0:25 SegFaultAX: (map vector [1 2 3] [:a :b :c])

0:25 ,(map vector [1 2 3] [:a :b :c])

0:25 clojurebot: ([1 :a] [2 :b] [3 :c])

0:25 devn: stcredzero: that too :)

0:25 ,(repeat 2 [1 2 3])

0:25 clojurebot: ([1 2 3] [1 2 3])

0:25 trap_exit: so (for [ [a b] (map vector lst1 lst2)] ... ) ?

0:26 well, [1 2 3], [1 2 3] were specific lists; I want it work with generic lst1, lst2

0:26 SegFaultAX: trap_exit: (fn [a b] (map vector a b))

0: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.

0:26 devn: are the same length?

0:26 trap_exit: not same length

0: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

0:26 trap_exit: but I only want to take pairs up to the shorter of the two

0:27 SegFaultAX: trap_exit: Then that's what you want.

0:27 bbloom: stcredzero: 100% CPU utilization isn't what you want...

0:27 SegFaultAX: trap_exit: What I just typed, that is.

0:27 stcredzero: bbloom: you re not p[aying attention. I'm running f on dozens of items to support 1000's of entities.

0:27 devn: stcredzero: i know we're typing into this thing that is supposed to contain smart people

0:27 but i think we are just having a hard time communicating

0:28 it sounds like there are reasons why you are choosing this approach

0:28 but we dont know everything about your problem

0:28 SegFaultAX: ,((fn [a b] (map vector a b)) [1 2 3] [:a :b :c :d])

0:28 clojurebot: ([1 :a] [2 :b] [3 :c])

0:28 SegFaultAX: trap_exit: ^

0:29 devn: ,(zipmap [1 2 3] [4 5 6 7])

0:29 clojurebot: {3 6, 2 5, 1 4}

0:29 devn: it might work... just saying...

0:29 SegFaultAX: devn: I think he wants a list of pairs.

0: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*!

0:29 bbloom: stcredzero: i scrolled up and find no mention of you making that point :-P

0:29 devn: SegFaultAX: sure, but im just saying that's close enough for jazz

0:29 stcredzero: bbloom: search for where I talk about sub-grids.

0:30 devn: heh

0:30 bbloom: stcredzero: i'm looking at it, but i'm not a mindreader

0:30 devn: "ask me about the time i cured world hunger"

0:30 bbloom: stcredzero: still, even with dozens, i don't think you want pmap

0:30 stcredzero: bbloom: admit it, you were taling the whole time assuming I'm talking about paralleism per-entity.

0:30 devn: kidding of course, just sounded funny

0:31 stcredzero: dude, this isn't a conspiracy

0:31 bbloom: stcredzero: i did think that, however, i still don't think pmap is what you want

0:31 stcredzero: for every single reason i've listed

0:31 SegFaultAX: stcredzero: Why are you still not measuring?

0:31 stcredzero: bbloom: show me where pmap is costlier than O(n*log32(n)) and you win. Instantly

0:31 bbloom: I can't measure yet.

0:31 devn: algorithm designs are meant to be tested

0:31 bbloom: stcredzero: if you can't measure yet, you can't optimize yet

0:31 stcredzero: and constants matter

0:31 a lot

0:31 stcredzero: bbloom: I can design.

0:31 bbloom: especially in threading

0:32 devn: stcredzero: see my previous comment

0: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

0:32 devn: amen

0:33 bbloom: hell, i've fixed multithreading bugs in the tools for finding multithreading bugs in xbox games

0:33 and even that took a few tries :-P

0:33 stcredzero: bbloom: I used to say that stuff to meetup audiences.

0:34 bbloom: stcredzero: i don't know why you think we're out to get you

0:34 we're trying to help

0:34 stcredzero: bbloom: also in your commentary, are you assuming there's any coordination between f's?

0:34 bbloom: nope

0:34 stcredzero: bbloom: so you're telling me that the coordination is O(n*log(n)) but that the constant factors are ungodly huge.

0:35 bbloom: stcredzero: i'm done arguing until you come back with numbers

0: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.

0:35 kras: HI Again. Any recommendations for network/graph library in clojure? Something equivalent to networkx in python.

0:35 seangrove: stcredzero: bbloom is a good guy, worht listening to, even if he comes across as borderline crazy ;)

0:36 bbloom: seangrove: surely you know i'm full on crazy by now!

0:36 stcredzero: I'm suspecting that no one knows what the ovehead of pmap is.

0:36 trap_exit: SegFaultAX: noted, thanks!

0:36 SegFaultAX: stcredzero: Well, that's because it depends on lots of stuff.

0:37 bbloom: stcredzero: no one is guessing b/c we're explicitly telling YOU not to guess

0: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.

0:38 And even if those conditions are met, pmap is still probably not the tool you need for a tight game loop.

0:38 (It's too broad a hammer)

0: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.

0:39 SegFaultAX: pmap is a sledge and you need a ball pene to have consistent processing time per frame.

0:39 stcredzero: How is "go measure and come back with data" a catch 22?

0: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!

0:40 SegFaultAX: stcredzero: Then why are we arguing? It's not like s/pmap/map/g is that hard to type.

0: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.

0:42 SegFaultAX: stcredzero: Ok. Let us know when you have measurements. Good luck!

0:42 stcredzero: As evidenced by the assumptsions that f would be cheap, that parallelism was per-entity, etc.

0:44 What would be actually helpful is to let me know what things pmap is not going to like in more detail.

0:50 technomancy: stcredzero: answering questions on IRC is largely a matter of pattern matching

0:57 kras: HI Again. Any recommendations for network/graph library in clojure? Something equivalent to networkx in python.

0:58 I don't require many algorithms, performance is the prime criterion

0:59 titanium, loom???

0:59 lazybot: kras: Yes, 100% for sure.

0: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.

0:59 "have it" is mistyped v = t

1:00 technomancy: stcredzero: haven't been paying attention to the discussion, just throwing that out there

1:00 beamso: kras: https://github.com/prismatic/plumbing ?

1: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

1:01 stcredzero: technomancy: I think your comment was very apt.

1:01 technomancy: (even if I have no idea what the actual answer is)

1:02 stcredzero: technomancy: because they were pattern matching, getting the details of my proposal wrong, then arguing from their pattern-match based assumptions

1:03 technomancy: hey, it's a 95%-effective approach

1: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.

1:03 My esoteric projects are 5% ideas.

1:03 technomancy: (this is why we have bots)

1: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

1:08 technomancy: everyone does it

1:08 the real world is too complicated to function any other way

1:08 you see someone dress a certain way and you make assumptions about their personality

1:09 because it's far more efficient than finding out for yourself

1:09 amalloy: technomancy: he left after cubbyholing everyone

1:09 technomancy: amalloy: well you know what they say about people who leave in the middle of IRC conversations

1:10 amalloy: they rarely get answers they're happy with?

1:10 technomancy: that they bloody well should learn how bouncers work

1:10 zspencer: ZNC + irsssi

1:11 technomancy: kind of annoyed that he ended up thinking I was just encouraging him

1:11 beamso: or screen + irssi

1:12 zspencer: ZNC allows multi-client so you can limechat in when you're afk

1:12 technomancy: tmux allows mosh though


1:12 zspencer: But yes, a screen/tmux terminal is good stuff

1: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

2: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?

2: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

2:54 if you only need the values then (map f (vals m))

2:54 AFAIK that's fastest as in fastest to type in the editor :)

3:09 antonv: hi

3:09 any cider users here?

3:10 wink: even if it's St. Patrick's Day, I'll wait a few hours with that :)

3:11 antonv: when I execute an expression with C-x C-e and the expression has error, then a stack trace buffer shows up

3:11 is there a shortcut to close it quickly, without havign to switch to that buffer by C-o first?

3:12 C-x o I mean

3:12 in SLIME I can just press q

3:12 and the debugger buffer closes

3:13 but in cider I must switch to the buffer - tedious

3:15 OK, added (setq cider-auto-select-error-buffer t) to the .emacs

3:15 not the error buffer is selected automatically, I just press q and it closes

5:43 chare: do you guys use intellij

5:43 or use just cursive?

5:51 wink: LightTable for Clojure and Lua, IDEA for all other languages

5:58 clgv: eclipse/counterclockwise

7:11 Pate_: how is Clojure's multimethod support implemented, specifically the dispatch function?

7:12 nightfly: probably with a hashmap and lambdas

7:12 Pate_: found this: https://github.com/clojure/clojure/blob/0b73494c3c855e54b1da591eeb687f24f608f346/src/jvm/clojure/lang/MultiFn.java

7:13 these is an IPersistentMap methodTable that caches the "preferred method" for a given dispatch.

7:14 sorry, the methodTable has all the possible methods and preferTable caches the preferred method.

7:35 clgv: Pate_: why do you ask for implementation details? just for learning and understanding?

7:35 Pate_: yes.

7:36 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.

7: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?

7:45 sm0ke: pepijndevos: gen-class is one way for defining java classes in clojure, :aot and :main are leinigen specific

7:46 clgv: Pate_: yeah in prinziple they are like a "cond" or "case" but open for dynamic extension

7: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?

7:46 sm0ke: pepijndevos: in clojure evrything is compiled to bytecode at the moment it is required, :aot is for doing it ahead of time

7:46 pepijndevos: runnable uberjar that is

7:46 clgv: pepijndevos: yes. :gen-class in the namespace of the -main method and :main and :aot in project.clj

7:46 sm0ke: pepijndevos: yes that is correct, if you want to invoke it like 'java -jar myjar.jar'

7:47 pepijndevos: cool. thanks

7:48 Was unsure if gen-class was still needed with :aot. I guess ahead of time compilation does not nececerily mean generating classes.

8:00 gfredericks: well it doesn't mean generating the particular class that gen-class generates

8:00 it does generate lots of other classes

8:02 usually the point of using gen-class is to make a class with a .main method

8:02 and you don't have one of those otherwise

8: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

8:39 failing..https://gist.github.com/jespada/729531b539ff6d556c1e

8:51 AeroNotix: w00t just bought my EuroClojure ticket!

8:52 http://euroclojure.com/2014/

8:52 anyone else going?

9:55 wagjo: AeroNotix: I'm going

9:55 AeroNotix: wagjo: in KRK already or ?

9:56 wagjo: AeroNotix: 3 hours by car from my place

9:56 AeroNotix: It was an offer I could not refuse :)

9:57 AeroNotix: wagjo: indeed :) Our office is going (3 clojure people!) woot

9:57 looking forward to it

9:57 hyPiRion: I'm tempted, but money

9:58 AeroNotix: hyPiRion: where you at?

9:58 mpenet: going too, not sure from where yet though

9:58 AeroNotix: Norway iirc? hyPiRion

9:58 hyPiRion: Oh hey I'm still a student at that moment I guess

9:58 yeah

9:58 mpenet: ppl going are staying where (hotel)?

9:58 wagjo: AeroNotix: Well you have it like 15 minutes, it would be shame not to go :)

9:58 AeroNotix: hyPiRion: dude, 70EUR

9:58 wagjo: it's right down the road from my flat

9:58 :D

9:58 hyPiRion: AeroNotix: that's not the costly part though. Planes and hotel is the main issue

9:59 mpenet: Hotel are kind of cheap there

9:59 AeroNotix: but yeah, places are cheap

10:00 hyPiRion: ah, you guys

10:01 * hyPiRion sends an email re tickets

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 oops

10:17 depends where you're coming from in EU

10:17 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 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 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 i saw "conj plane ticket"

10:40 and assumed you were talking about clojure/west

10:40 AeroNotix: well, we were just talking generally :)

10:41 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 when does the CFP end?

10:41 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 He built that in like a day with no hoplon experience

10:43 "Rapid Prototyping in Hoplon"

10:43 something like that is kind of what I'm thinking

10:46 so, now that we're talking about /that/ plane ticket... 1,622 USD

10:46 AeroNotix: yikes

10:46 I just take a walk and boom I'm there :)

10:46 devn: not a big surprise honestly

10:47 haha

10:47 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 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 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 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 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 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 eric_normand: thanks for the help

11:46 seubert: arrdem: congrats, you survived SXSW for another year

11:46 :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 glad your friends are ok

11:47 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 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 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 "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 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 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 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 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 ~'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 ,((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 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:22 * llasram brandishes his cross

13:23 * llasram wards off the evil eye

13:23 mdrogalis: Hmm

13:25 Works great, thanks justin_smith!

13:25 justin_smith: np, I made something similar for an ill-considered DSL ages ago

13:25 I reconsidered the technique, but will never forget how it was done

13:25 lol

13:26 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 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 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 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 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 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 s/and/or/

13:46 justin_smith: which brings us back to performance of course

13:46 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 (remove #{[:b _]} [[:a 1] [:b 2] [:c 3]])

13:52 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 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 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 there is not much to reinvent there

14:05 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 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 * seangrove tweets, "Technomancy officially endorses sha1 for password hashing, says md5 will do in a pinch"

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 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 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 http://en.wikipedia.org/wiki/Surrogate_key

14:10 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 and java has an API for that?

14:11 ah yes

14:12 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 yeah, it has a method to create random ones

14:12 and they are big enough that conflicts are vanishingly unlikely

14:13 ,(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 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 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 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 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 and I can set a reasonable limit on the key size

14:19 but obviously URLs must be variable length

14:19 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 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 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 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 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 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 dnolen_: Finding mostly twitter threads :)

14:39 (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 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 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 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 a seq of strings that represent lines

15:08 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 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 hash-map calls Persistent

15:21 hash-map calls PersistentHashMap's create method

15:21 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 so I'd just consider them equivalent.

15:26 aaronj1335: Cr8 cool thanks

15:27 i'm trying to convert a python program that does some nlp stuff to clojure

15:27 and the clojure version is 4-5x slower

15:27 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 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 second sdegutis.

15:31 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 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 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 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 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 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 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 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 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 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 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 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 aaronj1335: lein has bad defaults for benchmarking

15:55 aaronj1335: cool thnx

15:56 dnolen_: aaronj1335: :jvm-opts ^:replace ["-Xmx512m" "-server"]

15:56 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 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 you definitely want transients for that many objects

15:58 memory access and GC are going to dominate the code as you have it now

15:58 the mutability in python actually spares you a ton of garbage overhead, doubly true when you do one loop instead of two

15:58 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 aaronj1335: I would first get the fastest idiomatic Clojure, should compete w/ Python

16:00 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 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 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 especially if you CAN'T do all the work (ie infinite lazy seqs)

16:05 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 python generators don't capture past states in anyway

16:06 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 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 aaronj1335: you can get exceptionally good performance in both space and time for the same style of code

16:09 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 I have something like this in there right now, `(fn [msg#] ~@body)`

16:11 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 (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 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 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 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 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 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 Now I just wish I remembered who was asking for it D:

16:23 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 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 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 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 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 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 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 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 don't i need that too?

17:51 justin_smith: I don't know what you need

17:52 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 damn it

17:56 bbjva: hi all

17:57 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 ~snotback

18:00 seangrove: clojurebot: botsnack

18:00 clojurebot: Titim gan éirí ort.

18:00 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 * seangrove defends clojurebot against the bullies

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 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 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 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 *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 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 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 no mutation in fp

18:18 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 picking it up for work, loving the language lots so far, just changing my way of thinking is taking time

18:19 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 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 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 prosthetic nib

18:27 maybe it's not generics that are ugly but generics + classes/inheritance.

18:27 I have rather painful memories.

18:27 brehaut: yeah classes and inheritance are a pig

18:28 and yes they do make generics bleark

18:28 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 amalloy: onomatopoeia

18:28 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 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 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 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 = != 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 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 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 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 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 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 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 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 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 But only if I visit a route directly, the redirect from login results in an empty session

19:02 I am using the interactive-form workflow

19:02 Also, :credential-fn returns a valid login

19:05 Even though the login succeeds, current-authentication always returns nil

19:08 seangrove: Ugh, damnit

19:09 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 ,(instance? clojure.lang.ILookup {})

19:11 clojurebot: true

19:11 seangrove: Hrm, struggling to get it to work in cljs

19:11 Let me see if I can find the right name for it

19:12 cljs.core/ILookup

19:12 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 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 (-> 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 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 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 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 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 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 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 And I'm wondering how that would even work, since you can't know until runtime what to inject.

21:00 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 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 As is Dagger or Guice.

21:06 amalloy: those are what i know nothing about; DI the technique makes sense to me

21:06 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 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 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 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 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 (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 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 (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 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 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 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 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 ruby does have first class functions

21:40 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 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 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 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 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 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 i guess it still fits in though

23:55 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 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 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 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 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

Logging service provided by n01se.net