#clojure log - Nov 24 2013

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

0:00 technomancy: that's the only reason nginx is needed at small scale

0:00 swarthy: Okay so, uberjar on my machine. Nginx to forward to port setup for uberjar. su myappuser - java -jar myapp_uberjar

0:00 that is roughly the idea

0:00 with nginx adding more security \ stability

0:01 justin_smith and technomancy thanks for the input

0:01 justin_smith: np

0:01 dsrx: nginx is probably better for serving static files too

0:02 justin_smith: yeah, I usually set it up so the app never sees the requests for static files

0:02 swarthy: I think I came across that, you have to do something to allow the uberjar files to be served statically or something like that?

0:03 justin_smith: yeah, it is a pretty standard nginx config

0:03 so if you are running out of a jar, you would also want to unzip the jar in a predictable place

0:03 if you wanted that feature

0:03 with tomcat, the jar gets unzipped automatically and you can just point to where it ends up

0:04 swarthy: justin_smith: how much more cognitive overhead does getting tomcat and its ilk set up?

0:04 I know zero about java stack for deployment.

0:04 justin_smith: swarthy: in my experience, just adjusting the default jvm opts

0:05 then I copy the war for my app into /var/lib/tomcat7/webapps/ROOT.war

0:05 service tomcat [start|restart|stop] as apropriate

0:05 swarthy: what benefit does this yield over uberjar?

0:05 justin_smith: though it has options to auto-restart when you upload an artifact

0:05 the service abstraction

0:05 not having to find the pid manually or do a killall or something

0:06 logging in a default and reasonable way

0:06 without having to do anything other than println in my app if I don't want to do more

0:06 complete with zipping old logs renaming as apropriate etc.

0:07 swarthy: are there any good resources for learning this, anything that you used to get started or are you an old java hand?

0:07 justin_smith: it just takes care of a lot of the little nuiscance things that otherwise add up

0:07 technomancy: huh; I didn't know tomcat did logrotate

0:07 justin_smith: I just learned from my coworkers

0:07 yeah, it gzips old logs, all that standard stuff

0:07 swarthy: justin_smith: cool, I'll have to investigate

0:08 justin_smith: well from my coworkers, plus googling

0:10 also, using a war file in a tomcat container is probably the definitive way to run clojure webapps on elasticbeanstalk, which gives you a superset of tomcat's conveniences

0:11 with beanstalk I rarely even need to ssh to the box

0:11 'lein beanstalk deploy', send out the messages to interested parties when I am informed the new version is up

0:11 the rest is automated

0:14 something I am working on, regarding all this stuff, is a way to:

0:14 a) make it easy to deploy and access credentials

0:14 b) make development and usage of credentials easy

0:14 c) without ever having unencrypted credentials in git

0:15 swarthy: justin_smith: I haven't used elasticbeanstalk, how does it compare price wise to VPS providers like linode and digital ocean?

0:15 justin_smith: does Pallet do that sort of stuff, I looked at it briefly today?

0:15 justin_smith: I don't know actually, I don't pay that bill :)

0:15 swarthy: justin_smith: Ah, well DigitalOcean is dirt cheap if not a bit crappy from time to time.

0:16 but they are getting better and better

0:16 BAMbanda: I don't think anyone has developed firefox extensions with cljs and I would like to be among the first

0:16 justin_smith: I think pallet is meant to abstract over various deployment and hosting options

0:16 BAMbanda: i have some questions on packaging though:

0:17 will lein be able to output the js to a folder outside of the root folder that contains project.clj?

0:17 technomancy: BAMbanda: I have never used cljs but I would love to do some 'zilla hacking with it

0:17 BAMbanda: you can put .. in :target-path or whatever

0:17 justin_smith: swarthy: my guess would be that we go with amazon because they are reliable, large scale, and pretty standard as far as automated deployment goes

0:17 BAMbanda: technomancy, yeah thats exactly what im trying to do!

0:17 justin_smith: swarthy: I've been meaning to check out various openstack alternatives though

0:18 BAMbanda: technomancy, but even if that target path is a level above the lein project directory?

0:18 technomancy: BAMbanda: that probably has more to do with lein-cljsbuild though, which I haven't used

0:18 I think so?

0:18 BAMbanda: hmm

0:19 swarthy: justin_smith: You guys are a dev shop too though, so you can pass cost on to clients perhaps.

0:19 so stability > price

0:19 not a bad thing if that is the case

0:20 justin_smith: swarthy: yeah, we bill clients for their hosting, but if we can save money on deployment, I can probably talk my boss into some fraction of that money saved landing in my pocket :)

0:21 swarthy: Ahaha, well you guys having big name clients you will want that extra stability. DigitalOcean for example gives you a bare VPS fo $5 - $50 + per month. So you would need some sort of DevOps in place to get the same speed of deploy as AWS.

0:22 justin_smith: right

0:22 swarthy: and likely would not be anywhere near as stable or bandwidth limitations

0:22 justin_smith: and any downtime would translate into untold lost money

0:22 swarthy: yeah

0:22 for me, bootstrapping and mucking around I need cheap, lol.

0:22 justin_smith: though the bigger clients have their own server farms and hosting facilities, and we just ship the code to run to them

0:23 the biggest won't even let us use clojure :(

0:23 though to our credit we keep trying

0:24 swarthy: What do they want instead?

0:25 justin_smith: google has their python backend and weird google data backend

0:25 we don't even touch that stuff, we just ship the frontend with them

0:26 though sometimes we have to deal with some terrible spreadsheet to enter data the app needs

0:26 swarthy: sounds about right. People love excel.

0:26 In a scary way.

0:26 justin_smith: nike has a java stack in house, and let us use clojure for a while, until the adopted automatic security audits, and couldn't find a tool that did that for clojure code

0:27 bitemyapp: justin_smith: that's really disappointing.

0:27 justin_smith: we push back, really we do :)

0:27 swarthy: I wonder what the language landscape will be in ~5 years or so.

0:27 Just in the short term.

0:27 I wonder if it will change much.

0:27 arrdem: justin_smith: what toolkit/program did they do said audits with?

0:28 justin_smith: our tech leads and producers love clojure for the productivity (and it attracts high quality devs and keeps them interested, in their experience)

0:28 arrdem: justin_smith: I'm curious who peddles it.

0:28 justin_smith: arrdem: I'll need to look it up

0:28 we contacted them, and they gave us a quote for how much it would cost for them to add a clojure analysis feature

0:29 arrdem: justin_smith: kk. the pentest crowd is near and dear to my heart, which is why I'm curious

0:29 justin_smith: $(TOODAMNMUCH)

0:29 justin_smith: and actually, I should probably keep things at this level of vagueness, because this is client information after all

0:29 arrdem: yeah true that.

0:29 bitemyapp: justin_smith: what order of magnitude was the quote?

0:29 arrdem: I guess I'll just ask google...

0:30 justin_smith: bitemyapp: under a million :)

0:30 arrdem: oh, we never got clojure onto google, we just do frontend for them

0:31 swarthy: justin_smith: what languages are most requested by your clients. Which is to say what languages do people most want contracted in your experience?

0:31 justin_smith: bitemyapp: could be a decent job, if you could get someone to pay you to write that static analysis tool

0:31 arrdem: justin_smith: wha?... I meant google for the vendor...

0:31 justin_smith: ahh

0:31 they are also a client of ours, I got confused :)

0:32 also, I think static analysis for blub languages is much easier

0:32 bitemyapp: justin_smith: I agree, but I could write a basic static analysis security tool for Clojure

0:33 justin_smith: I'm sure you could, and I would love it if that existed

0:33 bitemyapp: the only real problem would be a lack of a nice security problem corpus.

0:33 justin_smith: and I know my bosses would pay to use it

0:33 arrdem: bitemyapp: what do you think such a thing would look like? a typechecker with information privilages type annotated?

0:33 bitemyapp: justin_smith: well I was looking at a nice Clojure code parser/dumper and it was particularly well suited to this kind of problem.

0:33 justin_smith: known cut and paste boilerplate patterns are a boon to sa

0:34 bitemyapp: arrdem: the types would be only marginally useful and probabilistic.

0:34 arrdem: bitemyapp: then what kind of analysis would you be thinking to provide?

0:34 bitemyapp: SQL injection would be the first and most obvious.

0:34 and is potentially a problem if somebody is doing something stupid with cjj in Clojure.

0:35 justin_smith: really what you would want to look for is any interface of read or eval with data that comes from third parties

0:35 arrdem: justin_smith: I think bitemyapp is on the right track.. there are more (read) and (eval) equivalent forms than just the obvious c.c.t ones.

0:35 bitemyapp: anything that uses a non-edn reader really.

0:36 the subject has been on my brain because my company is talking to a security vendor.

0:37 a tool vendor, offering "static analysis"

0:37 I was very disappointed with the tool and the price they were asking for what is frankly, snake oil.

0:37 justin_smith: yeah, SA stinks of that to me in many instances

0:37 bitemyapp: It's possible to produce very good static analysis tools

0:38 The Microsoft SA tools for C++ and .NET are probably among the best, but they're constrained to type checking, undefined behavior, etc etc etc

0:38 they're not really about "security" per se.

0:38 justin_smith: right, but it's also possible for a lot of money for bullshit if you call it static analysis

0:38 dsrx: what kind of type checking does a C++ static analysis tool do that the compiler does not?

0:38 (or C#, for that matter)

0:39 bitemyapp: dsrx: compilers aren't really allowed to use hueristics and probabilistic warnings to the degree an SA tool can

0:39 dsrx: SA tools will catch a lot more bugs than a vanilla C++ compiler because they'll warn on stuff that might be "valid" code or have undefined behavior that a compiler would let fly.

0:39 -Wall isn't enough.

0:39 justin_smith: hell, one could probably extend kibit to give security warnings

0:40 bitemyapp: I'm not doing that and I don't think it's a good idea.

0:40 dsrx: sure, I can definitely see how they could warn about undefined behavior

0:40 bitemyapp: dsrx: http://www.altdevblogaday.com/2011/12/24/static-code-analysis/

0:40 imagine would a static analysis tool could do with something like Haskell?

0:40 what a*

0:40 justin_smith: or, what made me think of kibit: things that aren't guaranteed to be shitty security, but give enough reason to advise a second look at the surrounding code

0:40 arrdem: kibit is the wrong way to come at this sort of analysis...

0:41 really you want a theorem prover like c.c.t

0:41 bitemyapp: seriously.

0:41 justin_smith: sure

0:41 bitemyapp: arrdem: that's not what we're talking about

0:41 arrdem: we're talking about heuristic-based SA which can be a lot more comprehensive than c.c.t

0:41 you can't cross function barriers with something like c.c.t, it's intentionally very conservative which is completely the opposite of what you want in this context.

0:43 you want something that's acting on a probability and hueristics so it can track things across functions and namespaces and be paranoid.

0:44 arrdem: it's better to just make the paranoid tool happy.

0:44 and take the warnings seriously.

0:44 justin_smith: right, sa has a relatively low cost for false positives

2:00 bitemyapp: SegFaultAX: he herped and he derped.

2:02 TEttinger: bitemyapp, herping is a useful skill, you never know when you will need to treat a snakebite.

2:03 ... did someone fail the Almighty Employment Challenge?

2:04 bitemyapp: TEttinger: no, just people being stupid about FP on Twitter.

2:04 TEttinger: I should take a census of white papers to make my point sometime.

2:05 TEttinger: heh. ironic that they're complaining on a site that has a fairly FP server-side (twitter uses scala I believe)

2:06 oh what's that? functional programming can't scale? well we have untold millions of users, minus 1. you.

2:06 somehow you were dropped from our DB, oh no...

2:07 * TEttinger likes the idea that all of twitter is controlled by a sassy AI

2:08 bitemyapp: HackerNewsOnion: Failed YC founder reluctantly taken back in by parents

2:08 TEttinger: it's not really about scale, they just don't understand the utility.

2:08 TEttinger: which is insane, if I kept a journal of bugs I wrote in Clojure 90-95% of them would be things languages like Haskell catch.

2:08 ditto Java.

2:09 doing the same "kind" of language over and over with a rebrand (Golang) is not progress.

2:09 TEttinger: yeah, there's a bad reputation that FP is useless for real-world tasks and is only used in academia

2:09 bitemyapp: well they keep slowly coming in our direction.

2:09 TEttinger: exactly.

2:09 bitemyapp: Garbage collection, transparent reference types etc are now standard.

2:09 as is first class functions, lexical scoping

2:09 TEttinger: I forget how clojure is scoped

2:10 bitemyapp: but it amuses me that the only things that really improve the modern languages are things FP did first.

2:10 TEttinger: lexical, of course.

2:10 TEttinger: Clojure is the best bits of Scheme along with CL-style full macros.

2:10 only thing it's really missing is TCO.

2:11 TEttinger: minus reader macros too, which isn't a huge loss for most tasks

2:11 bitemyapp: which is mostly a non-issue due to loop-recur, unless you've got a mutually recursive algo that needs trampolined or rewritten.

2:11 I don't think reader macros was one of the better things Common Lisp had :P

2:16 okay, this guy on Twitter is a fuckin' prick.

2:16 "when you're done confessing your faith" holy fucking shit what an asshole.

2:16 tbaldridge: feel like addressing the doubts of somebody that doesn't understand FP?

2:17 TEttinger: bitemyapp, leave him to stew in his misconceptions.

2:17 "don't feed the trolls"

2:18 bitemyapp: TEttinger: I posted links to white papers so people could learn more anyway.

2:18 TEttinger: good plan

2:22 bitemyapp: TEttinger: going to drink tea to ease out of the red haze now.

2:22 yogthos: hey

2:25 john2x: hmm since I can't require private fn's, how do I test them?

2:25 unit test*

2:26 bitemyapp: john2x: #'

2:27 john2x: bitemyapp: sorry I don't understand?

2:27 bitemyapp: I was trying to decide if I should do the google transcript answer or the technically correct but sufficiently baffling to force you to research and learn answer.

2:28 john2x: the above answer was an example of the latter. Do you want me to perform the requisite google query and explain to you the clicks and keyboard strokes required to get the answer in excruiciating detail?

2:28 john2x: because it's not like it's impossible that somebody else couldn't have possibly had the same question

2:28 TEttinger: $google clojure reader

2:28 lazybot: [Clojure - reader] http://clojure.org/reader

2:28 bitemyapp: john2x: leading them to ask said question in a public forum or Q&A site, like perhaps Stack Overflow

2:28 john2x: where they would receive an answer their google'able query

2:28 john2x: enabling you to have an answer for your common question

2:29 john2x: and then you'd perhaps realize that you could google things faster than getting trolled on IRC

2:29 TEttinger: it's called a var-quote, which should be easier to google

2:29 it should also give you an idea what it does

2:29 john2x: my bad. thanks both

2:29 bitemyapp: I don't even mind answering questions, I mind answering googleable/boring questions.

2:31 now if it's a question that requires reading code you can't understand, then we're in business.

2:31 say, details of Clojure's compiler that aren't always easy to understand.

3:00 arrdem: http://i.imgur.com/0i2apZv.gif

3:00 arrdem: bitemyapp: thank you for ridding me of my drowsyness.

3:01 bitemyapp: also with regards to the above, google doesn't deal nicely with special syntax like the arrows and var-quote. Those are reasonable IRC questions just because most search engines won't do the sort of full text indexing you really need to get answers there.

3:20 echo-area: s

3:20 Sorry

3:20 BBL

3:21 TEttinger: arrdem: symbolhound

3:22 $google symbolhound

3:22 lazybot: [SymbolHound: Search Better. Code Better.] http://symbolhound.com/

3:22 arrdem: TEttinger: I have a new favorite website...

3:22 TEttinger: it's amazing isn't it. that no one has tried it before... the indexing isn't great so far

3:23 but it seems to be rapidly improving

3:23 man I wonder if they have an API I can consume from lazybot

3:40 bitemyapp: arrdem: he didn't know #' anyway.

3:40 arrdem: googling the original question "use a private function" would've gotten him the answer just fine

3:41 arrdem: not the #' syntax. I was intentionally being a pain by answering #'

3:41 arrdem: being asking trivially googleable questions is senseless.

3:41 because*

3:48 echo-area: bitemyapp: Or a systematical training

4:08 zeebrah: is contains? not the right way to check if a map contains a key?

4:08 it returns false for every key i know to be in the map so i'm surprised

4:11 echo-area: zeebrah: Use `find'

4:12 bitemyapp: zeebrah: contains? is for keys in maps, yes.

4:12 zeebrah: could you please demonstrate an example.

4:12 echo-area: no.

4:13 zeebrah: user> (contains? :a {:a 20 :b 10}) -> false

4:13 echo-area: bitemyapp: Why?

4:13 bitemyapp: ,(doc contains?)

4:13 clojurebot: "([coll key]); Returns true if key is present in the given collection, otherwise returns false. Note that for numerically indexed collections like vectors and Java arrays, this tests if the numeric key is within the range of indexes. 'contains?' operates constant or logarithmic time; it will not perform a linear search for a value. See also 'some'."

4:14 bitemyapp: zeebrah: you pass the collection first, the key second.

4:14 zeebrah: read the documentation.

4:14 ,(contains? {:a 20} :a)

4:14 clojurebot: true

4:14 zeebrah: bitemyapp: just found that out

4:14 bitemyapp: it should throw an error or something.. but that makes a lot of sense now .. phew :)

4:14 bitemyapp: zeebrah: should throw an error? Clojure is dynamically typed and abides by the GIGO principle.

4:15 zeebrah: if you want something that catches mistakes, you're thinking of Haskell or Scala.

4:15 zeebrah: not at all

4:16 bitemyapp: zeebrah: then be prepared to embrace GIGO

4:17 echo-area: bitemyapp: Care to tell me your reason?

4:17 zeebrah: no

4:17 bitemyapp: echo-area: nope, I'm going to bed and reading an awesome book while sipping my lager.

4:18 zeebrah: if you pass in something that isn't a collection that's clearly an error

4:18 bitemyapp: "clearly" not really, no.

4:18 zeebrah: you're wrong

4:18 most dynamic languages do it that way

4:18 bitemyapp: there is no right or wrong, it's a design decision.

4:18 most? no.

4:18 Perl and Ruby do the same thing.

4:19 GIGO is fundamentally part of those languages.

4:19 zeebrah: smalltalk, common lisp, scheme

4:19 echo-area: bitemyapp: Okay. My guess is that `contains?' is more general than `find'. Not sure if it was your reason. Anyway, have a nice reading :)

4:19 bitemyapp: only Python is persnickety.

4:19 echo-area: it's not the reason, it's just the smarter function to use as long as you understand it, and since zeebrah expected contains? to act on the map key rather than value, I figured they understood it modulo arity.

4:20 echo-area: find has the same arity as contains? anyway, so it would've broken for zeebrah in the same exact way, not that you bothered to check why contains? wasn't working for them.

4:20 echo-area: avoid making blind suggestions without checking to see what the actual problem is.

4:21 zeebrah: i agree with bitemyapp find isn't the answer to the question

4:21 echo-area: bitemyapp: Noted. And thank you.

4:21 bitemyapp: off to my beer, bed, and book.

4:21 echo-area: Good night.

4:21 zeebrah: night!

4:30 amalloy: ,(contains? :a {:a 1})

4:30 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: contains? not supported on type: clojure.lang.Keyword>

4:31 amalloy: that changed in 1.5, which i thought was worth mentioning since apparently there was a spirited debate in here about which is right

4:31 zeebrah: awesome good to hear that amalloy

4:31 amalloy: well, don't get too excited. get, find, and so on still silently return nil

4:32 zeebrah: and i really thought i was using 1.5

4:32 oh :/

4:37 echo-area: ,(find :a {:a 1})

4:37 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to java.util.Map>

4:38 echo-area: It also applies to `find' :)

5:07 amalloy: &(find :a {:a 1})

5:07 lazybot: java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to java.util.Map

5:07 amalloy: i guess find was always that way

5:22 dbushenko: hi all!

5:27 bamford_: folks, quick question: in https://github.com/clojure/core.async/blob/master/examples/walkthrough.clj#L75-L81 , is looks to me like a thread is spawned and then runs indefinitely, since it contains a (while true ...) -- correct? It will continue running in the background even after leaving the (let ...) scope?

5:30 amalloy: yes

5:32 bamford_: amalloy: ok, then I understand that it's not an ideal example for beginners, one should never use (while true) in a (thread) since that will bind one OS thread. I will use loop ... recur then, thanks!

6:47 echo-area: amalloy: Are clojurebot and lazybot running different versions of Clojure?a

6:47 ,*clojure-version*

6:47 clojurebot: {:interim true, :major 1, :minor 6, :incremental 0, :qualifier "master"}

6:47 echo-area: &*clojure-version*

6:47 lazybot: ⇒ {:major 1, :minor 4, :incremental 0, :qualifier nil}

6:47 echo-area: Sorry, I should have evaluated these first

6:47 Didn't mean to bother you

7:25 myguidingstar: hi all, is there any test framework support mock file system io?

10:45 tcrayford: anybody got any idea how to convince the clj compiler to specialize to one static method of http://twitter.github.io/commons/apidocs/com/twitter/common/quantity/Amount.html (the `of` method)? Everything I've tried so far results in `CompilerException java.lang.IllegalArgumentException: More than one matching method found: of,`

10:45 things I've tried:

10:45 (defn amount-of-seconds [^long n] (Amount/of n Time/SECONDS))

10:46 can't type-hint locals with a primitive initializer, so that's out

11:04 justin_smith: http://stackoverflow.com/questions/11919602/generating-clojure-code-with-type-hints tcrayford, this may help

11:08 je: how (if?) is it possible to but the test-constant outside of the case: https://gist.github.com/jacobemcken/5778cb6a2caed2d2ebf2

11:08 xcthulhu: How do I check what protocols LineNumberingPushbackReader instances?

11:08 justin_smith: xcthulhu: clojure.reflect/reflect

11:09 it returns that info (along with a whole bunch of other stuff)

11:09 xcthulhu: Thanks :D

11:22 justin_smith: tcrayford: what about using (long n) (long Time/SECONDS)

11:22 the second may be unneccisary

11:22 tcrayford: justin_smith: the second long isn't wanted even, that's an enum

11:23 justin_smith: oh

11:23 yeah, looking at Unit now

11:23 tcrayford: the (Amount/of (long n) Time/SECONDS) call fails though, same thing about more than one matching call :/

11:23 justin_smith: weird

11:24 what is the full class of Time/SECONDS?

11:27 tcrayford: justin_smith: http://twitter.github.io/commons/apidocs/com/twitter/common/quantity/Time.html

11:28 (this is for connecting to zookeeper via the twitter commons client: http://twitter.github.io/commons/apidocs/com/twitter/common/zookeeper/ZooKeeperClient.html)

11:28 I might well just write a java shim around it that specializes to long

11:29 justin_smith: have you tried using the double or float or int versions? on the off chance

11:30 tcrayford: justin_smith: yep ;)

11:30 tried with (double n), (float n) and (int n)

11:36 xcthulhu: Hey, I'm a clojure noob and I just read some code where someone wrote (def- ^{:const true} blah "blah")

11:36 Is that idiomatic for private constants?

11:36 justin_smith: def- is idiomatic for private things

11:36 I don't know if :const actually does anything though, maybe someone else does

11:37 Bronsa: :const actually does something

11:37 justin_smith: http://stackoverflow.com/questions/9162558/how-does-clojure-const-work

11:37 Bronsa: it avoids the Var indirection when possible

11:37 justin_smith: that's good to know

11:38 how does it interact with redefinition?

11:38 Bronsa: it breaks it

11:38 justin_smith: figures

11:38 hyPiRion: with pain

11:38 justin_smith: thanks, that's useful

11:38 so I should wait until my code is "done" before adding const hints I guess

11:39 xcthulhu: Yeah, it's a premature optimization...

11:39 Bronsa: justin_smith: the rationale is that if you explicitely use ^:const you know what you're doing.

11:39 justin_smith: right

11:39 so basically, if I find something is getting looked up too often in a tight loop, use :const, otherwise just leave it be

11:40 Bronsa: if it's a constant, yeah

11:40 justin_smith: of course

11:40 but most top level stuff in good clojure code should be constants

11:41 TimMc: And even then, shouldn't hotspot help out?

11:41 and branch prediction

11:41 justin_smith: it would be interesting to see a comparison

11:42 TimMc: It would be interesting to have everything be constants by default in production, but make everything rebindable during (say) lein test.

11:42 test, repl... not sure what else

11:43 Bronsa: TimMc: that's what (hopefully) will be possible to do with tools.* one day :P

11:43 justin_smith: that would be cool

11:43 TimMc: (Not that I know it would definitely make a difference.)

11:44 xcthulhu: TimMc: Well, I was wondering because I have some parsing code and I want to use a gensym for an EOF symbol... in this case, dereferencing is the right thing to do, rather than inlining

11:44 justin_smith: xcthulhu: then you probably wouldn't want to use :const anyway

11:45 xcthulhu: Yeah, that's why I came in here and asked :D

11:45 Also, which is better: (gensym) or (Object.) ?

11:45 justin_smith: thanks for asking, it's cool when I can learn something from someone else's question

11:46 do you primarily care about a unique identity, or a binding that needs a unique symbol?

11:47 xcthulhu: Unique identity - clojure already has heigenic macros so it's hard for me to find a use-case for (gensym)

11:48 TimMc: xcthulhu: gensyms are a part of hygienic macros

11:48 That's what foo# does.

11:48 &`foo#

11:48 lazybot: ⇒ foo__38506__auto__

11:48 justin_smith: xcthulhu: you probably want Object.

11:48 xcthulhu: TimMc: Right. But explicitly writing (gensym) seems like a rare event

11:49 TimMc: It happens from time to time. I've used it maybe a couple times a year.

11:49 Bronsa: xcthulhu: (let [x (gensym)] `(~x ~@(map (fn [a] `(~x ..)) something)))

11:51 TimMc: Specifically, it useful when you run up against the limits of syntax-quote.

11:51 xcthulhu: I'm already there, actually.

11:53 My colleague wants to write the following, which I don't think is possible in clojure: (escape {"json": "is", "unnatural" : "in clojure" } ) => "{\"json\": \"is\", \"unnatural\" : \"in clojure\" }"

11:54 I think I could do something like that with this: https://github.com/klutometis/reader-macros

11:54 hyPiRion: it's not possible.

11:55 xcthulhu: Which is how I'd do it in Common Lisp

11:56 But I bet there's a "_ Considered Harmful" paper I'd be violating

11:56 justin_smith: you could do it if the input was a string, but the embedded colons could lead to a map with an uneven number of symbols, for example

11:56 if it were not a string

11:56 xcthulhu: justin_smith: Yeah, that's why I'd do it with a read-macro

11:56 hyPiRion: It would just break everything.

11:56 justin_smith: also, I don't think : is valid input

11:57 jtoy: is it possible to write an interator for a db that can be used with inject like so: http://pastie.org/8505426

11:57 that doesnt seem to work for me

11:57 Bronsa: there's no way it would work even with read-macros capabilities. : dispatches to read-keyword, you'd need to redefine that

11:57 TimMc: xcthulhu: You kind of want heredocs, which Clojure also doesn't have. Sort of.

11:57 justin_smith: hyPiRion: is that because you couldn't ensure your read macro ran before the built in {} read macro?

11:57 or whatever you call the thing that parses {}

11:58 TimMc: xcthulhu: I usually just write {:maps "are", :natural "in clojure"} and then tell Cheshire to convert it (taking keyword keys to string keys)

11:59 hyPiRion: justin_smith: even if you could, you may env up breaking all clojure libraries you use

11:59 justin_smith: so something as finely grained as "parse this block if we can tell it is a json literal, otherwise hand down to the next parser" is not possible?

12:02 hyPiRion: Well, you could probably do some reflection on the reader, but I wouldn't bother go that far.

12:03 xcthulhu: hyPiRion: The common lisp way is to hijack the reader and parse the character stream yourself

12:03 justin_smith: also, something like #json-literal [json map] -> "{\"json\" : \"map\"}" would work - but : would probably fuck it up

12:04 ,:

12:04 clojurebot: #<RuntimeException java.lang.RuntimeException: Invalid token: :>

12:05 justin_smith: \: could be a workaround

12:05 ,\:

12:05 clojurebot: \:

12:05 hyPiRion: xcthulhu: sure, been there, done that. Its usefullness in Clojure is debatable, though.

12:06 TimMc: xcthulhu: Anyway, what's wrong with just serializing a Clojure data structure to JSON?

12:06 justin_smith: they probably want the convenience of seeing the real json form embedded in the clojure code

12:06 TimMc: {"key" ["val" "ues"], "numbers whee" 45}

12:06 "Convenience", you can't even edit it structurally.

12:07 justin_smith: true!

12:07 TimMc: or template it

12:07 xcthulhu: TimMc: My crazy colleague wanted to do it the hard way, and as a n00b I'm honor bound to find a way to make his twisted dreams come true

12:08 justin_smith: if you want that kind of pervasive dsl paradigm, rebol is great for that

12:08 but it does not have the performance you would get from clojure, and it is closed source

12:08 and the "pro" version costs money

12:09 ie. in rebol an email address literal is somebody@example.com

12:09 and it just works

12:09 xcthulhu: justin_smith: Well my company pays us to program in clojure...

12:09 justin_smith: just saying, that is not what clojure is designed for as an approach, but there are languages that are designed that way

12:13 SegFaultAX: xcthulhu: Where do you work?

12:13 xcthulhu: SegFaultAX: OpinionLab in Chicago

12:14 The company isn't very interesting, but I wanted a functional job and someone managed to convince management to go with Clojure

12:14 SegFaultAX: I think you told me that once before actually. :)

12:14 I recognize the site.

12:14 (Or perhaps one of your colleagues that also hang out in #clojure)

12:14 xcthulhu: Totally possible

12:15 guns: xcthulhu: I had a recruiter approach me about OpinionLab; are you enjoying yourself?

12:24 xenon75: Hello

12:25 gdeer81: xcthulhu, is that the same opinionlab that you install on your website to get feedback about it?

12:27 xenon75: Are ClojureScript questions appropriate in this channel or should I go to #clojurescript (which seems quite dead) ?

12:27 gdeer81: xenon75, just fire away

12:27 xcthulhu: gdeer81: Yeah

12:27 It's that opinionlab

12:29 gdeer81: xcthulhu, ha our business users want to put opinionlab on our current site. good to know we're using a company that uses Clojure =)

12:29 xenon75: ok, well I am learning Clojurescript by porting a javascript app I did some time ago. It is a little 3D demo which shows some effects - I basically update "scene data" 60 times per second doing some nice visuals while music is playing.

12:30 now I was wondering that if I use persistent data structures and I "mutate" them 60 times per second

12:30 I might choke the JS interpreter

12:30 so maybe I should go with mutable stuff in clojurescript via (set!) or change the application I am learning with :)

12:31 is it the case or the clojurescript runtime can cope with that?

12:33 gdeer81: xenon75, start with persistent data structures, if it chokes the interpreter, then go with mutable data structures with a facade of immutability, if that doesn't work...go dirty

12:35 xenon75: gdeer81: that was my intention as well - just wanted to know if my experiment was doomed from the start :)

12:35 gdeer81: btw, what do you mean by "mutable data structure with a facade of immutability" ?

12:36 gdeer81: xenon75, lol yeah sorry

12:52 justin_smith: I think if changes happen anywhere near 60 times a second, you will need to stick with directly using the mutible structure

12:52 though other things that are less frequently updated can stay immutible, most likely

12:56 sritchie: hey guys - has anyone seen this error on the new cljs version?

12:56 Assert failed: :output-dir "/Users/sritchie/code/clojure/paddleguru/target/cljsbuild-compiler-3" must specify a directory in :output-to's parent "/Users/sritchie/code/clojure/paddleguru/resources/public/cljs" if optimization setting applied

12:57 andyf: Bronsa: Thanks for the quick tools.analyzer.jvm fix

12:57 sritchie: this happens with a custom :output-to, just as in the lein-cljsbuild example

12:58 Bronsa: andyf: np, if you encounter any more misbehavings please assume they are bug and report them

12:59 andyf: Bronsa: So reading your reply to me on the dev mailing list, you would recommend I copy-and-paste t.a.j's analyze function, and remove some passes that do checking that currently breaks?

12:59 Bronsa: I think you mentioned 'validate' as one pass that might be useful to remove.

13:01 Bronsa: andyf: depending on what you need to do, that may be a solution

13:01 (to avoid evaluating every form, that is)

13:02 the tradeoff is that you have no way of knowing if SomeClass/nonExistentField is valid or not

13:05 sritchie: dnolen: any advice on how to handle this error about output-dir?

13:05 or is that a cljsbuild thing

13:07 Bronsa: andyf: I'll take a look to see if I can help porting eastwood to tools.analyzer later

13:11 andyf: btw looks like ambrose's analyze does indeed eval the analyed expressions under the hood

13:19 andyf: Bronsa: Sorry, was on a phone call there. Yes, ambrose's jvm.tools.analyzer's analyze does eval.

13:19 danneu: How can you efficiently calculate `x^y modulo z` in one expression?

13:20 andyf: Bronsa: I already have eastwood partially updated to use tools.analyzer.jvm now. I'm trying it out on various contrib libraries to see which ones it works on, and which it fails on. Right now still lots of failures. I will re-run those tests with validate step taken out and see what changes.

13:20 Bronsa: andyf: if your goal is simply detecting duplicate def's though, there is no need for eval'ing

13:21 andyf: Bronsa: That was my thinking, too. Do as many checks that Eastwood does now, plus detecting duplicate def's, without doing eval, which probably means not doing validate, either.

13:22 Bronsa: Would you recommend walking the analyzed expression trees for :def ops, so that it handles things like (let (defn foo ...)) that a few code bases use?

13:27 danneu: to answer my own question: BigInteger#modPow

13:27 andyf: danneu: You beat me to it by a few seconds ... :)

13:28 Bronsa: andyf: depending on what you want to do you have different options -- if you want to support everything eastwood supports ATM, you'll need to use the bundled c.t.a.j/analyze or something really similar to that and eval every form, if you only want to do some static analysis e.g check for redefinition, unused functions etc, you can avoid evaluating everything and could probably use a custom analyze function with none of th

13:28 passes

13:28 andyf: yeah, you could use c.t.a.passes/walk to do that easly

13:28 andyf: danneu: I'd recommend converting the answer back using (bigint result) before using it elsewhere in your code. Might want to wrap that up in a small Clojure function to do the BigInt <-> BigInteger conversions.

13:28 danneu: andyf: thanks. i only become a google-fu wizard once i've asked a question in irc

13:29 andyf: yeah, i've been extending https://github.com/clojure/math.numeric-tower this way

13:30 andyf: danneu: Reason: BigInteger's do not obey hash consistency in Clojure, by choice. See http://dev.clojure.org/jira/browse/CLJ-1036

13:31 Bronsa: Thanks. I'll experiment for a while and let you know if I hit any road blocks.

13:39 bellkev: Hey I'm super new to Clojure, but I have a hopefully easy question. Does anybody know if deftype and defrecord are both equally likely to stick around, since the docs say both are "alpha"? I have a situation where I pretty much just need a struct-like map, but with a well-known set of fields. I definitely like the look defrecord, because it gives the map interface. Is that a popular way to go? Is deftype likely to be deprecated soon? Because

13:39 seems similar to defrecord but with less features?

13:43 Bronsa: bellkev: they're not in alpha anymore as of clojure-1.6.0-alpha3

13:44 bellkev: Bronsa: Haha, nice, not in alpha as of the new alpha ;) Thanks!

13:45 osnr_: is there a shortcut to recur with the same values for the bindings? like, (loop [x 1 y 2 z 3] (recur x y z)) a shortcut for (recur x y z)

13:47 justin_smith: osnr_: you could put all the args in a destructured vector: (loop [[x y z :as in] [1 2 3]] ... (recur in))

13:47 this would also requiring changing other calls to recur to put [] around the args

13:48 and you lose arg count checking

13:49 otherwise the code could stay the same

13:49 osnr_: justin_smith: would also make the initial binding harder to read, but thanks for the suggestion.. hmm. might end up doing that. would it be idiomatic to use a macro for this?

13:50 justin_smith: ,(loop [[x y z :as in] [1 2 3]] (if (< (rand) 0.5) :done (do (println :tick) (recur in))))

13:50 clojurebot: :tick\n:tick\n:tick\n:done

13:50 justin_smith: ,(loop [[x y z :as in] [1 2 3]] (if (< (rand) 0.5) :done (do (println :tick) (recur in))))

13:50 clojurebot: :tick\n:tick\n:tick\n:tick\n:tick\n:done

13:51 justin_smith: ,(loop [[x y z :as in] [1 2 3]] (if (< (rand) 0.5) :done (do (println :tick) (recur in))))

13:51 clojurebot: :tick\n:tick\n:tick\n:tick\n:done

13:51 justin_smith: sorry

13:51 that is a very small thing to be making a macro for

13:52 and I think the more you use destructuring, the more readable that form is

13:54 also if you put the binding form directly under the destructuring form rather than on the same line, seeing what lines up with what can be pretty straightforward

13:55 osnr_: OK, cool -- I will go with some form of the destructuring then, thanks!

14:08 bellkev: I answered my own question from earlier about why there are both deftype and defrecord constructs by reading this: http://clojure.org/datatypes. However, as I start to play with records, I wonder: what do most people do for data validation? For example, if I create records with (map->RecordName {...}), it is okay if fields are missing or if there are extra keys not defined as fields on the record. Do people tend to perform validations separat

14:08 like this: http://blog.8thlight.com/myles-megyesi/2012/10/16/data-validation-in-clojure.html ?

14:11 justin_smith: bellkev: gigo is a really common design choice in clojure and in clojure libs

14:11 my choice would be write a function that wraps map->RecordName with preconditions on the args

14:12 ,((fn [x] {:pre [(number? x)]} (inc x)) 1)

14:12 clojurebot: 2

14:12 justin_smith: ,((fn [x] {:pre [(number? x)]} (inc x)) \a)

14:12 clojurebot: #<AssertionError java.lang.AssertionError: Assert failed: (number? x)>

14:13 bellkev: Okay, fair enough. I will be wrapping it anyway for other things, so that will be fine

14:14 justin_smith: or, if you prefer to return nil rather than throwing an error:

14:14 ,((fn [x] (and (number? x) (< x 10) (inc x))) 1)

14:14 clojurebot: 2

14:15 justin_smith: thanks to and, it will return nil if anything before the final term returns nil

14:15 bellkev: Maybe it's less necessary for me to even use the defrecord versus just a hashmap in the first place then, because it's doesn't need to do any protocol-ish stuff. Is it typical in clojure to use defrecords for field groupings only just to be explicit about what the record is, versus just using an anonymous map?

14:16 justin_smith: usually defrecord is for performance

14:16 or protocol stuff

14:16 but then, protocols are often about performance too

14:16 it often works to use maps, then switch to a record if you find you need it eventually

14:17 bellkev: okay, that makes sense. Thanks!

14:17 justin_smith: records are not really used to ensure program correctness (since by design they really don't offer much for that), though I guess typed clojure could change that

14:26 gfredericks: does typed clojure have newtype? is there any reason it couldn't?

14:31 hiredman: gfredericks: it has some kind of type alias thing

14:31 def-alias

14:33 gfredericks: that's a bit different from newtype I assume

14:33 (newtype Name String) would mean I can't substitute a string where I expect a name

14:35 that would raise the question of how you'd obtain a Name in the first place I guess

14:38 justin_smith: a constructor that accepts a string of course

14:38 sounds like a monad

14:41 TimMc: When all you've got is a monad, everything looks like a burrito.

14:41 justin_smith: indeed

14:41 * justin_smith plans to answer every question from now on with "you can do that with a turing machine"

14:42 TimMc: justin_smith: How can I solve the halting problem?

14:43 Bronsa: TimMc: I lol'd

14:43 tcrayford: justin_smith: it's often used as a typelevel proof of something

14:44 e.g. if you have an invariant that all EncryptedPasswords are actually strings generated by bcrypt, then you hide the normal constructor, and have just the bcrypt encryption function be String -> EncryptedPassword, then you have a good way of ensuring that you won't accidentally check passwords against non bcrypted password strings

14:45 justin_smith: tcrayford: right

14:45 tcrayford: but newtypes in haskell are compile time only (99% of the time), so the code compiles/evals exactly the same as it would with String

14:46 they interact wonderfully with typeclasses (which are almost the same as procotols), as you can specialize say Eq for your custom strings without paying any performance penalty, which isn't true in many clojure lib designs that use protocols heavily

14:47 gfredericks: newtype CaseUnawareString = String

14:48 newtype EqualToItselfReversed = String

14:48 newtype EqualToEverythingElse = String

14:48 tcrayford: one of the things I love about newtyping EncryptedPassword is that you can make that thing not have a show instance, hide any way of getting it out, and suddenly you don't have to worry about accidentally logging passwords at all

14:49 gfredericks: clojurebot: haskell |means| you don't have to worry

14:49 clojurebot: In Ordnung

14:52 gfredericks: I just realized you can print a newline with (println)

14:52 tcrayford: :///

14:53 guns: (newline)

14:53 So people on windows don't yell

14:54 justin_smith: is println not guaranteed to generate a newline properly on windows?

14:54 guns: oh, I suppose so

14:59 dnolen: a sketch but here's a an idea I have for integrating mutable JS crap sanely w/o a perf hit and w/o paying for conversions clj->js js->clj conversions https://gist.github.com/swannodette/7631691

15:00 tldr; a transient that can't be made persistent that becomes unusable after an update operation

15:00 * gfredericks digests

15:01 gfredericks: dnolen: is this for a lib, or language feature?

15:02 dnolen: gfredericks: too half baked for language right now, but I plan on making it work for JS objects and we'll see what people think

15:02 gfredericks: if we can collectively make it less half baked maybe it's worth getting in - not sure yet

15:03 bbloom: seems like linear types

15:03 implemented dynamically

15:03 how do you deal with external modifications? ie if somebody gives you something that is already mutable

15:03 (i believe the answer is: you don't)

15:04 dnolen: bbloom: yeah not a problem I want to solve :) but this does address how annoying it is to work w/ JS APIs

15:04 bbloom: totally about the linear types bit

15:04 bbloom: seems like this will create a lot of gabage

15:05 dnolen: bbloom: see update!

15:05 gfredericks: so it only returns a new version if used = true?

15:06 I'm guessing at what check does

15:06 dnolen: gfredericks: no ops allowed if used

15:06 gfredericks: if you ever get a new value, the old one dies

15:07 * gfredericks must be missing the point

15:07 bbloom: yeah, i don't really understand how this helps either

15:07 dnolen: bbloom: no marshalling

15:07 bbloom: no aliasing in your own code

15:10 bbloom: so is the entire goal that i get an exception if i use something mutable after i've released it?

15:10 dnolen: gfredericks: bbloom: but it might not be worthwhile because you'd want it to work for nested values ... that seems tricky.

15:11 bbloom: yeah, i don't think this has any utility

15:11 i'd rather deal w/ mutable things in normal mutable ways, wrap them up in a little machine, and then talk to those machines w/ async :-P

15:13 dnolen: bbloom: heh, like I said half-baked. But I'm not sure about the general idea not having utility - survey showed a lot of people complaining about js->clj clj->js

15:14 bbloom: dnolen: yeah, but i don't think the problem is related to correctness, it's about convenience

15:14 dnolen: there are a couple things floating around out there - but few address the perf and good interaction on boths sides

15:14 bbloom: lots of js code use json or json-ish things for configuration, etc

15:14 people want js-obj to have {} syntax

15:14 that's basically it as far as i can tell

15:14 dnolen: bbloom: that's not my impression

15:14 bbloom: they want immutable maps

15:15 bbloom: what I'm suggesting here is having a mutable map and not being afraid to interact w/ it

15:15 bbloom: ok let's rewind

15:15 i'm going to look at the survey results again

15:16 do you have any particular comments you want to highlight? not your interpretation, source comments

15:16 dnolen: bbloom: yeah look at the individual responses on CLJS pain points

15:16 bbloom: but also the fact that cljs-> js->cljs even exists, and stuff like mr-hyde

15:16 anyways got a run for a bit - going to ponder the nested case

15:17 bbloom: mrhyde is insane

15:20 yeah, reading through these are confirming my suspicions

15:21 people want a way to call functions withArgs({like: "this"})

15:21 they want js data literals

15:22 i wouldn't be surprised if a #js reader literal & printing made 90% of the complaints go away

15:28 dnolen: another part of the problem is just that people need libraries & can't use jvm ones and wrapping sucks

15:28 particularly w/o feature expressions b/c it means if you write a date/time lib, for example, it's gonna be hard coded to JodaTime or moment.js or whatever

16:14 {[^-^]}: ,(reduce + (seq [1 2 3 4 5]))

16:14 clojurebot: 15

16:14 {[^-^]}: is there any performance penalty to seq'ing that vector?

16:14 justin_smith: that seq call is redundant

16:14 reduce does that already

16:14 {[^-^]}: it works around the subvec reduce problem

16:14 ,(reduce + (subvec [1 2 3 4 5] 1 4))

16:14 clojurebot: 9

16:15 {[^-^]}: um

16:15 justin_smith: the what problem?

16:15 {[^-^]}: ,(reduce + (subvec (into (vector-of :long) (range 1000)) 0 100))

16:15 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.core.Vec cannot be cast to clojure.lang.PersistentVector>

16:15 {[^-^]}: ,(reduce + (seq (subvec (into (vector-of :long) (range 1000)) 0 100)))

16:15 clojurebot: 4950

16:16 {[^-^]}: yesterday someone told me to use vec instead of seq, and obviously that's slow

16:16 ,(reduce + (vec (subvec (into (vector-of :long) (range 1000)) 0 100)))

16:16 clojurebot: 4950

16:17 justin_smith: so is the idea to get the subvec directly, rather than having to drop / take on the seq reduce would make?

16:18 {[^-^]}: I don't understand what you said

16:18 justin_smith: I guess I still don't understand why you would have to explicitly call seq on an arg to reduce

16:19 {[^-^]}: because you can't reduce over subvectors of primitive types

16:19 which is a bug

16:19 justin_smith: ahh, ok

16:19 not vector, but vector-of

16:19 {[^-^]}: yea

16:25 sveri: hi, i have two clojure projects, where project A depends on project B, how do you handle this usually during develop time and during build time? i read about the checkouts folder and that makes sense, at least at dev time, but during build time? gradle handles multi projects really well, is there something similar with leining?

16:26 justin_smith: sveri: I typically put each project on clojars

16:26 sveri: justin_smith: ok, and what about private projects?

16:26 justin_smith: sveri: if something cannot be open source, I don't make it depend on other non-open-source things

16:26 which is a limitation, true

16:26 sveri: well, both projects are private

16:26 justin_smith: there is the option of a private maven repo

16:27 or, if you only build on one machine, lein install

16:27 sveri: ah, i see, i have to setup a private maven repo, that sounds good

16:27 justin_smith: I have not really played with subprojects

16:27 magnars: sveri: we had this problem, and are in fact using gradle to handle the multi-project part of things, delegating to leining for each project. It's a hassle, tho. A private repo sounds better.

16:27 justin_smith: they may very well work nicely, I just have no experience with them

16:28 come to think of it, the only time I have heard gradle come up in the clojure world is multi-project stuff

16:28 sveri: so obv. thats where leiningen is missing something

16:28 justin_smith: yeah

16:30 sveri: does anyone of you use jenkins or bamboo?

16:30 magnars: we use teamcity for our multiproject gradle-leining frankenstein :)

16:31 sveri: any reason why you chose teamcity?

16:32 magnars: I wasn't involved in the decision. I know they tried one of the free ones first, but had some issues that teamcity resolved handily. Can't remember any details tho, unfortunately. Sorry about that.

16:32 sveri: yea, no problem, thank you :-)

16:37 BlueOrg: hello, i'm new to web development in Clojure. I want to parse the data entered into a form on a web page as a Clojure data structure. Can someone point me to specific examples that show how to parse form data into maps. I'm guessing Compojure can do that but i can't find specific examples.

16:40 magnars: BlueOrg: that's what http://clojuredocs.org/ring/ring.middleware.params/wrap-params is for :) see :form-params

16:41 coventry2: sveri, magnars: Got to go, but the problem you're describing sounds like what lein checkout dependencies are for https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#checkout-dependencies

16:43 magnars: coventry2: that's for development. The problem is building multiple private projects in the correct order for deployment.

16:45 justin_smith: sveri: we use jenkins

16:45 BlueOrg: compojure is actually pretty small, and just has to do with page routing. Ring is where most of the action is.

16:46 and the many ring middlewares

16:46 BlueOrg: justin_smith where can i learn more about them?

16:46 SegFaultAX: Check out Clojure Web Development for an in depth tutorial on building simple web applications in Clojure.

16:47 http://pragprog.com/book/dswdcloj/web-development-with-clojure

16:47 justin_smith: BlueOrg: the ones that come with ring are in ring.middleware.<etc> namespaces

16:58 gfredericks: how many folk go out of their way to line up the values in multi-line map literals?

16:58 dnolen: pretty cool to see CLJS close to CLJ on this - https://github.com/kovasb/combinator

16:58 justin_smith: my coworkers do it and it is annoying

16:58 they never stay lined up

16:59 gfredericks: justin_smith: I was thinking I would do it more if emacs knew how to do it

16:59 justin_smith: some kind of tabstop mode?

16:59 gfredericks: probably? I don't know a lot about emacs wrt this

17:00 justin_smith: also, one of the only things I miss about common lisp syntax is the auto-indent of let clauses would actually differentiate bindings from expressions that generate bindings

17:00 (on a related note)

17:01 Bronsa: gfredericks: https://github.com/gstamp/align-cljlet does it

17:01 gfredericks: Bronsa: oh man look at that

17:01 justin_smith: Bronsa: nice, answers both of our gripes

17:02 gfredericks: I am going to try this with much haste

17:02 Bronsa: I've beein using it all the time for tools.analyzer AST

17:02 gfredericks: elisp looks so alien to me

17:02 justin_smith: gfredericks: was clojure your first lisp?

17:03 gfredericks: justin_smith: yeah

17:03 justin_smith: yeah, clojure is the outlier actually - now I like (most of) its differences though, after having to get over my familiarity based kneejerks

17:05 arrdem: does core.async have support for message passing over sockets?

17:06 gfredericks: Bronsa: omg omg omg it worked

17:06 (inc Bronsa)

17:06 lazybot: ⇒ 13

17:06 gfredericks: man this is going to make me hate everybody else's code

17:06 Bronsa: hah

17:06 arrdem: gfredericks: what did I just M-x package-install?

17:07 gfredericks: arrdem: doesn't matter just use it

17:07 arrdem: TIL clojure is a drug...

17:08 justin_smith: man, can you hook me up? I've been settling for racket and need a hookup asap

17:10 arrdem: gfredericks: okay. yeah. this is pretty slick...

17:10 gfredericks: I just bound it to C-c C-a

17:12 I'm not looking forward to all the "align all the things" commits I have to make. why can't I just run gofmt

17:19 BlueOrg: any startup using luminus web framework in production? how was the experience?

17:41 justin_smith: BlueOrg: I work for a digital agency using Caribou (actually we wrote caribou), which is similar to Luminous in many ways. It works great in production for us so far.

17:42 but we aren't a startup

17:42 BlueOrg: justin_smith yeah. i looked into Caribou. i wish you guys could work on the documentation more and put out a few more sample apps. that would make it much more awesome. like a basic CRUD app.

17:43 i'm new to Web development in Clojure.

17:43 justin_smith: if you just create and run the default config, that creates a crud app

17:43 also, our documentation is really extensive, but if there are specific spots where it could use more, let us know

17:44 brehaut: BlueOrg: if you are new to web dev in clojure, start by understanding Ring, and then probably look at compojure (because its a great example of how ring works, even if you dont use it later)

17:45 BlueOrg: brehaut okay. thank you. :) i guess there's a section dedicated to it in the Clojure Programming book. i'll read it.

17:46 dnolen: less half-baked CLJS purgatory https://gist.github.com/swannodette/7631691

17:47 timings at the bottom interesting

17:47 handles the nested case now

17:47 you can update something inside but it will invalidate the parent

18:02 logic_prog: http://www.clojurescript.net/ <-- how does this clojurescript repl work? is it interperted in the client, or is there some server behind it?

18:03 gfredericks: logic_prog: it's cljs-in-cljs, so presumably all in the client

18:04 logic_prog: taht is badass

18:04 https://github.com/kanaka/clojurescript agrees with your analysis

18:13 dabd: I would like to implement a Tree abstract data type. Should I use protocols and deftype or is it overkill?

18:13 bitemyapp: dabd: overkill.

18:13 dabd: do a first pass with vectors.

18:13 dabd: why?

18:13 clojurebot: why is the ram gone is <reply>I blame UTF-16. http://www.tumblr.com/tagged/but-why-is-the-ram-gone

18:13 bitemyapp: dabd: [:parent [:child [:grandchild-one] [:grandchild-two]]]

18:13 dabd: it's simpler.

18:14 dabd: it's also what the tree based zipping libraries are based on.

18:14 dabd: also, you had your "why" when I said, "overkill"

18:14 justin_smith: protocols and deftype get messy in the repl too

18:14 bitemyapp: dabd: don't use protocols and deftype until you no longer need to ask questions in IRC. So long as you need to ask in here, you're going to get a no. At least from me.

18:15 gfredericks: o_O

18:16 dabd: lol

18:16 arrdem: dabd: the zen of Clojure is that for the most part you don't need to formalize your datastructures with types and protocols. Also protocols and deftypes get nasty in the repl and force restarting a lot :/

18:16 gfredericks: (inc arrdem)

18:16 lazybot: ⇒ 6

18:16 arrdem: dabd: there's nothing more workflow disruptive than a repl restart

18:16 bitemyapp: (inc arrdem)

18:16 lazybot: ⇒ 7


18:17 bitemyapp: arrdem: replus interruptus

18:17 egghead: hm, in core.async how do I wait for multiple go blocks to close?

18:17 something with alts! i'd imagine?

18:17 arrdem: $google replus interruptus

18:17 lazybot: [The TV Business Keeps Getting Stronger ! | blog maverick] http://blogmaverick.com/2012/01/14/the-tv-business-keeps-getting-stronger/

18:17 bitemyapp: egghead: send nil yo.

18:17 arrdem: lazybot: you have failed me for the last time, commander

18:17 bitemyapp: egghead: oh you want a "I died" event?

18:17 gfredericks: is anybody else getting SSL problems fetching from github?

18:17 justin_smith: egghead: (go (while ...) (this runs when the block closes))

18:18 egghead: bitemyapp: I have two channels that close when completed, I just want to wait until they are both done

18:18 bitemyapp: egghead: have them send "I died" signals to alternate channels using justin_smith's example.

18:18 egghead: when your "they-ded" vector has the count you want, proceed, until then, keep looking.

18:18 looping*

18:18 but it worked anyway.

18:19 justin_smith: also, the other channel could have (or channel-a-open channel-b-open) as its while condition

18:19 egghead: sounds reasonable, thanks

18:20 bitemyapp: if I sound reasonable, the world has gone truly mad.

18:20 dabd: what is wrong about using the tree deftype as shown here: https://code.google.com/p/clojure-contrib/source/browse/trunk/src/clojure/contrib/types/examples.clj?r=527

18:21 bitemyapp: dabd: it makes you an asshole and contrib is not an example of good code more often than not.

18:21 dabd: contrib is dead.

18:21 gfredericks: dabd: I think the answers you've already gotten still apply

18:21 bitemyapp: ~contrib

18:21 clojurebot: Monolithic clojure.contrib has been split up in favor of smaller, actually-maintained libs. Transition notes here: http://dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go

18:22 justin_smith: dabd: if you are not going to redefine anything, nothing. If you are still working on the code for the definition, you have to restart the repl frequently, because changing a type definition does not change pre-existing instances

18:22 bitemyapp: dabd: why do you ask people for advice and then argue with them?

18:23 dabd: if you're hell-bent on doing stupid shit, can you do that without wasting other peoples' time in the process?

18:23 arrdem: bitemyapp: because they're being caustic asshats themselves

18:23 bitemyapp: arrdem: I'm the only caustic asshat allowed.

18:23 dabd: lol

18:23 arrdem: I'll leave that to tech's leniency

18:23 * bitemyapp dances

18:24 gfredericks: as long as you sound self aware about it it's totally fine!

18:24 bitemyapp: gfredericks: it applies to companies too!

18:24 arrdem: 1d2

18:24 clojurebot: 1

18:24 gfredericks: dabd: some things you get for free with vectors but not deftype: equality, hashing, serialiation...

18:24 dabd: can only laugh about your rudeness. Not arguing with anyone. I am reading on deftype and protocols and I find it hard to learn from docs only.

18:24 arrdem: (inc bitemyapp)

18:24 lazybot: ⇒ 14

18:25 bitemyapp: arrdem: http://i.imgur.com/OpxSJBf.gif

18:25 dabd: obviously trees can be implemented with simple lists or vectors. I already know that.

18:25 bitemyapp: dabd: structural sharing, immutability.

18:25 gfredericks: well deftype does give you immutability by default

19:02 arrdem: anyone know of a good dead tree book on the JVM bytecode standard?

19:05 justin_smith: I don't know of any, but I found a listmania on the subject on amazon after googling

19:07 arrdem: I'm amazon harder then. a cursory search didn't turn up a clear victor volume.

19:08 *I'll

19:49 ambrosebs: gfredericks: newtype probably isn't possible with Typed Clojure. instead Typed Racket has refinement types that update a type to say it's passed a particular predicate. (Refinement Long clojure.core/even?)

19:49 need to copy that at some point

19:49 bbloom: gfredericks: oh yeah, i meant to comment on that earlier, but got distracted

19:49 newtype is basically (deftype Wrapper [whatever] ...)

19:50 where ... delegates all operations on this to whatever

19:50 then the haskell compiler removes the delegation statically :-)

19:50 so it wouldn't make sense to introduce newtype at the type checker level, you'd need a different aliasing mechanism

19:51 ambrosebs: bbloom: yea

19:51 well put

19:52 bbloom: gfredericks: refinement types better match my intuitive notion of types, rather than the tag==type notion

20:07 arrdem: clojurebot: ping

20:07 clojurebot: PONG!

20:11 coventry`: ,(let [recur (constantly nil)] (println recur) (loop [] (if 1 (recur)))) ; No locals shadowing special forms, I guess.

20:12 clojurebot: Execution Timed Out

20:16 bbloom: ,(let [recur 5] recur)

20:16 clojurebot: 5

20:16 bbloom: coventry`: it's only in call position

20:16 but yeah, it's a major wart of clojure that the specials are not namespaced

20:17 (doc special-symbol?)

20:17 clojurebot: "([s]); Returns true if s names a special form"

20:18 Bronsa: bbloom: except for import* :/

20:19 bbloom: weird.

20:33 justin_smith: is there a way to define a special form?

20:33 other than forking the core of the language

20:33 brehaut: not without hacking the compiler

20:33 justin_smith: that was my suspicion, cool

20:33 brehaut: (which you might be able to do at run time but shouldnt)

20:34 bbloom: justin_smith: dare i ask: why?

20:34 justin_smith: bbloom: curiosity

20:34 not wanting to make one, but to understand their status

20:34 bbloom: justin_smith: good answer :-P

21:02 gfredericks: bbloom: interesting; I might not have an intuitive notion of types :)

21:04 bbloom: gfredericks: nah, my intuition just differs from normal sane people 99% of the time

21:04 gfredericks: bbloom: you must be a fan of structural typing?

21:05 I feel like this approach is better at describing whether the program will crash, while haskell/tagging is better at describing what the programmer is imagining that things are

21:05 bbloom: gfredericks: in addition to (where appropriate), not instead of nominal typing

21:07 gfredericks: nominal typing must be a thing I don't know of

21:07 if it is neither structural nor tagging

21:07 bbloom: gfredericks: http://en.wikipedia.org/wiki/Nominative_type_system

21:07 dsrx: nominal typing just means "do the names of the types on their declarations match"

21:07 bbloom: == tags

21:08 dsrx: any usage i've seen (i am a noob) of 'tagging' in type systems refers to the notion of objects carrying type information at runtime

21:09 gfredericks: oh the nominative != nominal screwed up my googling

21:09 these terms must be deemed equivalent via structural typing of english

21:09 dsrx: lol

21:09 bbloom: dsrx: no, you're understanding correctly. "tagged" for "tagless" generally refers to the execution strategy

21:10 * gfredericks hrms

21:11 bbloom: dsrx: i just don't draw as big a distinction has the PL community does b/c i'm firmly in the optional typing camp. i view tagless as an optimization (one which complects values with the context in which they are accessed)

21:13 $define nominative

21:13 doesn't lazy or clojure bot do that?

21:13 arrdem: bbloom: there's $google..

21:13 bbloom: $google define: nominative

21:13 lazybot: [Nominative case - Wikipedia, the free encyclopedia] http://en.wikipedia.org/wiki/Nominative_case

21:13 bbloom: boo

21:13 adj: relating to or denoting a case of nouns, pronouns, and adjectives (as in Latin and other inflected languages) used for the subject of a verb.

21:14 nominal: (adj) existing in name only.

21:14 *shrug* i guess thye are different

21:14 my bad.

21:27 jcromartie: CIDER makes me lose my cookies

21:27 justin_smith: your cookies?

21:28 jcromartie: Specifically, C-c C-k in a Compojure app (with the server defonce'd) causes my in-memory session store to be lost

21:28 I just wanted to make a vomit joke.

21:28 justin_smith: hah

21:29 https://github.com/tovbinm/emacs-24-mac/blob/master/etc/COOKIES best result from the google search

21:29 the best thing about installing emacs from source is probably all the weird shit they just pack into the source package just because

21:32 TimMc: $whatis nominative

21:32 lazybot: nominative does not exist in my database.

21:33 jcromartie: I guess it's because each time I load the file the top-level handler gets a new in-memory session store from compojure.handler/site

21:34 justin_smith: I wonder if there is a way to be sure changes to the handler are loaded, without forcing creation of a virgin session store

21:35 http://c2.com/cgi/wiki?NominativeAndStructuralTyping this is a good take on nominative vs. structural typing

21:36 {[^-^]}: why is clojure much faster than other dynamic languages like ruby and python even though they are imperative?

21:37 justin_smith: because they are too mutable, for starters

21:37 there are certain optimizations that do not play nicely with mutation

21:38 {[^-^]}: even though haskell does lots of optimizations based on purity, it's still not faster than C

21:38 justin_smith: too much of the language depends on state, and preserving state semantics while speeding up code is hard

21:38 c has the advantage of low cache churn

21:38 jcromartie: justin_smith: compiling to JVM bytecode goes a long way, too

21:38 justin_smith: but ruby and python are just as shitty about cache usage as the jvm is, so they pay twice

21:39 once for being imperative, and then again for type tags and heavy heap usage (non-locality of data)

21:39 actually the jvm is probably smarter about heap usage than their compilers are

21:40 because of how python and ruby objects are defined, you cannot use them without dereferencing their contained properties at each step

21:40 because there are no promises or limitations about when a mutation in an object could occur

21:41 I guess that java must be smarter about declaring things final? that part I am less sure of.

21:41 jcromartie: ,(-> 123 #'str)

21:41 clojurebot: #<CompilerException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.Symbol, compiling:(NO_SOURCE_PATH:0:0)>

21:41 jcromartie: ,(-> 123 (#'str))

21:41 clojurebot: "123"

21:41 jcromartie: I know why, but it's weird

21:42 ,(-> 123 ((var str)))

21:42 clojurebot: "123"

21:43 justin_smith: another weird one:

21:43 ,(-> '{a 0} 'a)

21:43 clojurebot: (quote {a 0})

21:43 justin_smith: ,('a '{a 0})

21:43 clojurebot: 0

21:45 justin_smith: another factor is that python and ruby devs have put little priority on performance in their language design. Both the jvm and clojure are pretty aggressively optimized.

21:45 and some optimizations aren't just things you can tack on post-facto - they need to be factors in the base level design of the language

21:46 that's the caveat to the whole "premature optimization" thing - there is such a thing as preemptive deoptimization through bad design

21:57 jcromartie: simple solution: (defonce session-store (ring.middleware.session.memory/memory-store))

21:58 then (handler/site app {:session {:store session-store}})

22:07 {[^-^]}: justin_smith: what about jruby and jython?

22:08 just bad deoptimization?

22:09 jcromartie: {[^-^]}: I don't think JRuby and Jython get the same JIT or AOT compilation treatment that Clojure do

22:09 hiredman: {[^-^]}: it is an uphill battle for them, I haven't heard anything performance wise for jython, but jruby has respectible performance due to heroic efforts

22:10 jcromartie: JRuby is worse than 1.9 as far as I know

22:10 {[^-^]}: slightly

22:10 ruby 1.8 was much slower than jruby

22:11 I'm starting to think clojure is the fastest dynamic language out there

22:12 jcromartie: with enough macros, it can be insanely fast

22:15 hiredman: http://clojure-log.n01se.net/date/2010-03-23.html#01:55

22:20 justin_smith: {[^-^]}: common lisps beat it still

22:21 but only the ones that target a particular hardware, I think

22:28 paomian: how to create 1000 agent by a function

22:31 justin_smith: ,(dotimes [i 1000] (agent i))

22:31 clojurebot: nil

22:32 justin_smith: you probably actually want to hold onto the values though, maybe a loop or a map + doall

22:35 amalloy: (repeatedly 1000 agent)

22:35 paomian: justin_smith: it maybe do not word

22:35 justin_smith: it maybe do not work

22:35 amalloy: although why you would want a thousand agents is beyond me. that almost can't help but be crazy

22:35 oh, i guess i forgot to give the agent an initial value (repeatedly 1000 #(agent 0)), or (map agent (range 1000))

22:35 hiredman: amalloy: agent needs an argument

22:36 #(agent nil) or something

22:36 amalloy: hiredman: already fixed it

22:37 hiredman: oh, so you did

22:57 coventry: There's 1000 agents in the example at the bottom of http://clojure.org/agents

23:11 justin_smith: hah, so there is

Logging service provided by n01se.net