#clojure log - Apr 24 2013

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

0:01 pppaul: walking is awesome

0:03 i have a walk that turns everything it touches into a set

0:03 :)

0:03 i use walks for datomic stuff too

1:30 beaky: hello

1:32 how do I learn the clojure language?

1:32 callen: beaky: hello

1:32 beaky: buy a book

1:32 beaky: I recommend Cemerick's

1:32 beaky: ah

1:32 callen: beaky: SegFaultAX: something

1:32 beaky: http://www.clojurebook.com/

1:42 tdignan: callen: i bought a book

1:43 but I don't know clojure

1:43 what do I do next?

1:43 seriously, I bought the book. idled in the irc for a month, but not a lick of clojure.

1:43 do I have to actually read the book as well?

1:43 tbh, it intimidates me a lot.

1:44 its so unlike anything else i've done.

1:44 Raynes: Well, you're never going to want to lick the Clojure.

1:45 tdignan: That is a quite possible outcome.

1:45 Oddman: tdignan, that's functional programming for you

1:45 :P

1:47 beaky: clojure looks like scheme

1:47 callen: Clojure is relatively easy, as far as functional languages go.

1:47 It's not the "pull brain out of you through your asshole" experience that Haskell represents.

1:48 tdignan: oh, yeah. i looked at haskell once years ago.

1:48 callen: looking doesn't really do anything

1:48 which might explain why you haven't learned Clojure yet either.

1:49 tdignan: I haven't learned something just for the sake of learning it for a long time.

1:49 usually i just learn the things I need to know to build things.

1:52 I suppose I'm not the only one to give up here.

1:52 callen: tdignan: why are you here?

1:53 tdignan: callen: um, I thought idling here and watching people talk about clojure would help to stoke my interest more

1:53 I've been on autojoin for a month

1:58 beaky: so the bird book is the one to go for for beginners?

1:58 Pupnik-: ive been working with that one

1:58 i think it is good

2:00 tdignan: looks like there is also a free webcast by the author on may 1st

2:00 ...2012

2:00 nevermind

2:01 beaky: what are the challenges to learning clojure?

2:06 tdignan: beaky: i can tell you why I haven't learned it yet. it's unlike anything else I know, and I don't actually need to learn it.

2:07 i'm sure your challenges will be unique to your own mind.

2:07 beaky: ah

2:08 I know c++

2:08 so I am probably going to have a tough time :D

2:08 since clojure is so different from those braces languages

2:10 but I want to use it to build a data processing app

2:11 Raynes: Every single app ever is a data processing app.

2:11 beaky: heh

2:11 apps are just sequences of bits that flip other sequences of bits

2:13 clojure doesn't seem particularly object-oriented

2:13 tdignan: apps are programs that flip tons of redundant sequences of bits so the programmer can actually get done in a reasonable amount of time

2:13 nope. it's a functional language.

2:14 beaky: functional? like C?

2:14 tdignan: C is procedural

2:14 beaky: ah

2:14 tdignan: the main difference has to do with keeping state. a purely functional program doesn't have it.

2:15 beaky: so a language like clojure does away with flipping bits

2:15 tdignan: the bits do flip. the code itself is data.

2:15 beaky: ah

2:16 tdignan: so a clojure program, is actually data, that gets read by a parser, which then executes the code... which itself is actually flat text, data :)

2:16 Chousuke: a purely functional program does have state. it's just explicit and individual states are generally immutable values

2:17 Haskell takes value-oriented programming to an extreme. even I/O is pure in haskell :P

2:17 beaky: ah

2:17 so a functional programming language just views state as data/values, and functions are just maps between values?

2:18 (like mathematical functions)

2:18 sparkjoy: That's a good way to think of it

2:18 Chousuke: that's maybe oversimplifying a bit, but yes

2:19 when you work in a truly "pure" language you need some creativity to be able to do certain things that are "easy" in an impure language (I/O is the usual example)

2:20 beaky: is IO pure in clojure like haskell?

2:20 Chousuke: nah, clojure is not a purely functional language

2:20 beaky: ah, so clojure is more practical ^^

2:20 sparkjoy: very much so

2:21 Chousuke: it's not more practical for that reason

2:21 it may be more practical because of JVM interop, but not because it's impure

2:21 callen: tdignan: code being data has nothing to do with being functional, that's homoiconicity.

2:21 Raynes: It's certainly more practical for people without the patience necessary to learn Haskell well enough to use it properly.

2:22 callen: Raynes: I don't think the purity is the confusing part with Haskell.

2:22 Raynes: callen: Wasn't saying it was.

2:22 Chousuke: the way haskell does IO is instead of "functions" that just do it, IO actions are represented as values that don't actually do anything until the *runtime* "interprets" them

2:22 callen: fair enough.

2:23 Chousuke: so you can store those values in data structures and copy them around, since without the runtime interpretation they don't actually have side-effects

2:24 beaky: so clojure is practical because it runs on the jvm and has seamless java interop and lisp metaprogramming facilities?

2:24 Chousuke: Clojure is practical if you can use it to solve a problem you have

2:24 beaky: ah

2:24 Chousuke: if you can't, it's not practical, in your case.

2:25 "practical" is very relative

2:25 Some people would consider Agda to be practical because they need to write formally verifiable software :P

2:25 beaky: right

2:26 I guess sometimes the functional style is very practical

2:26 Chousuke: it has many benefits

2:26 the main one, to me, is having fewer things interacting

2:26 so fewer things to worry about

2:27 when working with mutable data, in theory anything could interact with anything else at any point during execution, so you have no guarantees, and have to code in a way that minimizes the likelihood of such interactions occurring when not intended

2:28 if you work with immutable data, you have a guarantee that nothing will affect it short of hardware failure

2:28 matko: mutability is adventurous, living on the edge

2:29 there's actually no such guarantees though, are there? Reflection lets you 'break in' at any time if you wish

2:29 Chousuke: well, that's true. but such violations would be easy to spot

2:30 you can't do something like that by mistake

2:30 beaky: in rich hickey's talk about simplifying programs he did mention that immutable data simplifies things a ton; does clojure give lots of help in having immutable data? (C++ isn't really helping much in that area :( )

2:31 Chousuke: All of clojure's basic data structures are immutable

2:31 sparkjoy: immutability is the default in clojure

2:31 Chousuke: there's also a system for safely handling shared state, with well-defined concurrency semantics

2:32 sparkjoy: immutable + persistent (e.g. efficient versioning) data structures are really handy and idiomatic

2:33 we've been doing a lot of functional style work in an OO language, with somewhat persistent data structures, but it's not idiomatic and sometimes it can be painful

2:33 Chousuke: personally I find it difficult to work with mutable data nowadays

2:33 it's frustrating to have to worry about making mistakes.

2:33 sparkjoy: you find yourself fighting the language a lot - clojure makes these things much easier

2:35 right I can't tell you how many times as a library developer I've been handed a mutable collection and wondered, "should I clone this, or is it gonna be stable"

2:35 Chousuke: say if in python you have a list full of dictionaries full of lists and want to transform it somehow. it ends up being rather painful.

2:36 especially if you want to hold on to the non-transformed version

2:38 for example, what if one of the lists you're transforming is being shared with some other part of the code? you've just broken things.

2:38 it's not fun

2:39 murtaza52: (def primitive-conv {:I 1 :V 5 :X 10 :L 50 :C 100 :D 500 :M 1000})

2:39 (defn substraction-rule

2:39 [coll]

2:39 (map #(if (primitive-conv %1)

2:39 (if (< (primitive-conv %1) (primitive-conv %2))

2:39 (list '- %2 %1)

2:39 %1)

2:39 %1)

2:39 coll

2:39 (rest coll)))

2:39 (substraction-rule b) => (+ (- :L :X) :L :I)

2:39 expected => (+ (- :L :X) :I :I)

2:39 brainproxy: murtaza52: gist or refheap please

2:39 don't paste in chan

2:39 murtaza52: How do I correct the above fn ?

2:39 sorry let me do that

2:45 Can anyone help is getting this right - https://www.refheap.com/paste/13927

2:51 matko: so why is 'ideomatic' so important? Like, I had a debate the other day about (seq collection) vs (not (empty? collection)), where the other guy argued that (seq collection) was the more ideomatic way to check for non-emptyness, and the documentation seems to concur. Why is 'one way' so important?

2:52 antares_: matko: it's not more idiomatic. Also, it's a matter of taste. Use (not (empty? …)) if you prefer that.

2:52 matko: ok, so maybe I have the wrong definition of ideomatic in my head

2:52 I've really only ever heard this word in clojure context

2:52 Chousuke: actually using (seq foo) in a boolean context is a Clojure idiom

2:53 matko: I prefer (not empty? ..) cause it gives true rather than a value

2:53 err.. messed that up, but you get the idea

2:53 Chousuke: and (not (empty? foo)) is the same as (not (not (seq foo))

2:53 see the definition of empty?

2:53 matko: reading it now..

2:54 Chousuke: idiomatic just means something that is commonly accepted as being good style

2:55 and an idiom is an instance of that. eg. it's a clojure idiom to use map/filter instead of explicit loops

2:55 matko: so why does this matter? I mean, 'good style' of course matters, but is (seq foo) truly better style than (not (empty? foo))? I find that rather arbitrary

2:55 antares_: but it doesn't have to be the only style

2:55 Chousuke: matko: it is arbitrary, but that's what makes it an idiom

2:56 it's the accepted choice among many.

2:56 matko: >Heh, but what is the purpose of having an accepted choice?

2:56 Chousuke: well, lots of Clojure functions deal with sequences

2:57 rodnaph_: can anyone tell me how to emit a "debugger;" statement via clojurescript?

2:57 noidi: when there's a Right Way (tm) to do something, it's easy to see what the code is doing just by its shape

2:57 Chousuke: so (seq foo) fell out from that

2:57 and it's shorter. and faster :P

2:57 rodnaph_: gah! got it, just as i had given up (http://stackoverflow.com/questions/11181752/clojurescript-breakpoints)

2:58 noidi: in C there's an idiom for iterating over a collection: for (i = 0; i < size; i++). everyone who sees that knows immediately what's going on

2:58 of course you could use a while loop there, but that would not be idiomatic, and it would require more thinking from the reader to see what the loop's about

2:58 Chousuke: noidi: it's also an idiom in C to treat integers as booleans, for whatever reason

2:59 matko: Chousuke: ah, that makes sense

2:59 Chousuke: it makes no sense if you start thinking about it but no-one considers it weird at all in the context of C

2:59 matko: noidi: but I disagree with the idea that (seq foo) looks clearer than (not (empty? foo)) :p

3:00 noidi: seq vs. not empty? is not the best example of a clojure idiom, as it's one that many people disagree with

3:00 matko: at least I know a rationale behind it now

3:00 Chousuke: matko: it doesn't look clearer, but since you should know what seq does if you want to get anything done in Clojure, you learn that particular idiom quite quickly

3:00 and *then* it will look clearer

3:00 because it's shorter

3:00 noidi: a better example might be mapping over a map: (into {} (for [[k v]] m] [k (f v)]))

3:01 matko: well I come from a common lisp background, so I'm very familiar with using value and nil as true and false.. it just striked me as odd that clojure would do it when it also has boolean values

3:01 tieTYT: with gen-class, is it possible to pass the :methods in as a variable? I'm not sure how to do that because it needs a symbol in it (the name of the method without the prefix)

3:01 noidi: you see "into {}" and "for [[k v]] m]" quite often in clojure code

3:01 Chousuke: matko: booleans are there only for java interop

3:02 matko: haha really? I thought they were there from scheme

3:03 Chousuke: it's a wart, but a necessary one

3:03 it would be difficult to use Java libraries without access to booleans

3:04 matko: But clojure propositions return true or false as well

3:04 antares_: Chousuke: I doubt that

3:04 Chousuke: that just helps when calling them from Java

3:04 amalloy: Chousuke: i disagree that booleans are only for java interop

3:04 Chousuke: most clojure code doesn't really care.

3:05 amalloy: well, they are useful outside it too, but not required

3:06 amalloy: lists and numbers aren't required either: we could just work with church encodings in the lambda calculus. but they're easier and more sensible to work with, and so are booleans. why should (= 1 2) return the empty list instead of false?

3:06 Chousuke: nil is not the empty list

3:06 () is the empty list

3:07 matko: wait what.. nil is not '()?

3:07 Chousuke: I'm just saying that Clojure has no real need for explicit booleans because you could use nil and anything non-nil instead

3:07 Right. nil is not ()

3:07 matko: wow confused

3:08 Chousuke: in Clojure nil means "nothing"

3:08 matko: it also evaluates as true it seems

3:08 in an if

3:08 Chousuke: yeah, because it's a value

3:08 beaky: does clojure have tail-call optimization?

3:08 sparkjoy: not automatically, beaky - need to use recur explicitly

3:08 matko: unfortunately it doesn't have tail-call optimization

3:09 Chousuke: the JVM doesn't guarantee tail-call elimination

3:09 people get this stuff confused really easily

3:09 there's a difference between doing tail-call elimination and *guaranteeing* it

3:10 the latter is an issue of language semantics. the former is just an optimization.

3:10 sparkjoy: good point

3:10 beaky: ah

3:11 too bad :(

3:11 matko: so, nil and false are false, everything else is true, and the seq trick works cause seq returns nil rather than the empty list when called on an empty collection

3:11 this feels.. hackish

3:11 xxxyxxyxx: oioiiiiiii9o99

3:11 madar chod

3:13 beaky: what is clojure's associative model for data?

3:13 is it like a map?

3:13 sparkjoy: maps and records

3:14 beaky: ah neat

3:14 sparkjoy: records give you associative via a class, higher perf, easy to move to once you've figured out your model with a map

3:15 Chousuke: matko: the way seq works is that if you have something in a collection, it will returns a seq representing the contents. if there is nothing, it returns nothing (nil)

3:15 beaky: records are like structs in C, or classes with no methods and all data fields public in java?

3:15 or ADTs like in haskell?

3:16 Chousuke: records are an optimization of maps

3:16 sparkjoy: public final fields on a gen'd java class

3:16 matko: Chousuke: I see that, but don't understand the reason for not returning an empty list instead, exept to return something that evaluates to false.. but in that case I don't get why empty list is not false in the first place.. eh, it doesn't matter much

3:17 Chousuke: matko: it's not false because there are other empty things

3:17 an empty list is distinct from an empty vector

3:17 katratxo: matko: only false and nil are "falsy"

3:17 Chousuke: and I think treating nil as an empty list is a mistake that CL made.

3:18 sparkjoy: oh interesting point about () and [] - never thought about it that way

3:18 matko: it made recursing over lists easy

3:18 (in common lisp)

3:19 Chousuke: I suppose seqs in clojure are sort of like CL lists in that regard

3:19 you can recurse until (seq whatever) returns nil

3:20 and because you're calling seq in the recursion, the function works the same for all seqable data structures

3:20 matko: yes, I like how clojure made vector and map as easy to use as lists

3:21 sparkjoy: one quick point about (seq foo) - if foo is a lazy seq, in my experiments this causes foo to materialize. Just tested it on an infinite seq and it materialized the first 32 items.

3:21 that surprised me the first time I saw it

3:21 Chousuke: sparkjoy: yeah it has to force one element to know if there are any

3:21 sparkjoy: makes me less confident that (seq foo) is faster than (not (empty? foo))

3:22 if you weren't going to materialize it I suppose

3:22 Chousuke: sparkjoy: it is faster because empty? is defined in terms of seq :P

3:22 sparkjoy: LOL nm then

3:22 that's funny

3:22 Chousuke: 32 elements getting realized is just an internal optimization (chunking)

3:22 sparkjoy: yea that's what I figured

3:23 Chousuke: in general, having sequences with side-effects is a bad idea

3:23 sparkjoy: yea, I threw a println in a map to test it out

3:23 was just curious

3:23 mthvedt: sequences with side-effects were a pretty fun paradigm for some computations

3:24 now, you have to be careful about chunks

3:25 Chousuke: laziness and side-effects don't mix very well with dynamic typing :P

3:27 mthvedt: chousuke: i can think of a billion procedural languages with dynamic typing

3:27 Chousuke: actually, any time side-effects are involved you just need to be careful, regardless of the language or its laziness.

3:28 mthvedt: sure, but lazy + effectful is already a bit of a problem. In Haskell's case, the type system at least helps a bit.

3:29 mthvedt: well one reason haskell needs that, though, is because it enforces laziness

3:29 Chousuke: fortunately laziness in Clojure is restricted to sequences so it's easier to control

3:29 mthvedt: clojure isn't a lazy language, it's an eager in-order language

3:29 but a lot of lazy paradigms are used

3:30 because they are useful and convenient

3:30 Chousuke: I don't mind Haskell's laziness though. There are many useful things you can do only because it is lazy.

3:31 beaky: haskell avoids success at all costs :D

3:31 mthvedt: idk, haskell reminds me of the guy who could be a successful manager but would rather be a senior engineer instead

3:32 where playing with neat ideas > practicality

3:32 Chousuke: it does make things harder for people trying to figure out how to make things efficient, but the haskell community is full of smart library writers solving that problem.

3:32 mthvedt: the thing is, those neat ideas turn out to be practical once you get them fleshed out

3:33 Functors and applicatives are something everyone uses. Monads too.

3:33 mthvedt: well, monads are like

3:34 you can do all these neat things with monads and monadic flow control, but that doesn't explain why you need them to write to stdout

3:34 Chousuke: mthvedt: You don't need monads to write to stdout

3:34 mthvedt: chousuke: really? hacker news threads have lied to me

3:34 Chousuke: mthvedt: the thing is, if you want to write to stdout, you have a monad

3:35 it's not that monad -> ability to write to stdout

3:35 it's that ability to write to stdout -> monad

3:36 mthvedt: i have to confess that's not very eludicating

3:36 Chousuke: mthvedt: I assume you already understand that haskell is pure? basically everything is an immutable, side-effect free value

3:37 representing side-effects in a system like this may seem difficult at first but it's really not

3:37 all you need is the ability to treat the "instructions" as values

3:37 and then the runtime will interpret those instructions

3:38 so when you say main = getLine in haskell, you're saying that the value of main is getLine

3:38 and when the program executes, it "sees" that the value of main is getLine, and does what it needs to do

3:38 beaky: how does clojure compare to haskell in expressiveness? I guess clojure wins in that ballpark thanks to dynamic typing and metaprogramming facilities

3:38 Chousuke: what monads accomplish is allow you to combine two values into one that represents both

3:39 beaky: or is haskell's magical type system surprisingly expressive?

3:39 Chousuke: so you can say main = getLine >>= putStrLn

3:40 which just says "the value of main is the combination of getLine followed putStrLn with the result of getLine"

3:40 followed by*

3:40 and that's it

3:40 mthvedt: yes, and that's what i'm getting at

3:41 it's dancing around an impedance mismatch, followed by bragging about how neat the dance was

3:41 Chousuke: mthvedt: there is no impedance mismatch

3:41 int main() { x = getLine(); putStrLn(x) } says the *exact* same thing

3:42 tcrayford: beaky: I've never had a problem with expressiveness in either language. Clojure has macros, haskell makes it super easy to write a dsl with free monads/data types.

3:42 beaky: ah

3:43 Chousuke: mthvedt: the cool thing in haskell is that it recognises that the operation that combines the two substeps also applies to a lot of other things.

3:43 for example, callbacks-oriented control flow can be represented as promises

3:44 and the operations to combine promises... form a monad

3:44 mthvedt: i know how monads work

3:44 if that wasn't clear before

3:47 Chousuke: at any rate, the point is that you don't need monads to do IO, callbacks, or short circuiting evaluation.

3:47 but since you do all of those things anyway

3:47 and all of them form monads

3:47 why would you not use monads?

3:49 Glenjamin: what's the advantage of doing (do a b) to represent (a >>= b) instead of having the language allow a; b ?

3:50 beaky: a >>= b is formally recognized by the type system

3:50 Glenjamin: or i guess, why do i need to know it's a monad

3:50 mthvedt: that's a good question to ask anyone who's ever done unsafeperformio

3:50 beaky: once you know that something forms a monad, you can do cool stuff that worked on other monads :D

3:51 clgv: Glenjamin: good question, e.g. I can use `for` and do not need to know that it is a monad in principle... ;)

3:51 Glenjamin: i'm ok at basic haskell, but i never really grokked monads - so never done anything more complex than homework assignments

3:51 the list monad being some form of nondeterministic search really confused me

3:52 mthvedt: the other thing is

3:52 Glenjamin: and then you get into arrows and functors, it often felt like abstraction for abstractions sake

3:52 mthvedt: should a language really have a high barrier to entry for doing io

3:53 noprompt: i think it largely depends on what the goals of the language are.

3:53 Glenjamin: just because everything i do is equivalent to a mathematical model doesn't mean i want to deal with the model most of the time

3:54 Chousuke: Glenjamin: the nondeterminism is actually not that hard to understand

3:54 Glenjamin: you can think of a nondeterministic function as one that retuns a list of all its possible outputs

3:54 mthvedt: in practice, a lot of people don't understand it

3:55 Glenjamin: i know, but *why* treating lists as monads make them deterministic was lost on me

3:55 it was like discovering prolog hidden in the standard sequence container

3:55 Chousuke: Glenjamin: then combining a nondeterministic function with another means running the other function with every output from the first one

3:55 and concatenating the result

3:56 and that operation of combining them is what gives you a monad (along with a return operation)

3:57 the benefit from treating things as monads generically is that you can write functions that work across all monads

3:57 and if you have syntactic support for one monad, you have syntactic support for all monads

3:59 imagine if in C++ you could just do foo (Foo* x) {return x.doSomething()} and if x is null you just get a null.

4:00 Glenjamin: i don't write in C++, but that seems like how all the high level languages without monads work in that scenario

4:00 oh, sorry misread

4:01 Chousuke: Glenjamin: the thing is, people are adding these things into languages as special cases

4:01 some languages have .? for null propagation

4:01 * noprompt imagines a world without C++

4:02 Glenjamin: mm, because you often don't want null to make it further through the computation and blow up when you need a value to do something useful

4:02 Chousuke: then there are those coffeescript extensions with await and whatnot for less insane node.js programming

4:02 whereas if you just had a neat syntax for >>=, you'd get all that for free.

4:02 noprompt: less insane node.js programming?

4:02 not sure if that's saying much. :)

4:02 Chousuke: noprompt: avoiding nested callbacks

4:03 noprompt: Chousuke: yeah, i know what you're refering too.

4:03 Glenjamin: meh, i like node.js

4:04 Chousuke: if you coded node in haskell you could just write do { x <- someAsyncOp; y <- anotherAsyncOp; return x+y}

4:04 Glenjamin: the module loading system and dependency management encourages really small, clean re-usable modules

4:05 again, i don't really see that as being leaps and bounds better than async.parallel([someAysncOp, anotherAsyncOp], callback)

4:05 noprompt: well, there is type safety. which *is* a good thing.

4:05 Chousuke: whereas in javascript that's like someasyncOp(function(x, err) {if (!err) anotherAsyncOp(x, function...{})})

4:05 which is a complete horror

4:05 Glenjamin: noprompt: like in clojure?

4:06 Chousuke: glenjamin: oh, I forgot to add a dependency of anotherAsyncOp to x

4:06 noprompt: javascript is just horrific in general. you have to be armed to the teeth with a body of knowledge before you can even consider writing serious code in the language.

4:07 Glenjamin: again, i don't really see that as being leaps and bounds better than async.waterfall([someAysncOp, anotherAsyncOp], callback)

4:07 Chousuke: Glenjamin: yeah, and that's a monad

4:07 Glenjamin: noprompt: i don't strongly disagree, but to do web work you have to know it pretty well

4:07 noprompt: it's probably the second or third worst language i've used (php being the first).

4:07 Glenjamin: Chousuke: right, but does knowing its a monad change anything?

4:07 Chousuke: Glenjamin: you're just using a non-generic implementation of the exact same thing

4:07 Glenjamin: yes, i agree

4:07 Chousuke: Glenjamin: and you don't get syntactic benefits

4:08 noprompt: Glenjamin: well yes if you write raw javascript.

4:08 Chousuke: do notation is better than what you wrote.

4:08 Glenjamin: but is it much better?

4:08 Chousuke: it is.

4:09 because it's based on something generic, and thus extends to things you can't even imagine yet.

4:09 like, say, the Tardis monad :P

4:09 (which is a combination of state and reverse state)

4:09 noprompt: Chousuke: you're making want to pick up haskell again. :)

4:10 *making me

4:10 Chousuke: it's unfortunate that Monads are called monads

4:10 Glenjamin: they should reall be Monoids!

4:11 Chousuke: if they were called "generic API for boilerplate" people might not be so scared

4:11 Glenjamin: what's that phrase now...

4:11 monads are just monoids in the category of endofunctors

4:11 Chousuke: yeah, heh

4:11 mthvedt: i only program in the lambda calculus on categories

4:11 everything is a category

4:11 * noprompt head explodes

4:12 Glenjamin: i'm not especially scared of them, it's just i'm unconvinced of the improvement - you still have to understand what the properties of the monad you're using are in order to compose them

4:12 Chousuke: Glenjamin: there are a lot of big words in that sentence but what is actually says is really simple :P

4:12 Glenjamin: sure, but you're doing that anyway when you're working with any kind of data

4:13 Glenjamin: yep, but more concrete abstractions designed for the particular problem can make the tasks you're likely to do easier

4:13 Chousuke: I've never seen an example of that

4:13 noprompt: Glenjamin: you know it's funny you mention that.

4:13 Glenjamin: and you could build them out of monads, or something less general - but when i'm using the specialised version it stops mattering

4:14 Chousuke: Glenjamin: I mean, you can do things with specialised versions and it's easy

4:14 but using the non-special versions is easy too

4:14 it's just two operators :|

4:14 and one of them is trivial

4:15 noprompt: personally, i think people tend to looking to apply general solutions or patterns when building software that they actually miss out on what they're actually trying to do.

4:15 Chousuke: it's like you'd rather have listSort() mapSort() vectorSort() all separate so that you know what you're sorting each time :P

4:16 noprompt: I don't think monads are like that

4:16 Glenjamin: thats why we have interfaces, or protocols / type classes

4:16 noprompt: Chousuke: i don't necissarily either.

4:16 Glenjamin: the monad stuff is at a level of abstraction I don't often need to deal with

4:17 Chousuke: Glenjamin: you're dealing with it all the time

4:17 Glenjamin: and yet I don't know I am!

4:17 which is my entire point

4:17 Chousuke: Glenjamin: if you knew, you'd stop repeating yourself :)

4:17 noprompt: i guess what i notice is that people learn about a X design pattern or X abstraction technique and try to make use of it when they really could have just solved their problem with a few lines of code.

4:18 Glenjamin: That's a monad, I can use the monadic operators / That's some repetition, I can abstract that away

4:18 ^^ whats the difference?

4:19 ejackson: noprompt: i'm not seeing that in myself. As I learn higher level concepts, they dissolve the lower level ones. But its taking a long time.

4:19 noprompt: iow i can sympathize with what Glenjamin is saying.

4:19 Chousuke: monads are just a generic operator for the boilerplate in the following: A -> (operation) -> (boilerplate) -> B

4:19 noprompt: ejackson: i wasn't refering to a large body of people, but some do approach software in this manner.

4:20 ejackson: fancy composition operators :)

4:20 Glenjamin: so is A -> (high-level-operator) -> B

4:20 Chousuke: Glenjamin: that doesn't work if the operator doesn't actually return B

4:20 noprompt: i worked with a guy a while back who was just so obsessed with "patterns" that it drove me to quit working with him.

4:20 ejackson: noprompt: oh, sorry, I thought you were making a general argument against higher level abstractions

4:20 noprompt: hehe, I know what you mean now :)

4:20 Chousuke: Glenjamin: it's just so obvious to me.

4:21 Glenjamin: if you have functions that can return null, you can just go foo(bar(something(A))) to get B

4:21 you have to do null checks after everything

4:21 which is just boilerplate that you can't avoid

4:21 Glenjamin: (cond-> A something bar foo)

4:22 Chousuke: that's just one case

4:22 noprompt: ejackson: i guess my point was that it's important to know when and where to apply abstraction.

4:22 Glenjamin: it's the case of hiding null

4:22 Chousuke: Glenjamin: if you have monads and syntactic support for it, you don't need any such special operators.

4:22 noprompt: of course, i still struggle with that too :)

4:23 Glenjamin: if you have macros and syntactic support for them, you don't need any such special monads?

4:23 Chousuke: macros don't compose

4:24 Glenjamin: mm, thats true

4:24 Chousuke: what if you had async operations that could return nulls?

4:24 if you implemented these things as monads, you could still use do syntax

4:25 Glenjamin: but what if i want to evaluate in parallel, or do something other than chain the calls?

4:25 surely i still need more notation

4:25 Chousuke: Glenjamin: do notation doesn't specify evaluation order

4:26 other than what is implied by the dependencies of each expression

4:27 Glenjamin: but if two computations fail in parallel, what error value would i get back?

4:27 Chousuke: both? it depends on the implementation of your bind

4:27 that's the point

4:27 you get to decide what happens

4:27 but the syntax stays the same

4:28 there are of course limits to what monads can express

4:28 but sufficiently many things are monadic that having syntactic support for them is convenient

4:29 noprompt: the day a language which marry's haskell and lisp comes a long will be a glorious day.

4:29 Chousuke: I think there is one already

4:29 Glenjamin: you have convinced me there's an advantage when building composable operations

4:30 noprompt: Chousuke: there are actually a few i've seen, but they're either no longer maintained or incomplete.

4:30 Chousuke: Glenjamin: if you think about it, composing things is the majority of what a programmer does nowadays

4:30 ejackson: Chousuke: so, which is it ? :)

4:31 Chousuke: Liskell is one I've seen mentioned somewhere

4:31 I haven't actually looked at it

4:32 ejackson: do you use Clojure's monads at all ?

4:32 noprompt: the last i checked liskell wasn't being maintained.

4:32 there's another one called shin.

4:33 Chousuke: ejackson: I have some code that uses them, and I implemented monads once myself using protocols :P

4:33 noprompt: sorry, shen.

4:33 Glenjamin: Chousuke: you've managed to pique my interest enough to try using some monads in my clojure :)

4:34 Chousuke: ejackson: They're not as ubiquitous in Clojure since having a static type system really helps with monads (gives you safety and all) but you can still get some pretty elegant code

4:34 Glenjamin: and now I'd better go to work!

4:35 ejackson: yeah, i hardly ever see them in the wild

4:39 Chousuke: ejackson: https://gist.github.com/Chousuke/141085 here's some toy code I wrote ages ago to test out clojure monads. I don't think it'd be trivial to write without monads.

4:40 or rather, you'd just end up duplicating State :P

4:40 * ejackson sidles over to have a look

4:41 Chousuke: it's a functional parser that supports incomplete input and can be resumed arbitrarily many times.

4:41 ejackson: that's pretty cool

4:41 and short !

4:41 Chousuke: IIRC it has a bug though where the regexp sometimes fails if the input is split in a certain way

4:43 ejackson: haskell is like malaria: every few years I succumb to a relapse

4:44 noprompt: ejackson: couldn't have said it better myself!

4:44 ejackson: i *so* want to actually use it all the time, but haven't put enough block time aside to get it right

4:44 noprompt: i'm debating picking up either erlang or prolog over the summer.

4:44 Chousuke: My main problem with haskell is that it makes it more difficult for me to program in other languages

4:45 ejackson: Clojure has done that to me too

4:45 Chousuke: "gah why can't I just fmap this and be done"

4:45 noprompt: Chousuke: yes, and it dooms you to see bugs.

4:45 ejackson: "what do you mean I can't use vectors as keys in a map, PYTHON ?"

4:45 what's haskells matrix story like ?

4:46 noprompt: ejackson: clojure reduced ruby to my shell scripting language.

4:47 actually, functional programming in general has ruin my experience in any language that isn't functional. :'(

4:47 Chousuke: ejackson: I tried doing v = v.sort() in python and then wondered why it wasn't working (I didn't get NPEs because my template-engine silently converted nulls to nothing)

4:48 noprompt: doomed to obscurity at the local developer meetups. it's a sad life. :)

4:48 ejackson: yeah, exactly. Clojure teaches you to rely on certain things, and elsewhere they're just not there.

4:48 noprompt: Chousuke: i had a fun conversation about the relevance of using negative indexes the other day with a python programmer.

4:49 apparently python doesn't even have a last function.

4:52 ejackson: clojure is also a great lesson in thinking in terms of data and data transformation.

6:02 ayia: Hi guys, How can i "paste" name passed to macro like (defmacro def-name-var [name] ...) into name of the var in its definition, where name should be like -<name>-fields?

6:16 clgv: ayia: please provide an example macro call and the desired expansion

6:29 noidi: ayia, maybe you want `symbol`? it takes a string and returns a symbol, so you can do something like `(def ~(symbol (str name "-suffix")) ~value)

6:40 ayia: clgv: =>(def-name-var jack) ;; should create a var with name -jack-fields

6:40 clgv: ayia: ok

6:41 ayia: (defmacro def-name-var [var-name] `(def ~(symbol (format "-%s-fields" (name var-name)))))

6:43 ayia: clgv: noidi: thanks you guys, for this approaches... Just one more question, is there any other way to do this, maybe just with using quotes/unquotes? i.e. to make the code even more readable...

6:44 clgv: ayia: no. you can define a separate function though

6:46 ayia: clgv: what does this mean "define a separate function"?

6:49 jaffe_: ayia: you can define a function that adds the suffix to the symbol, and then have your macro call that function instead

6:51 clgv: ayia: (defn derive-symbol [fmt s] (symbol (format fmt (name s)))) and then (defmacro def-name-var [var-name] `(def ~(derive-symbol "-%s-fields" svar-name)))

7:00 ayia: clgv: jaffe_: got it! thanks!

7:56 beaky: hello

7:56 knob: Hello!

7:56 beaky: Rich Hickey often refers to "Polymorphism a la carte" in his speech; what does that mean?

7:56 is it like the single-dispatch polymorphism in C++?

8:00 sparkjoy: I'm not the expert, but my studies so far have revealed both single-dispatch polymorphism

8:00 joegallo: i think it's like, you can have a slice of cake, or a slice of pie, or also there's multimethods

8:00 sparkjoy: but also multi-methods

8:01 protocols use single dispatch, with a privileged first arg (like this in OO)

8:01 hyPiRion: beaky: polymorphism as polymorphism itself. It's not bound to classes, only to functions.

8:02 sparkjoy: multimethods allow you to dispatch based on more than just the first arg

8:02 also a very cool thing about protocols

8:03 is that you can extend them not only to types that you define

8:03 but also to types that others have defined for which you do not control the source

8:04 I'm just learning about protocols now (highly recommend _Clojure Programming_) but they sure seem powerful

8:08 DerGuteMoritz: sparkjoy: note that protocols are just a subset of multimethods

8:08 beaky: clojure has multimethods too?

8:08 DerGuteMoritz: yes

8:08 sparkjoy: yep beaky

8:08 beaky: (even though it isn't OO at all) :D

8:09 DerGuteMoritz: protocol methods are just like multimethods which dispatch on the type of the first argument

8:09 Bronsa: mh, I don't think protocols are exactly a subset of multimethods

8:09 beaky: so OOP has no monopoly over polymorphism?

8:09 DerGuteMoritz: well, and with protocols you can also check whether they are implemented for a certain type, not sure if that's possible with multimethods

8:09 Bronsa: with protocols you can dispatch on the interface too, I don't think you can do that with multimethods

8:09 DerGuteMoritz: Bronsa: how do you mean?

8:10 surely you can use the same dispatch function that's used by protocols?

8:10 Bronsa: (extend-protocol proto clojure.lang.IPersistentMap (f [this] ..)))

8:10 DerGuteMoritz: except protocols will be more efficient

8:10 Bronsa: with a multimethod, you can't do that if you're dispatching on the first argument type

8:11 DerGuteMoritz: Bronsa: ah, perhaps

8:12 sparkjoy: beaky: there's plenty of polymorphism in Clojure - you just have finer grained control

8:14 watch Rich's "Simple made easy" talk - I think you'll get a feel for his goals of "decomplecting" systems

8:14 beaky: yeah that was an awesome lecture

8:23 so OOP is the enemy of simplicity?

8:24 sparkjoy: I wouldn't go that far, but I'm knee deep in an enterprise OO system now, using all the best practices, DDD, etc.

8:24 and I can tell you that we are not as agile as we could be

8:24 in large part because of the silos (classes) we've constructed around our data

8:25 we program with immutable objects in C#, and we use immutable, persistent data structures, but this is not idiomatic so we find ourselves fighting against the current a lot

8:26 and our persistent data structures suck compared to what's provided by default in Clojure

8:54 cmajor7: what would be the way to render protobuf from compojure? overrite "Renderable" with "byte-array" type?

9:18 stuartsierra: By the way, Hudson releases are (mostly) working again.

9:18 In case anyone was waiting to release a library or something.

9:18 See my latest email to clojure-dev.

10:12 dsabanin: hey guys

10:13 hey guys

10:14 silasdavis: I'm getting a "don't know how to create ISeq error" which I've learnt usually means I've done somethign weird with '()'

10:14 could anyone explain how the handler on line 52 could cause this error

10:14 when the alternative handler/site works fine

10:16 dsabanin: I wonder what is the right place to put a type hint for return value in defn? before arguments vector or before the name?

10:16 ucb: silasdavis: paste code?

10:17 silasdavis: ucb, oh I did paste it, I just didn't give you the link, how helpful of me: https://www.refheap.com/paste/13932

10:20 ppppaul: what should i use instead of walk to easily transform a nested data structure?

10:22 stuartsierra: dsabanin: In the past, functions were type hinted with ^ClassName metadata before the function name.

10:23 dsabanin: ah, I see. That explains why both ways work :)

10:23 thanks!

10:23 stuartsierra: dsabanin: With the introduction of primitive function arguments & return values in Clojure 1.3, you could put return type hints on the argument vector.

10:24 ppppaul: If you know something about the structure of the thing you're walking, you can create your own recursive function that will be much more efficient than clojure.walk, e.g. using `update-in`.

10:25 clojure.walk is a general, but not very efficient, solution to walking any arbitrary data structure.

10:25 gfredericks: clojurebot: clojure.walk is a general, but not very efficient, solution to walking any arbitrary data structure.

10:25 clojurebot: In Ordnung

10:26 stuartsierra: clojure.walk also doesn't work on `defrecord` types

10:26 if I recall

10:27 tcrayford: also you could try using a zipper. They are super good for walking nested structures and manipulating bits of them as you go

10:27 ppppaul: stuartsierra, i have found that when i attempt to do transformations with update-in it can get very hairy

10:27 maybe i'm doing them wrong

10:27 stuartsierra: Oh, it can get hairy. :)

10:27 ppppaul: i find my walks to be very simple

10:27 though, when i need a complicated walk it usually fails

10:28 so i stack a few simple ones together

10:28 currently i'm mostly using walks for testing

10:28 stuartsierra: ppppaul: If it works and is fast enough for the use case, then there's no reason not to use clojure.walk.

10:29 ppppaul: i think that i can probably get away with memorizing if i need performance

10:29 thanks stuartsierra, last night there was some talk about walk, and it made me feel like i may be going in the wrong direction with my style of clojure programming

10:30 stuartsierra: `walk` is certainly convenient - that's why I wrote it. :)

10:32 ppppaul: i have found it very useful. i even ported it to javascript.

10:36 actually, since i'm on this topic... stuartsierra there have been occasions where i want to rip out some things from a tree and put them in a flattened array. like maybe all integers or something. i tried to do this a few times with walk but found it extremely hard. do you have any strategy for doing something like that (other than using an atom)?

10:36 stuartsierra: Yeah `walk` isn't really designed for that.

10:37 I do it with recursive functions and `mapcat` but it's not always easy.

10:37 ppppaul: just wondering if there was some clever way to deal with that with walk... like returning arrays and then doing a flatten or something

10:38 VFe: Anyone been using Riak via Clojure and have any recommendations for client libs?(i.e. any reason or problems I might encounter using Welle over Sumo or clj-riak, etc)

10:38 tcrayford: what kinda items are you querying for? You might be able to use tree-seq

10:38 antares_: VFe: clj-riak and sumo are not really maintained, AFAIK

10:38 tcrayford: VFe: I have been. I think welle's the only one of those that is regularly updated

10:38 ppppaul: hmm... something like #(= (type %) "whatever")

10:38 tcrayford: (sadly, I don't think welle is very well designed at all)

10:39 VFe: yeah, welle has been giving me some issues, and I was curious if people used one of the others more regularly

10:39 antares_: tcrayford: how many ways are there to design a K/V store API? :)

10:39 VFe: care to elaborate? I'm the author

10:39 VFe: Oh, well hello :)

10:40 ppppaul: antares_, redis...

10:40 tcrayford: antares_: when that store is eventually consistent, there are quite a few things welle does that I'm sad about (I'm a contributer, and using it)

10:40 antares_: ppppaul: I'm talking about client libraries

10:41 ppppaul: hmmm... there are probably a lot of ways to do so

10:41 antares_: tcrayford: well, I've seen only one issue from you, what else is missing?

10:41 ppppaul: really? for a key/value store?

10:41 ppppaul: but the top level API shouldn't be so big

10:42 VFe: Well, first question, when I run it from repl, am I supposed to see like 3 pages of reflection warnings?

10:42 antares_: VFe: welle itself has next to no reflection warnings

10:43 some of its dependencies have them

10:43 tcrayford: antares_: the api doesn't force people to use resolvers/retriers, and the docs sorta handwave over receiving conflicts.

10:43 antares_: tcrayford: and that's it?

10:43 VFe: yeah, I see nrepl, complete/core, etc, so that's expected behavior then?

10:44 antares_: tcrayford: retriers are now used by default. Forcing people to use resolvers sounds a bit too much.

10:44 tcrayford: man, at least we have some documentation. Most projects don't even explain what the hell R, W, DW and so on are.

10:44 tcrayford: antares_: right. I'm glad about that ;)

10:45 antares_: VFe: the only way to solve it is to run after every dependency (and dependency dependency, and so on) and fix reflection warnings there

10:45 people did fix some in Cheshire and clj-http

10:46 sometimes they can't really be avoided, because in Clojure you only can overload on function arity, not types

10:46 tcrayford: antares_: the fact that I've been wrapping welle in my own library so that the interface is nicer kinda makes me want to just go away and write my own clojure client lib on top of the basho java client.

10:47 antares_: tcrayford: well, it's your call :)

10:47 tcrayford: antares_: I'm not sure, but I think modify might do the wrong thing with vclocks right now as well. Also, I have a rant about the *riak-client* and binding style of injecting the client, but that seems standard in clojure, sadly.

10:48 antares_: tcrayford: there is one thing that will change in 1.6 with vclock

10:48 apparently the value we need to propagate is the one from the response

10:48 and it's currently not preserved. So kv/fetch return value will have to change :(

10:49 tcrayford: antares: is that with modify? That was my issue ;)

10:49 antares_: to {:vclock … :object …}

10:50 tcrayford: it affects modify but is also a problem of its own

10:50 unfortunately, the Java client itself has next to no docs

10:51 at least did not have them 2 years ago when Welle was started

10:51 tcrayford: antares_: that'd cause sibling explosion, right? (assuming you have allow_mult on, which should nearly always be the case)

10:51 antares_: so it wasn't obvious which vclock value we have to use

10:51 tcrayford: antares_: yeah. It's been rewritten completely since then from my perspective ;)

10:51 antares_: yes, that's what aphyr has observed

10:51 with his network splits simulation tool

10:52 tcrayford: I didn't see major changes, they just added and documented some stuff

10:52 tcrayford: heh. It's a good thing the app I've written on top of welle isn't in production yet then ;)

10:52 antares_: with this change, I don't think there will be anything missing in Welle w.r.t. to the Java client

10:52 except that you don't have domain objects, of course

10:52 tcrayford: well, that's part of clojure

10:52 ;)

10:53 the shit you store in riak should just be data, not domain objects ;)

10:53 ieure: Sup tcrayford.

10:53 tcrayford: ieure: sup

10:54 antares_: tcrayford: what I often used Riak for, I often used LWW :) but I hear ya. I think 1.6 will be out in the next few days. We got a lot of tests to update, but the code change is minor.

10:55 tcrayford: antares_: neat. Thanks. I don't wanna sound pissed off, welle is reasonably good as far as the riak clients I've used go.

10:55 antares_: tcrayford: but I totally welcome more clients

10:55 tcrayford: there is #clojurewerkz now if you want to suggest something or complain about welle more ;)

10:56 tcrayford: antares_: it'll be a while if I do my own, I have an app to ship first

10:56 antares_: VFe: not sure if this answers your question, but with 1.6, Welle will likely be good enough even for demanding users. And it is maintained, including the docs.

10:57 VFe: My main issue was the reflection things, pages of warnings tend to make me think I'm doing something wrong XD

10:57 antares_: tcrayford: understandable. If you want to see more changes in Welle, please file an issue.

10:57 VFe: But the discussion was enlightening, I mainly asked cause I have to decide what we're going to be using in production

10:58 antares_: VFe: can you gist them?

10:58 VFe: sure

10:59 tcrayford: antares_: honestly most of the changes I'd want to see would be api changes (e.g. I don't think most of the options to fetch/store/etc should be options, they should be bundled up in a "bucket", along with a resolver/retrier. Those are more personal opinion things though. I have an internal namespace that does all of that for me right now).

11:00 VFe: https://gist.github.com/VFe/5452786

11:01 antares_: tcrayford: Riak Java client kinda has two clients: "raw" and POJO-oriented. We can consider adding a "higher level" one in Welle.

11:01 tcrayford: antares_: yeah. We should take this discussion to #clojurewerkz, not keep it in here

11:01 antares_: VFe: so, most of them are from complete/core. Is that an OSS library?

11:02 VFe: clojure.tools.nrepl I can't fix, I live in a country that has no reliable mail to US, so I won't be filing Clojure CA until it is electronic :(

11:05 VFe: I actually don't know what complete.core is, though in regards to the second part, couldn't you sign the document, email it to someone you trust in the US, have them print it and send for CA?

11:05 i.e. have someone act as your legal proxy

11:06 antares_: VFe: it's not a Welle dependency, it's loaded by something else

11:06 noidi: VFe, if that was acceptable then Rich Hickey could just receive the e-mail directly and print it out himself if he ever needs a copy

11:07 antares_: VFe: possibly. I don't generally bother with core.* stuff, even trivial patches are accepted 3-12 months after you submit them.

11:07 that's not how OSS should work and I'm tired of trying to change the system. There are better ways to spend time.

11:08 nrepl developers are a bit better in this regard

11:08 beaky: hello

11:09 antares_: VFe: if you run lein deps :tree, it should show you what dependencies you have. Could you please gist that?

11:09 beaky: how do I run clojure programs on my platform? I am using archlinux on x86/64

11:09 nDuff: antares_: Can you send faxes? Those are legally recognizable in the US in many cases (Relevance would have to talk to their lawyer, which I'm not, to determine if that's the case here).

11:09 VFe: lol, I like how I I just googled for complete/core/clj and now that gist is on first page of results

11:10 I suddenly feel so alone

11:10 and yeah, lemme do that

11:10 noidi: beaky, do you want to get started with Clojure development, or run a program written by someone else in Clojure?

11:10 beaky: get started :D

11:11 antares_: beaky: there are tutorials at http://clojure-doc.org, take a look

11:11 beaky: ah thanks

11:11 * beaky brandishes his parentheses

11:11 beaky: hmm clojure uses square brackets and braces too... thats new :D

11:12 antares_: nDuff: the policy is, you mail a piece of paper or sign it at one of the Relevance events. And then there are "screeners" and Clojure/core and months and months of waiting. I won't bother with that.

11:12 nDuff: antares_: Yes, I know -- I've done the "sign it at a conj" thing.

11:12 VFe: https://gist.github.com/VFe/5452872

11:12 nDuff: antares_: ...but I'm saying that it should be possible to make a case for accepting faxes.

11:12 beaky: btw why does it use first/rest instead of car/cdr?

11:12 technomancy: heh; faxes

11:13 antares_: nDuff: the process is made intentionally hard. I'm not going to cooperate.

11:13 nDuff: technomancy: They're used for sensitive medical documents all the bloody time.

11:13 antares_: beaky: because nobody knows what car/cdr mean

11:13 technomancy: http://achewood.com/index.php?date=11222006

11:13 nDuff: antares_: Ahh. If it's protest, that's a completely different matter.

11:13 antares_: beaky: besides CL and Scheme users, which are a tiny % of people who get into Clojure (33% Java, 33% Ruby/Python)

11:13 beaky: yeah I guess it's car/cdr are way too oldschool/archaic and first/rest are more communicative

11:14 VFe: Technically, in the US, signature is an intent, which is why anything can be a signature, including digital. or why you can proxy your legal rights at will.

11:14 antares_: nDuff: not really a protest, I just don't think it's worth it

11:14 VFe: So if they don't accept an email or fax, its a matter of personal policy, not of legality

11:14 noidi: besides, clojure's sequences are not linked lists made out of cons cells

11:14 ieure: beaky, Clojure takes some inspiration from Scheme, which uses first/rest rather than car/cdr.

11:14 noidi: so car/cdr could lead old lisp programmers astray in thinking that

11:14 tcrayford: antares_: I haven't signed one as well, for similar reasons. I've been to relevance events and not signed purposefully.

11:14 beaky: so the default clojure sequence is something from java?

11:15 tcrayford: no

11:15 ieure: Well.

11:15 * beaky is not very familiar with java

11:15 ieure: Much of Clojure is implemented in Java, or at least has Java interfaces.

11:15 noidi: beaky, http://clojure.org/sequences

11:15 beaky: I am only familiar with C++ :D

11:15 ieure: So clojure.lang.ISeq is the underlying type.

11:15 beaky: ah thanks

11:16 antares_: beaky: please read a guide on sequences at http://clojure-doc.org, they are not implemented as cons cells and yes, they are implemented in Java. But most importantly they are immutable.

11:17 beaky: a slightly more approachable version http://clojure-doc.org/articles/language/collections_and_sequences.html

11:17 beaky: ah, so clojure sequences are much like haskell's []

11:18 but more general

11:18 tcrayford: well, haskell

11:18 lucian: beaky: or less general, depending how you look at it

11:18 tcrayford: 's [] is implemented as cons cells iirc

11:18 lucian: beaky: certainly more explicit

11:18 beaky: ah

11:18 that's awesome

11:19 I like the idea of having a uniform interface for sequences

11:19 maio: I would like to serve result of write function from https://github.com/jkk/purty/blob/master/src/jkkramer/purty.clj as HTTP response. Any idea how to do that? It expects something that works with clojure.java.io/file

11:19 beaky: e.g. in C++, the containers are unified under iterators

11:19 (but C++ containers are mutable by default) :(

11:19 tcrayford: beaky: haskell has uniform interfaces for sequences (see Traversable/etc). They're just not commonly used

11:21 beaky: hmm why not? :(

11:21 maybe the haskell crowd prefers pointfree or something else I guess

11:22 tcrayford: for one thing they're kinda complicated interfaces, and they're not exported by the Prelude. First/Rest is a much better design (imo)

11:22 beaky: ah

11:23 seq is simple yet powerful :D

11:29 tomoj: Traversable > Seq

11:29 beaky: is there a nice repl with autocomplete for clojure?

11:30 vijaykiran: beaky: nrepl has autocomplete

11:30 cmajor7: answering my own question (serving protobuf from Compojure). no need to extend "Renderable", just wrap it into ByteArrayInputStream.

11:31 nDuff: beaky: I'm very happy with emacs' nrepl.el

11:31 cmajor7: beaky: "lein repl"

11:31 beaky: ah

11:32 lein repl works :D

11:32 * nDuff is too spoiled by emacs to call the stock repl "nice". Gotta have paredit...

11:32 beaky: I think ill try nrepl

11:32 im a vim user... how long will it take me to ge tused to emacs? :D

11:33 * nDuff has been swinging both ways (editor-wise) for well over a decade, and so couldn't say.

11:34 technomancy: don't learn emacs and clojure at the same time

11:34 antares_: beaky: why not use Vim Fireplace?

11:35 beaky: http://clojure-doc.org/articles/tutorials/vim_fireplace.html

11:35 TimMc: Is clojure-jack-in still a thing?

11:35 beaky: ah thans

11:35 TimMc: I installed clojure-mode from Marmalade, but that command is missing.

11:36 tcrayford: beaky: vim is fine with clojure. Not as fluid as emacs, but fine. Fireplace has some weird redrawing bugs on my system, but nothing super bad

11:37 beaky: :D

11:37 blrm: beaky: vim fireplace is nice. I did wind up switching to emacs just for clojure, and it wasn't so bad. But yeah, learning clojure and a new editor at the same time is not going to be fun

11:37 rbxbx: tcrayford: beaky fwiw I've found vim/fireplace better in some regards than nrepl.el (if you'll pardon the heresy)

11:37 beaky: I always thought of emacs as the ultimate lisp ide

11:37 kliph: I seem to remember stumbling upon a MIT Scratch/Berkeley BYOB visual block-based programming implementation in Clojure, but now I can't find it. Am I off my rocker or can anyone point me in the right direction?

11:39 tcrayford: rbxbx: it also has the bit in the readme about tim TPing your house

11:40 blrm: beaky: you might check out emacs live if you decide you want to learn emacs. that helped me to get started with emacs+clojure: https://github.com/overtone/emacs-live

12:06 beaky: if clojure is not object-oriented at all, how does it do interop with java?

12:06 (which is pretty religious about OOP) :D

12:07 danlarkin: clojure lets you invoke methods on objects

12:07 beaky: ah

12:07 danlarkin: and do other stuff too, like implement interfaces and inherit from classes, but that's generally not necessary

12:08 mikerod: I'm looking at the source for `reify` and I see that it is a macro. It uses a function `reify*`. Where is `reify*` defined at? I can't seem to find it.

12:09 In the clojure source that is.

12:09 llasram: mikerod: It's a special form, directly recognized by the compiler

12:09 nDuff: mikerod: clojure/lang/Compiler.java

12:10 mikerod: Ah, ok. I didn't realize this. Thank you.

12:11 joegallo: lo, in the beginning there were the special forms, and the special forms were with clojure, and the specials forms were clojure.

12:12 mikerod: :)

12:12 antares_: mikerod: special forms are listed on http://clojure-doc.org/articles/language/macros.html#special_forms :)

12:15 mikerod: antares_: Oh, I have not came across this one before. That's a great reference, thanks.

12:29 jcromartie: so here's a weird question

12:29 what's should I name a ref that holds the state of the data model

12:29 in a local scope

12:30 "ref" is already core/ref

12:30 "model" sounds more like a value

12:30 same with "state"

12:31 antares_: jcromartie: state is fine (and pretty common). You can also use ref'.

12:31 jcromartie: but then I use "state" to name the current value in the function arguments to alter, send, etc.

12:33 and Clojure calls the current value of an identity/ref "state"

12:33 bbloom: jcromartie: i've run into that naming conundrum before... where you have like the-state and a-state

12:33 beaky: how does clojure achieve encapsulation without OOP?

12:33 Ember-: via several means but also encapsulation isn't as important as with OOP

12:33 jcromartie: beaky: closures, records, datatypes

12:34 beaky: you shouldn't worry about hiding things, but you should try to abstract things

12:34 Ember-: if you have no mutable state then a large part of why encapsulation is so crucial with OOP goes out of the window

12:34 beaky: ah

12:35 bbloom: jcromartie: i've more or less just decided it's ok to shadow the ref's name

12:37 jcromartie: (defmacro swapping! [name & body] `(swap! ~name (fn [~name] ~@body)))

12:37 i've never actually used that, but it conveys a pattern :-P

12:37 jcromartie: nice

12:37 beaky: so in clojure, all the OOP fluff is simply unnecessary? :D

12:37 bbloom: beaky: no one said that

12:37 beaky: ah

12:38 bbloom: beaky: OOP is a deeply understood and well studied bag of tools

12:38 beaky: clojure just embodies the opinion that OOP is the wrong default

12:41 ToBeReplaced: anyone have any tools for edn-based rpc they like?

12:41 beaky: it's not the default because it ties together a bunch of stuff in an unnatural way?

12:41 technomancy: ToBeReplaced: sure: https://github.com/technomancy/die-roboter

12:41 bbloom: beaky: great talk by stuartsierra on thinking in data instead of objects: http://www.infoq.com/presentations/Thinking-in-Data

12:41 beaky: ah thanks

12:43 jcromartie: but at some point you might need something object-like (i.e. an identity that changes)

12:43 for instance a cache of values that is updated in the background

12:43 bbloom: jcromartie: objects are useful even without identities sometimes

12:45 jcromartie: like take a look at clojure/zip.clj, which rich wrote in the early days of clojure

12:45 jcromartie: bbloom: what would that be? isn't it just data at that point?

12:45 ah

12:45 bbloom: jcromartie: it stores functions in the metadata of a vector....

12:45 jcromartie: it would probably have been much better as a protocol & a reify

12:46 (but i don't think those existed at the time)

12:46 jcromartie: nope

12:46 bbloom: objects are great when you have "co-data"... aka data that isn't printable/readable/immutable/acyclic/etc

12:46 see also seqs

12:47 they use objects to represent infinite data, not identities

12:49 ToBeReplaced: technomancy: cool, but not what i'm looking for; i'm looking for libraries to handle the equivalent of the json-rpc spec with edn

12:49 technomancy: ToBeReplaced: hm. never used json-rpc, but if there are no libraries for it, it could be because it's just a trivial compojure handler

12:51 ToBeReplaced: yeah it's pretty straight forward / easy to roll -- you want the same kind of thing for client too

12:51 beaky: (alter-var-root #'*read-eval* (constantly false)) ;; What does this line do? It was generated by lein and it says it somehow prevents some kind of dangerous behavior

12:56 no7hing: it prevents the clojure reader from evaluating forms that were e.g. loaded via slurp

12:57 antares_: beaky: disables evaluation of arbitrary code by the reader (clojure.core/read-string, etc)

12:57 beaky: if you use Clojure 1.5.1, it is the default so that line can be removed

13:02 andyfingerhut: beaky: antares_: *read-eval* still defaults to true in Clojure 1.5.1

13:03 antares_: andyfingerhut: oh

13:03 beaky: ah

13:03 andyfingerhut: Clojure 1.5.1 added the clojure.edn/read and read-string functions, that behave much like clojure.core/read and read-string, except have no ability to execute code as a side effect.

13:04 tools.reader contrib library also provides similar capability for edn reading with no side effects, and works with Clojure 1.3 and later.

13:04 clojure.core/read has its uses as it is still, but primarily when you want to pass around executable Clojure code as text.

13:16 technomancy: beaky: it was meant to be a workaround for the problem that read and read-string were unsafe on user-provided data, but they changed the tune and said that they now aren't intended for user data anyway

13:17 which IMO is unhelpful because they are still going to be used for it anyway, but that ship has sailed

13:22 sritchie: cemerick, any advice on how to get clj-http to provide a proper csrf header in a post request?

13:30 mynomoto: How do I require a project namespace in a lein plugin?

13:31 technomancy: mynomoto: eval-in-project

13:31 that is, leiningen.core.eval/eval-in-project

13:31 mynomoto: technomancy: I tried that, but not sure how to use it. Do you have an example?

13:33 technomancy: mynomoto: sure; see the source for the "check" task in leniingen

13:33 mynomoto: Ok, thanks.

13:34 technomancy: basically it's like eval except it takes a project argument first

13:34 project map

13:37 cemerick: sritchie: you mean something like X-Requested-With?

13:37 sritchie: cemerick: figured it out -- I just needed to use the :cookie-store option

13:37 cemerick: ah

13:38 sritchie: yeah, X-Request-With isn't right, anyway.

13:39 silasdavis: how should I convert ':foo' to 'foo'?

13:39 llasram: Do you want ##(name :foo) ?

13:39 lazybot: ⇒ "foo"

13:40 silasdavis: thanks

13:43 Glenjamin: when the 'check' task warns about reflection, what is it actually warning about?

13:45 technomancy: ...is this a trick question?

13:55 beaky: does a dynamically-typed programming language need polymorphism?

13:56 technomancy: beaky: you need polymorphism for clojure's built-in types. genuine need for polymorphism for user-defined types is fairly rare.

13:57 it's completely orthogonal to the static/dynamic divide though

13:57 beaky: ah

13:58 patchwork: Trying to wean myself off swank for nrepl

13:59 Can you embed nrepl inside a running process?

13:59 beaky: what are clojure's builtins? I guess it has strings, symbols, singly-linked lists, vectors, hashmaps, and sets?

13:59 technomancy: patchwork: yeah, it's in the nrepl readme

14:00 patchwork: technomancy: I read through it, I just see it being able to start from the command line or from within emacs, but nothing about starting it from inside my app then connecting to it

14:01 technomancy: patchwork: are you sure you have the right readme?

14:01 patchwork: That is the main draw for swank, I can start it up inside my app then control my running app process from emacs

14:01 https://github.com/kingtim/nrepl.el ?

14:01 technomancy: https://github.com/clojure/tools.nrepl

14:01 you're reading the client's readme, not the server

14:01 patchwork: technomancy: Aha, thanks!

14:01 technomancy: sure

14:03 jcromartie: I really need to get out of this one-big-ref thing

14:03 I have one ref for the configuration of the app

14:03 patchwork: jcromartie: I just went through that

14:04 jcromartie: but then the runtime data should have its own references

14:04 atoms, agents, whatever

14:04 I have an API that is used by a JS front-end for making changes to the config.

14:04 patchwork: I think it is better to have a dynamic var actually, then you can rebind it at will, but not affect other processes

14:04 you bind it when the app boots

14:04 jcromartie: I think I might just do that

14:04 because I don't realyl need to create instances of the system

14:05 I went down this route thinking it was cool

14:05 patchwork: I ran into trouble with the ref because all threads saw the same thing!

14:05 It is helpful if that is what you want

14:05 beaky: can you program in an imperative style in clojure? (like in scala)

14:05 patchwork: but for config I needed to change some options

14:05 jcromartie: beaky: sure why not?

14:05 patchwork: beaky: If you insist!

14:05 (do (op! …) (op! …) ...)

14:06 beaky: ah :D

14:06 jcromartie: patchwork: someone gave me the idea of having a function that creates a "system" ref that can be held in the REPL or whatever and then pass that to functions that create compojure handlers etc

14:06 but it would just be simpler to have a var

14:06 patchwork: jcromartie: I found the var to be more flexible for config specifically

14:07 jcromartie: and you can add watches to save it etc

14:07 patchwork: but I'm sure others have other opinions!

14:07 jcromartie: I dunno

14:07 I'd just have a ref in a var

14:07 I have a good system in place for persistence

14:07 patchwork: Do you know about the #'var-name idiom?

14:07 jcromartie: yes

14:08 patchwork: it returns a reference to the var, not the value

14:08 very useful

14:08 jcromartie: it just returns the var itself

14:09 patchwork: Yeah. I avoid dynamic vars everywhere (it couples code too heavily and fns can't be reused elsewhere), but config needs user specified values somehow

14:12 Glenjamin: is there a quick way to grab the first non-empty string in a sequence?

14:12 tcrayford: (first (filter empty? seq))

14:12 oh

14:12 non empty

14:12 patchwork: Glenjamin: (first (filter identity seq))

14:13 Or more clearly (first (remove empty? seq))

14:13 tcrayford: ,(first (filter (complement empty?) ["a" ""])

14:13 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

14:13 patchwork: remove/filter are lazy so it will only calculate up to the first non-empty string

14:13 tcrayford: ,(first (filter (complement empty?) ["a" ""]))

14:13 clojurebot: "a"

14:14 kaw: patchwork: Isn't "" trueish?

14:14 Glenjamin: presumably that identity one doesn't work, or i could just use (or)

14:14 tcrayford: yeah, identity doesn't work

14:14 filter is fine because of laziness though

14:14 patchwork: Ah, yeah I was thinking nil, not ""

14:15 tieTYT2: http://stackoverflow.com/questions/16199258/how-can-i-pass-in-the-list-of-methods-to-gen-class

14:15 Glenjamin: it's a shame clojure doesn't have a haskell style function composition operator

14:15 tcrayford: comp is ok

14:15 clojure doesn't have operators!

14:16 Glenjamin: hah, true

14:16 reader macro then :p

14:16 tcrayford: like arc?

14:16 (a:b thing)

14:16 Glenjamin: that could work

14:18 bbloom: blargh. just what i need. yet another thing that breaks * and # in vim

14:18 Glenjamin: ,((comp first remove) empty? ["" "a"])

14:18 clojurebot: "a"

14:18 Glenjamin: vs

14:18 ,(first (remove empty? ["" "a"]))

14:18 clojurebot: "a"

14:19 Glenjamin: or i guess (-> ["" "a"] (remove empty?) first)

14:19 ,(-> ["" "a"] (remove empty?) first)

14:19 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.core$empty_QMARK_>

14:19 Glenjamin: bah, ->>

14:19 anyway, it all seems to be roughly the same size-wise

14:26 gfredericks: woah that money library has functions called `plus` and `minus` o_O

14:27 antares_: gfredericks: yes, what about it?

14:28 we used the same names as Joda Money. Also, asking people to :refer-clojure :except [+ -] is a bit too much

14:29 gfredericks: antares_: I'd rather do :as m with m/+ and m/-

14:30 antares_: gfredericks: then our + would be non-variadic

14:30 Raynes: antares_: Please, please expect that people are going to :require :as your libraries.

14:30 antares_: at least if we change the signature

14:30 Raynes: I am not recommending :use or :refer :all

14:31 Raynes: I'd so much rather have then called + and - and have to qualify them.

14:31 them*

14:31 * antares_ shrugs

14:31 tcrayford: (money/+ a b) reads worse than (money/plus a b) to me

14:32 antares_: I followed joda money names, it doesn't matter to me if it is + or plus

14:32 Raynes: I mean, it isn't a huge deal, but clj-time is super inconsistent because it's horrified of shadowing clojure.core names.

14:32 antares_: plus does not behave like clojure.core/+ if you take a close look

14:32 it is not variadic, it can accept Java objects or doubles

14:32 llasram: I'd like it to be `+` please (Unicode "PLUS SIGN" character)

14:33 Raynes: Shadowing doesn't imply behaving the same.

14:33 antares_: Raynes: may also be because it is really old and has dozens of functions in a single namespace

14:33 trinary: use the emoji fat plus

14:33 gfredericks: tcrayford: because of the '/' and the '+' next to each other?

14:33 antares_: trinary: ha

14:33 Raynes: plus and minus are perfectly acceptable in any case.

14:33 tcrayford: gfredricks: yep

14:33 also

14:33 does money// even work?

14:33 for division?

14:34 antares_: good point, amounts// would at least look terrible

14:34 tcrayford: it should

14:34 Raynes: &(clojure.core// 10 2)

14:34 lazybot: ⇒ 5

14:34 tcrayford: there's something new about clojure's syntax

14:34 (to me)

14:34 gfredericks: is that // bug fixed?

14:34 antares_: lets call division // to confuse people!

14:35 I still roll my eyes when I have to use =:= and =/= in Erlang

14:36 Raynes: I roll my eyes when I have to use ports in Erlang.

14:37 gfredericks: in any case, I think most would agree that the idiomatic clojure practice is to give things the most straightforward name and use namespaces to distinguish

14:38 then the user can decide if they want naked symbols to refer to the core version or the library version or whatever

14:38 Raynes: We should put it in that monstrous style guide!

14:38 antares_: gfredericks: I thought the most idiomatic is to be all anal about consistency?

14:39 gfredericks: antares_: I'm not sure what you mean by that

14:39 Raynes: Yeah, that's a horrible thing to be.

14:39 antares_: when a minor difference in behavior with clojure.core/+ means you have to pick a different name :)

14:39 gfredericks: oh I see

14:39 Raynes: After you've used clj-time for more than five seconds and ended up in secs seconds second minutes mins minute hell...

14:40 gfredericks: no, I agree with raynes that using the same name doesn't imply any particular similarity; also is there some reason it can't be variadic?

14:40 Raynes: FWIW, I'm totally fine with plus and minus.

14:40 I was just making a case for not avoiding shadowing in other scenarios.

14:41 antares_: Raynes: I think clj-time is a case where the domain is very nuanced, less so with money. There are "hours" and "hours of day", for example, the former is a period of time

14:41 Raynes: antares_: Not what I mean though.

14:41 antares_: IIRC, there is at least one case where it names something 'sec' instead of 'second' because of clojure.core/second, while the minute analogue is called 'minute'.

14:41 That is *horrifying*.

14:42 And I've nearly broken things over it in the past. :P

14:42 antares_: Raynes: maybe I focused to much on seconds vs second vs secs :)

14:42 callen: why isn't it days/hours/minutes/seconds

14:42 gtrak: &min

14:42 lazybot: ⇒ #<core$min clojure.core$min@11cdd43>

14:42 antares_: Raynes: please file an issue, I think seancorfield would consider changing that to "second"

14:43 Raynes: I doubt it. It'd be a breaking change.

14:43 antares_: I doubt clojure.core/second gets much use

14:43 gfredericks: I use it all the time

14:43 but the shadowing wouldn't bother me, obviously

14:43 antares_: callen: there are functions that return a period of N seconds and # of seconds on a date/time

14:43 Raynes: it's OK to have a breaking change once in a few years

14:43 I'm going to break a few key functions in Welle tomorrow :)

14:44 Raynes: antares_: So, you do some Erlang?

14:44 antares_: because it's the right thing to do

14:44 gfredericks: fortunately, it's not Ruby, people will get a warning

14:44 gtrak: make a new lib called clj-time+ or clj-time-plus

14:44 gfredericks: antares_: oh sure

14:44 * callen reminds himself who the author of clj-time is

14:44 antares_: Raynes: yes, mostly on and around RabbitMQ. Also have an Elixir library :)

14:44 VFe: the real question I have, is how do I actually use emoji in clojure?! (defn 🍉 [🐉 🐪 💀](+ (* 🐪 🐉) 💀))

14:44 * callen ponders the merits of trolling him

14:44 antares_: gtrak: noooooo

14:44 Raynes: antares_: https://www.refheap.com/paste/13920 I'll pay you $10 to send Erlang a patch for this.

14:45 Of course I'm pretty sure that involves C.

14:45 antares_: VFe: like so twitter.com/michaelklishin/status/270072723751960576? ;)

14:45 Raynes: I don't hack on OTP, I use Erlang

14:45 Raynes: antares_: But you should.

14:46 gfredericks: using words for numeric operations bothered the hell out of me every time I wanted to do alternative arithmetic in java or JS; clojure allows that to be much nicer in my opinion

14:46 but I don't mind being a minority on that. I can always creating locals for + - * / etc :)

14:46 antares_: Raynes: right after clojurewerkz passes 100 projects, I promise

14:46 gfredericks: (defmacro with-money-math ...)

14:46 technomancy: gfredericks: CL's use of -p for predicates drives me nuts for the same reason

14:46 VFe: antares_: this changes everything

14:47 gfredericks: technomancy: it's a required thing?

14:47 technomancy: gfredericks: no, a cultural thing

14:47 Raynes: antares_: I'll hold you to it.

14:47 technomancy: gfredericks: well, it might be required in CL; not sure if the standard allows for ?

14:47 tcrayford: I really wish haskell allowed ? as part of a variable name :/

14:47 Raynes: 'variable'

14:48 technomancy: I bet all widely-used implementations do, and elisp certainly does

14:48 Raynes: EVIL ONE

14:48 antares_: Raynes: I know you are serious business

14:48 gfredericks: technomancy: oh right question marks

14:48 tcrayford: Raynes: im troll

14:48 * Apage43 has hacked on the erlang VM before

14:48 Apage43: it's pretty hairy though

14:48 Raynes: Apage43: You can have my $10 as well.

14:48 It's bounty.

14:48 I'll even tack on $1 for pain and suffering for having to use C. ;)

14:49 technomancy: hazard pay

14:49 antares_: do C programmers get to retire earlier, too?

14:49 mynomoto: I'm still trying to use eval-in-project for a lein plugin. I got this code https://www.refheap.com/paste/13938

14:50 SegFaultAX: Apage43: Y u no nif?

14:50 Apage43: SegFaultAX: I've done NIFs too

14:50 mynomoto: And this error: Exception in thread "main" java.lang.ClassNotFoundException: squiggle.core, compiling:(NO_SOURCE_PATH:1:37)

14:50 Apage43: I've built the VM for Android and iOS before and that required getting into the guts though

14:50 technomancy: mynomoto: it's best to use fully-qualified var names for referring to things not in core

14:50 SegFaultAX: Apage43: Then I /really/ feel your pain.

14:50 technomancy: at least for starters

14:50 Apage43: also had to debug the VM on numerous occasions

14:51 SegFaultAX: Apage43: Eheh, Erlang on Android. Wut?

14:51 Apage43: *and* iphone

14:51 it was for a product that packaged CouchDB

14:51 SegFaultAX: Apage43: But.. why?

14:51 Ah.

14:51 mynomoto: technomancy: my bad. Will do.

14:51 SegFaultAX: Still, pleasae no.

14:52 technomancy: mynomoto: but it sounds like the init form might be the culprit here

14:52 confirm it's on the classpath, etc

14:52 cemerick: dnolen: any ideas re: a StackOverflow compiling a match form in one environment, not another (on the same commit in the same project)?

14:52 Apage43: indeed, it was a silly idea, and we've luckily scrapped it in favor of just writing a CouchDB-compatible lightweight db for that stuff

14:52 Raynes: I'd do the port stuff myself, but goodness, I value my life more than that.

14:52 Apage43: compatible meaning it syncs with it, not necessarily exposes the same API

14:53 dnolen: cemerick: hmm not really

14:55 SegFaultAX: Apage43: Why would you want such a thing to begin with?

14:55 mynomoto: technomancy: I'm running the plugin in that project folder. It should be in the classpath right?

14:55 cemerick: yeah, figured it'd be a longshot

14:56 Apage43: SegFaultAX: sync. CouchDB replication is really nice for that.

14:56 technomancy: mynomoto: maybe print out (leiningen.core.classpath/get-classpath project) before calling eval-in-project so you can verify?

14:56 * cemerick specializes in finding nasty corner cases, only on heroku :-P

14:56 dnolen: cemerick: feel free to open a ticket w/ stack trace, it might be obvious or it might not.

14:57 cemerick: does heroku AOT?

14:57 SegFaultAX: Apage43: But couch on a mobile device? Ugh. It doesn't seem like you have the CPU nor the memory to do anything more than the most trivial work.

14:57 Apage43: that is: work offline for a bit, edit your local db, then connect up for a short time and sync it with some remote db.

14:57 cemerick: dnolen: good question, I don't recall....(goes to look)

14:57 * gfredericks renames his macro try-let

14:58 Apage43: SegFaultAX: that's why it was silly. The new thing is a much less silly, being a layer over SQLite that implements some of the couchdb functionality.

14:58 ppppaul: try-let sounds sexy

14:58 gist gist gist!

14:59 Raynes: refheap refheap refheap!

14:59 cemerick: dnolen: heh, yeah, it does :-P

14:59 SegFaultAX: Apage43: We built something like that at my last job (mobile games). But were actually storing transformations in the database which would be streamed to the server in blocks when they regained connectivity.

14:59 owengalenjones: anyone using :creds :gpg ever see an EOF error when trying to pull lein deps from an archiva repository?

14:59 SegFaultAX: Apage43: I'm curious, is your implementation open source?

15:00 amalloy: gfredericks: try-let sounds like toilet

15:00 gfredericks: amalloy: phew!

15:00 Apage43: the new one isn't by me, but it's here https://github.com/couchbase/couchbase-lite-ios

15:00 gfredericks: amalloy: for several seconds I thought you were using "toilet" as a generic adjectivish thing to describe something you don't like

15:00 I can imagine tcrayford using the word that way

15:00 amalloy: haha

15:01 that name is *pants*, sir

15:01 Apage43: formerly called TouchDB

15:01 dnolen: cemerick: that's probably the issue

15:01 Apage43: we had to slap branding on it

15:01 SegFaultAX: Apage43: Neat! Thanks.

15:01 dnolen: cemerick: there's a ticket for the AOT problem, would love some help on that one.

15:02 ppppaul: i used to couchdb

15:02 but not couchbase

15:02 they are a bit different

15:03 mynomoto: technomancy: It's in the classpath.

15:06 SegFaultAX: Is it just me or does github /feel/ very different when you're not logged in?

15:07 gideonite: hi i have a noob ring question: i can't seem to get form parameters from a request.

15:07 when (:form-params req) i get a map with strange keys

15:07 which are not symbols

15:07 something like (user foobar) instead of (:user foobar)

15:08 any advice?

15:08 SegFaultAX: gideonite: What middlewares are you using?

15:08 weavejester: gideonite: By default, parameters are strings

15:08 gideonite: should i being using wrap-params?

15:08 weavejester: Parameter keys, I mean, because a parameter name doesn't necessarily conform to what is allowed in a keyword

15:09 For example, foo%20bar=baz translates to {"foo bar" "baz"}

15:09 SegFaultAX: gideonite: Are you using Compojure?

15:09 weavejester: The wrap-keyword-params middleware turns the parameter keys into keywords

15:09 gideonite: i'm actually using pedestal.io

15:10 SegFaultAX: Does pedestal use Compojure?

15:10 weavejester: But wrap-keyword-params only applies to (:params req)

15:10 Pedestal doesn't use Compojure

15:10 SegFaultAX: Bummer.

15:10 weavejester: (:form-params req) will always have strings for keys

15:10 SegFaultAX: gideonite: https://github.com/weavejester/compojure/blob/master/src/compojure/handler.clj <- good example of some reasonable default middlewares.

15:11 weavejester: Presumably gideonite wants to do a lot of async work, which pedestal is designed for

15:11 gideonite: weavejester: right, but it does use ring. right now i'm just trying to set up something simple. ah, so i need to figure out how to get from a map where keys are string

15:11 weavejester: eventually, yes.

15:11 weavejester: gideonite: Try accessing (:params req)

15:12 SegFaultAX: Is it safe to assume that pedestal sets up the common middlewares for you by default?

15:13 gideonite: weavejester: that does work. i now see that my question is really how to get from a map with strings as keys. that's already helpful

15:13 weavejester: gideonite: It's the same as getting from a map with keywords

15:13 gideonite: Well, except that you can't use strings as functions

15:13 SegFaultAX: gideonite: Maps are functions of their keys.

15:14 weavejester: gideonite: So (params "foo") or (get params "foo")

15:14 SegFaultAX: gideonite: Keywords are functions, too. They try and get themselves from their argument.

15:14 gfredericks: dangit try-let is hard to write

15:15 gideonite: boom -- obviously it's get. noob questions! thanks so much

15:15 SegFaultAX: gideonite: Or using the map itself in function position, ##({"foo" 1 "bar" 2} "foo")

15:15 lazybot: ⇒ 1

15:15 gideonite: there's also a function keyword fyi, if you're committed to having keywords

15:17 SegFaultAX: haha, that seems complicated

15:18 SegFaultAX: gideonite: Why?

15:18 gideonite: As I said, maps are functions of their keys. That turns out to be really useful.

15:19 jcromartie: I am OK with putting important runtime state in a var.

15:19 there. I said it

15:19 gfredericks: "keys are functions of their maps" would be a fun terrible feature for a language

15:19 jcromartie: with alter-var-root? or with an atom?

15:20 jcromartie: not quite

15:20 I mean refs in vars

15:20 etc.

15:20 gfredericks: refs in vars in atoms in agents in actors in scala

15:20 jcromartie: yes

15:20 SegFaultAX: gfredericks: That's concurrency done right.

15:20 TimMc: gfredericks: I look forward (with some trepidation) to ##(format "lib-%04d" (rand-int 1e4))

15:20 lazybot: ⇒ "lib-3236"

15:20 TimMc: (regarding keys and maps)

15:21 jcromartie: I think that a core namespace is the right place to bolt down some important things in place and put all the important parts together.

15:21 gfredericks: TimMc: mutable numbers first

15:22 TimMc: I resisted that naming pattern recently

15:25 [tab][tab][tab]: Oh my god this is the best nick.

15:25 SegFaultAX: [tab][tab][tab]: Hah

15:26 TimMc: ...and registered.

15:27 gideonite: SegFaultAX: sorry, you are absolutely right. that's the best thing to do. i guess strings don't evaluate to themselves?

15:27 gfredericks: they do

15:27 (eval "foo") => "foo"

15:28 SegFaultAX: gideonite: Strings always evaluate to themselves.

15:29 TimMc: Strings, keywords, vectors, maps, sets...

15:29 amalloy: they just aren't functions

15:29 gideonite: then why can't i go ("foo" {"foo" "bar"})

15:29 SegFaultAX: gideonite: But they aren't functions. Keywords are and all they do is `get` themselves from their argument.

15:29 amalloy: TimMc: minus vectors, maps, and sets...

15:29 TimMc: amalloy: Eh?

15:29 gideonite: SegFaultAX: got it

15:29 amalloy: the vector [x] clearly does not evaluate to [x]

15:29 gfredericks: being evaluated and being called are different

15:30 gtrak: &(eval 'x)

15:30 lazybot: java.lang.SecurityException: You tripped the alarm! eval is bad!

15:30 TimMc: amalloy: Hmm... fair.

15:30 gtrak: CompilerException java.lang.RuntimeException: Unable to resolve symbol: x in this context, compiling:(NO_SOURCE_PATH:1)

15:30 SegFaultAX: gideonite: I think most people like to use keywords as functions if the maps their dealing with have keyword keys.

15:31 gideonite: Eg (:foo {...}) vs. ({...} :foo)

15:31 Despite them being equivalent

15:31 gtrak: the first will never give an NPE

15:31 SegFaultAX: gideonite: For all other types of keys, you pretty much have to use the map in function position.

15:31 amalloy: meh, i rarely use maps in function position. i usually just use get

15:31 TimMc: ,('foo {'foo 4})

15:31 clojurebot: 4

15:31 TimMc: ^ almost never used

15:32 SegFaultAX: TimMc: Literally never used.

15:32 clojurebot: TimMc: There is a Clojure patch on CLJ-1168 that seems like it should allow Leiningen to work with 1.5.0 and :jvm-opts ["-Dclojure.read.eval=unknown"] http://dev.clojure.org/jira/browse/CLJ-1168

15:32 TimMc: Thanks, bot. Thanks... for nothing.

15:32 nz: what is difference between with-redefs and binding? other than binding works only with vars that are marked ^:dynamic?

15:32 SegFaultAX: TimMc: But it is interesting that keywords are effectively just symbols.

15:32 nz: ,(doc binding)

15:32 clojurebot: "([bindings & body]); binding => var-symbol init-expr Creates new bindings for the (already-existing) vars, with the supplied initial values, executes the exprs in an implicit do, then re-establishes the bindings that existed before. The new bindings are made in parallel (unlike let); all init-exprs are evaluated before the vars are bound to their new values."

15:32 nz: ,(doc with-redefs)

15:32 callen: sometimes I think the bot was coded to be unreliable/weird on purpose.

15:32 clojurebot: "([bindings & body]); binding => var-symbol temp-value-expr Temporarily redefines Vars while executing the body. The temp-value-exprs will be evaluated and each resulting value will replace in parallel the root value of its Var. After the body is executed, the root values of all the Vars will be set back to their old values. These temporary changes will be visible in all threads. Useful for mockin...

15:33 TimMc: nz: The difference is that with-redefs is not thread-safe, alters the root, and should only be found in your test/ directory.

15:33 gfredericks: woah java is getting "default methods" for interfaces

15:34 TimMc: oh what

15:34 SegFaultAX: gfredericks: Oh? How does that make them different from abstracts?

15:34 gfredericks: they're on the interfaces instead of superclasses

15:34 nz: gfredericks: yep, it is so that List etc interfaces can work nicely with lambdas

15:35 SegFaultAX: Soo, Java is getting mixins via default interface methods?

15:35 gideonite: SegFaultAX: so in some sense :a evaluates to #(get % :a). i agree, it's a very nice concept

15:35 gfredericks: I am sitting 15 feet in front of Brian Goetz describing this

15:35 nz: you can add default implementation to interface. that impl is used if the implementing class doesn't implement the metod

15:36 TimMc: The slow slide into multiple inheritance.

15:36 SegFaultAX: TimMc: That's what I was thinking.

15:36 gfredericks: he said "java has always had multiple inheritance for types" and I'm not sure what that meant

15:36 SegFaultAX: TimMc: Very Ruby-esque.

15:36 gfredericks: is that what interfaces are?

15:36 nz: http://www.lambdafaq.org/do-default-methods-introduce-multiple-inheritance-to-java/

15:37 SegFaultAX: gfredericks: Maybe that classes can implement an infinite number of interfaces?

15:37 tieTYT2: can someone help me with this question? http://stackoverflow.com/questions/16199258/how-can-i-pass-in-the-list-of-methods-to-gen-class

15:38 SegFaultAX: nz: Yup

15:38 tieTYT2: I think i'm asking a fundamental clojure question here, not something specific to gen-class

15:38 nz: list.forEach(System.out::println)

15:39 SegFaultAX: nz: Although I never really would have called that multiple inheritance because it carries a slightly different connotation for me than simply implementing any number of interfaces.

15:39 nz: multiple inheritance of behavior

15:40 SegFaultAX: nz: That's what I usually associate with MI, the behavior part. But it's easy to adjust that mental model to include types.

15:41 Still, default methods means that Java can now properly implement the mixin pattern. I guess that's ok?

15:44 tieTYT2: why does this return nil? (macroexpand-1 '(gen-class

15:44 :name com.sandbox.GeneratedClass

15:44 :methods [[hello [] String]]))

15:44 gfredericks: I think gen-class always expands to nil

15:45 nDuff: *nod*.

15:45 tieTYT2: how's that possible?

15:45 gfredericks: it's a side-effecting macro

15:45 tieTYT2: oh so I can't see what it's doing?

15:45 gfredericks: you can read the implementation

15:45 nDuff: tieTYT: It doesn't do anything at all except during ahead-of-time compilation.

15:45 gfredericks: the 7th rule of macro club is don't write side-effecting macros

15:45 tieTYT2: oh right

15:45 ok well I really am stuck with this then

15:46 http://stackoverflow.com/questions/16199258/how-can-i-pass-in-the-list-of-methods-to-gen-class

15:46 amalloy: tieTYT2: that is not a thing it is possible to do

15:46 nor would it be terribly useful if you could

15:46 gfredericks: and java's getting this streaming interface

15:46 tieTYT2: amalloy: ok thanks, at least now I know that.

15:47 SegFaultAX: Wow, gen-class is exceedingly complicated.

15:47 jcromartie: oh snap

15:47 cyclical dependency

15:47 tieTYT2: amalloy: the reason I want to do that is because I want to make a function you use like this: (GET "url" [url] some-body) that will generate a jersey class

15:47 but I want each of those function calls to add a method to the gen-class

15:48 and I can't figure out how to do that a method at a time

15:48 TimMc: jcromartie: Having everything in core?

15:49 *too much

15:49 jcromartie: had something important in a web.core, that was used by web.core.routes.foo

15:49 and vice versa

15:53 gfredericks: I think java just invented reducers?

15:53 jcromartie: foo.bar.baz should not use vars in foo.bar, as a general principal

15:55 beaky: are there progrmaming languages that are better than clojure?

15:55 ppppaul: no

15:56 clojure is best

15:56 SegFaultAX: beaky: Better than Clojure /for what/?

15:56 ppppaul: even for micro computing

15:56 AimHere: beaky > INTERCAL is better than clojure.

15:56 ppppaul: or, micro-codeing

15:56 beaky: ah

15:56 gfredericks: yes: it has been proven that either J or Dart is better than Clojure, but also that it is impossible to determine which one

15:56 this has been called the "J-Dart Indeterminacy Problem"

15:56 ppppaul: J <3

15:57 ivan: if clojure doesn't do what you want, just write a sufficiently smart clojurescript emitter

15:57 beaky: hmm I should look into J

15:57 SegFaultAX: ppppaul: Have you seen Conway's GoL in APL?

15:57 ppppaul: i have

15:57 i was impressed

15:58 callen: beaky: fortran is way better than clojure

15:58 SegFaultAX: Such an excellent video: http://www.youtube.com/watch?v=a9xAKttWgP4

15:58 beaky: but fortran isn't as general-purpose as clojure afaik

15:58 Chousuke: with a sufficiently smart compiler, (can-have? 'pony) returns true and a pony will be delivered shortly

15:59 beaky: it's just a dinosaur language for dinosaur numerical computing libs that have over 6 decades of optimization

15:59 amalloy: Chousuke: i would expect more like a piece of paper with the word pony to arrive

15:59 (can-have? pony) might give you an actual pony

15:59 Chousuke: that may be

15:59 or maybe the compiler is feeling generous and gives you a pony sticker instead

15:59 ppppaul: i want pony

16:00 AimHere: I think if something has 60 years of optimization, then it's going to be pretty damn optimized, and quite likely to be the best at what it does. Therefore Fortran is Best Language

16:00 QED

16:00 patchwork: I do all my computations on abacus

16:00 ppppaul: abacus is best language

16:00 gfredericks: the first language to be invented is necessarily the best

16:00 callen: AimHere: Fortran used to have a performance advantage on C due to design that has since been overcome with vectorization and compiler flags.

16:01 AimHere: advantages that weren't entirely due to "time", keeping in mind that C has had quite a lot of industry dollars dumped into it.

16:01 SegFaultAX: AimHere: Also, quite a lot of math library code is still written in Fortran even today.

16:01 beaky: ah

16:02 TimMc: English is a pretty nifty programming language. Very expressive. However, a sufficiently powerful runtime can be quite expensive.

16:02 callen: TimMc: I hear grad students make good interpreters.

16:03 beaky: is somebody commissioning you to ask questions for a dictionary with definitions composed entirely of IRC logs?

16:03 AimHere: English is just Cobol++

16:03 Apage43: English interpreters tend to be pretty slow, comparatively.

16:04 You can sometimes get one to translate your English to something more computer usable though :)

16:06 TimMc: English is very prone to non-deterministic bugs. For instance, if you issue the same command multiple times, it is likely to stop working.

16:06 guns: Does lazy-seq guarantee safe concurrent access to the next value?

16:06 beaky: I guess all programming languages have a raison d'etre; hence there is no best one

16:06 TimMc: The result is that the more you test a program, the less likely it is to work!

16:06 guns: I found what I thought was an unsynchronized mutation in a deftype on (next)

16:07 Chousuke: english is not a very good programming language

16:07 guns: but the object was wrapped in a lazy-seq and survived hammering from 1000 threads!

16:07 Chousuke: compilation takes months or years, might not terminate, and the end result might or might not correspond to what you mean

16:07 guns: sorry for interleaving the conversation.

16:08 TimMc: guns: You're not the one who should be apologizing. :-P

16:08 Is the code somewhere where we can see it?

16:08 guns: TimMc: If you're interested, I could gist it

16:09 Raynes: &(interleave '[Chousuke TimMc] '[guns Raynes])

16:09 lazybot: ⇒ (Chousuke guns TimMc Raynes)

16:09 Raynes: Sorry for interleaving guys!

16:10 Chousuke: You made me gun TimMc, Raynes

16:10 that is not nice

16:10 Raynes: Nice.

16:12 tbaldridge: guns: yes it does: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LazySeq.java

16:12 notice how sval and seq anre synchronized, thus only one thread can be running those methods on the same object at a time.

16:12 guns: tbaldridge: I took a look at that file, but didn't immediately see an answer to my inquiry

16:13 I guess I should have read closer

16:13 tbaldridge: guns: yeah it's a nasty bit of code.

16:13 guns: tbaldridge: Ah, I see it now. Brilliant

16:14 tbaldridge: that's actually the cool thing about Seqs as opposed to interators or .NET's IEnumerable. running over the same seq 100 times will only actually calculate the seq once.

16:15 guns: I was using a Random and BitSet in my deftype; I thought I would have to lock and clone, but lazy-seq took care of all the details

16:16 tieTYT2: amalloy: i don't understand why you're saying that would not be very useful

16:19 I'm getting the sense clojure is a bad language to build a java-code generator

16:19 Apage43: i once used clojure to generate C. I wish I could stop remembering.

16:20 Raynes: s/clojure/any language/

16:24 tieTYT2: I'm trying to write a clojure DSL to generate Jersey code, but it doesn't seem possible to me since gen-class won't let you pass in a dynamic list of method names

16:26 TimMc: Macros to the "rescue"...

16:26 tieTYT2: a macro that generates a gen-class ?

16:27 I didn't know that was an option

16:27 raek: *sigh* why is the syntax highlighting suddenly gone for me in clojure-mode...

16:29 Raynes: raek: Holy shit. I haven't seen you speak in like a year.

16:29 How are you? Besides your emacs being broken?

16:33 andrew__: this might be a ridiculous question, but what is the difference in terms of java interop between using . and /? for example, I sometimes see ServerSocketChannel/open but on the next line I'll see (InetSocketAddress. "localhost" 5000)

16:33 raek: Raynes: things are good...

16:34 andrew__: are only certain things able to use the / for interop, whereas others must use the . ?

16:34 raek: have been playing with Haskell for some time (and I also have a job nowadays)

16:35 dnolen: andrew__: / for static methods

16:35 raek: andrew__: (Foo/bar) means bar method of Foo class, but (Foo.) means Foo constructor

16:35 andrew__: much appreciated dnolen and raek

16:36 * raek tries to catch up on Clojure again

16:41 iamdrw: greetings. is there a profiler for clojure? because profiling via time makes me go mad

16:42 tcrayford: iamdrw: all the jvm profilers work

16:42 so jvisualvm works (and you prolly already have it installed), yourkit is free if you're open source and mention it on your page, and much better than jvisualvm

16:43 nightfly__: profiling results might be dissapointingly vague if using higher-order functions though

16:43 amalloy: technomancy: how do i force refetching of snapshot dependencies?

16:44 technomancy: amalloy: lein -U deps

16:44 TimMc: iamdrw: If you just want benchmarking of different algorithms, criterium is excellent.

16:44 amalloy: thanks

16:45 iamdrw: criterium seems what I was looking for. Thanx

16:47 amalloy: criterium is great if you want to know how long a particular thing takes; yourkit is more work, but is better if you want to know what is taking so long

16:47 tcrayford: they do different jobs for you ;)

16:49 weavejester: Hmmm… there might be a bug in core.memoize… either that or I'm misreading this stacktrace

16:49 amalloy: weavejester: core.memoize and core.cache both do a big pile of reflection for no particular reason. i'd consider that a bug, in libraries designed to improve performance

16:51 weavejester: I get this interesting stacktrace, which looks like a race condition: https://gist.github.com/weavejester/60a0a0bf334af85ffdfe

16:53 amalloy: ,@nil

16:53 clojurebot: #<NullPointerException java.lang.NullPointerException>

16:53 amalloy: funny that it thinks that's a Future, but whatever

16:54 weavejester: I think that's the last type of deref it tries...

16:54 hiredman: because deref now works on non-clojure created java futures

16:54 yet another hand rolled protocol

16:55 cemerick: dnolen_: yeah, it was AOT. I'll see if I can track it down. Hopefully I can be 1/3 with core.match issues. :-P

16:55 dnolen_: cemerick: :)

16:57 weavejester: It would seem to imply that (swap! cache through* f args) is returning nil for some reason

16:58 Which implies clojure.core.cache/through is...

16:58 I'm not seeing how that's possible, however...

16:59 dnolen_: iamdrw: I recommend YourKit, criterium appears nice for only high level benchmarking

16:59 er profiling

16:59 amalloy: weavejester: of course it's possible: cache is a protocol, and you can implement it so that every function returns nil

17:00 weavejester: amalloy: Yeah, but all the functions in the TTLCache seem to return not-nil

17:03 mikerod: When someone was learning Clojure the other day, they posted the question "so what's the "right" thing to do other than the giant, procedural let block?" I didn't have a good answer or a good reference. However, I feel there is much more to programming in Clojure than a "big procedural let block." Hmm.

17:04 I've been puzzling over what to say to this.

17:04 bbloom: depends on the problem at hand

17:04 but generally the answer is more functions....

17:05 mikerod: Yeah, I think it was a question directed at what does the functional paradigm offer over the "big procedural let block" perhaps.

17:05 More functions is appropriate I'd say. :P

17:05 bbloom: it's very common to see a (-> pipeline of step functions like this) where you thread a {:map "of" :keys "like" :this "through"}

17:05 technomancy: what does being in a let block have to do with being procedural?

17:06 bbloom: technomancy: i assume he means that he is shadowing names for each incremental "change"

17:06 mikerod: I don't think of them as coupled.

17:06 technomancy: bbloom: hm; that's a strange use of the word procedural

17:07 bbloom: technomancy: i agree, but i've seen quite a few people new to functional programming use single static assignment in a way that feels like a throwback to some C code

17:07 mikerod: I agree it was an open ended question and over generalized. I think bbloom had the right description with "shadowing names for each incremental change".

17:07 technomancy: I don't think there's anything wrong with shadowing names for each change if it's a case where -> is not suitable for argument order reasons

17:08 that pattern alone does not make code procedural

17:08 bbloom: i agree with technomancy, but i'll add that after a small handful of let bindings & your function gets too big, it is a code smell

17:09 technomancy: right; but function size is orthogonal to let-rebinding

17:09 well, they may be correlated, I guess

17:09 pjstadig: correlation is orthogonal!

17:09 bbloom: technomancy: forgive me for jumping to conclusions, but mikerod seems to have suggested that i read his & his colleagues' minds... :-)

17:10 mikerod: So more functions obviously gives you more abstraction, modularity, reuse, comprehensibility, etc.

17:10 bbloom: mikerod: it's also just easier to work with if you stick some stuff in a map b/c you can print it out

17:10 mikerod: bbloom: I don't agree with the question I posted, I just have had a hard time formulating an appropriate response.

17:11 bbloom: mikerod: yeah, it's hard to teach someone a new way of thinking

17:11 mikerod: bbloom: Indeed. I appreciate your feedback on it too.

17:14 Raynes: guns: Oh, you're the vim-clojure-static guy.

17:14 guns: I commend you on your efforts good sir.

17:17 seancorfield: just saw the discussion about clj-time... i inherited it and am not particularly attached to the names in it... that said, introducing 'second' would cause many users of clj-time to see the ugly "warning ... name already bound to ..." message on :use or :refer :all ... which is how most code uses it i suspect

17:17 gfredericks: seancorfield: I think most of our usages of clj-time are :as or :refer [...]

17:18 seancorfield: but it wouldn't be the only library that shadows a core function and folks know how to get around it...

17:18 gfredericks: mostly on principle of avoiding :use/:all

17:18 seancorfield: gfredericks: you could well be right

17:18 and the docs could make it clear too

17:18 gfredericks: seancorfield: just piping up with a data point

17:18 seancorfield: clojure.java.jdbc has shadowed resultset-seq for a long time, for example

17:19 TimMc: seancorfield: Maybe that's a good reason to call it "second" -- fewer people using :use.

17:19 seancorfield: (but core/resultset-seq is a silly place for that function!)

17:19 TimMc: heh, yeah, strong encouragement to change their ways :)

17:20 feel free to create an issue https://github.com/clj-time/clj-time/issues (when github comes back up :)

17:21 Raynes: seancorfield: If that's how most code uses it then that code is wrong and needs to be changed anyways.

17:27 seancorfield: "most code is wrong" -- Raynes, April 2013 :)

17:27 i agree, btw

17:28 Raynes: seancorfield: I'm writing an issue.

17:29 https://github.com/clj-time/clj-time/issues/70

17:32 seancorfield: thank you sir!

17:41 Raynes: seancorfield: https://twitter.com/mikeflynn_/status/327175064644628481

17:43 patchwork: Is *worst* a dynamic var there?

17:45 Anyone use morph for modeling global state? https://github.com/blancas/morph/wiki/Modeling-Global-Data

17:45 I am looking at it as an alternative to having a dynamic var for configuration

17:45 might be more trouble than it's worth

17:46 I like the idea of having pure functions access global values without passing config vars everywhere though

17:47 TimMc: Raynes: I wonder how much of that is just "time is hard" and the guy thinks it is clj-time's fault.

17:47 Raynes: TimMc: All of it I'd wager.

17:51 seancorfield: i replied on twitter suggesting he open issues with improvement ideas

17:51 a lot of ppl are quick to criticize but slow to actually suggest concrete improvements

17:52 joegallo: well, it's easy to take potshots from the peanut gallery, much harder to climb down and start working ;)

17:54 TimMc: You can't really file a proper (design) bug report in 140 characters, but if you file a github issue you don't get to be ranty in front of your friends, and we can't have *that*.

17:58 rasmusto: why does this behave differently at the repl and when doing 'lein run'?: (map (comp #(.exists %) as-file) ["." "target" "/tmp" "fjoewifj"]) ; (I only get false when doing lein run)

17:58 callen: Raynes: I +1'd your issue.

17:59 Raynes: WITH RUV

17:59 Raynes: callen: Good on ye, sir.

18:01 seancorfield: callen: changing everything to plurals would be kinda disruptive to existing users... and i think there are already some singular and plural versions of the same thing?

18:01 i'll have to go dig into the API when i get to that

18:02 Raynes: tpope: It'd be cool if I could pass a commit message to :Gcommit somehow.

18:03 callen: seancorfield: I'm open to superior alternatives that don't rest on "don't fix things"

18:03 Raynes: tpope: It'd be useful for quick commits with short messages.

18:03 callen: seancorfield: you could have a migration period where using the old names pukes a warning and lets them know the next semver compliant version will get rid of the old names.

18:04 SegFaultAX: Raynes: But if you're already in the editor, what does that actually buy you?

18:05 Raynes: SegFaultAX: About 4 keystrokes.

18:05 rasmusto: hey Raynes, can I bounce a fugitive+fireplace idea/pull req off of you?

18:05 SegFaultAX: i:wq is too much?

18:05 Raynes: SegFaultAX: Yes.

18:05 SegFaultAX: I guess i<esc>:wq

18:05 Raynes: rasmusto: Sure, but I have nothing to do with either of those projects.

18:05 rasmusto: I'm wondering if I should submit a pull request for this: https://github.com/rasmusto/vim-fireplace/commit/f8ae7c429aaa4a6375dbbade239b5f1b82538506

18:06 Raynes: I'm just curious if anyone would use it

18:06 Raynes: I don't think I use fugitive nearly well enough for this to be useful to me in particular, but that doesn't mean it isn't good.

18:07 rasmusto: It lets you use cpp when inside of a :Gdiff window, so you can throw old code at the REPL

18:07 Raynes: That sounds totally useful.

18:07 You should run it by tpope.

18:07 rasmusto: I've pinged him a few times, which is why I was wondering about just making an issue/preq

18:07 Raynes: Yeah, that's best. He isn't around particularly often.

18:08 rasmusto: kk

18:19 rocco`: can someone help me with something

18:19 TimMc: rocco`: Just go ahead and ask your question; if someone can help they will answer.

18:20 rocco`: I'm running a repl in emacs and I'd like for a function running in a different thread to print into the repl

18:21 right now I have no idea where it prints because I don't understand the *in* and *out* streams

18:23 TimMc: Oh, that can be tricky. I remember something about nREPL binding a new *out* for each new entry, too.

18:24 rocco`: what would be the preferred way to do it?

18:27 technomancy: use bound-fn for your thread maybe

18:29 TimMc: rocco`: Oh right, how are you starting that thread?

18:30 rocco`: using the java Thread start

18:30 should I use clojure abstractions instead?

18:31 I'm just learning this

18:31 I'm trying to run a socket server with server-socket from the old contrib

18:31 and I want it to speak to me :)

18:37 whinub: Hey guys, I'm pretty new to clojure but I was wondering if anyone could recommend a decent sized program / project with good documentation that I could read through and learn from.

18:38 rocco`: whinub: how about the clojure implementation itself?

18:40 TimMc: The Clojure implementation breaks all the Clojure dev rules. :-/

18:40 technomancy: that's not a very good way to learn

18:40 TimMc: Leiningen is pretty nice.

18:40 technomancy: TimMc: as long as you skip the profile merge stuff =)

18:41 beppu: rocco`: this one is relatively small and is well documented. https://github.com/Engelberg/instaparse

18:42 (that last one was for whinhub)

18:42 rocco`: :)

18:43 whinub: Thanks for the suggestions guys, will definitely be checking them out.

18:43 rocco`: I'm also going to check it out

18:44 TimMc: rocco`: clojure.core/future and other multi-threaded constructs generally convey bindings such as *out* to the new thread.

18:46 rocco`: makes sense

18:46 will try

18:55 there's something about lein I don't understand

18:56 is running a lein repl the same as doing a jack-in

18:56 callen: whinub: web app?

18:56 rocco`: no just ordinary app

18:56 callen: rocco`: I wasn't talking to you.

18:57 whinub: do you want to see what a clojure web app looks like?

19:01 technomancy: rocco`: jack-in is just `lein repl :headless` plus connecting an elisp client to it

19:02 SegFaultAX: whinub: If so, refheap and 4clojure are both open source.

19:02 technomancy: as is clojars

19:03 tpope: Raynes: :Gcommit -m works

19:04 Raynes: tpope: Of course it does. Because you're tpope. I should have just known.

19:23 bingo: Any one has experience installing with brew install leiningen 2.1.3 in mac osx?

19:23 Raynes: Meh, don't bother.

19:23 amalloy: don't use brew

19:23 Raynes: Just install via the shell script.

19:23 technomancy: homebrew is kind of silly

19:23 Raynes: Don't use a package manager for anything related to Clojure ever.

19:23 bingo: oh i see.

19:23 Raynes: technomancy: It's perfectly fine for other things, but it's silly for this and Clojure in general.

19:23 * amalloy wonders how Raynes got his jvm installed

19:23 technomancy: Raynes: I disagree

19:24 Raynes: amalloy: OS X comes with a JVM iirc.

19:24 technomancy: What package manager would you propose I use?

19:24 None at all?

19:24 whinub: callen: Hey sorry about delay went to cook some dinner. Taking a look at a web app would be awesome. What do you recommend?

19:24 Raynes: I kind of need one.

19:24 technomancy: Raynes: apt-get or nix

19:24 amalloy: technomancy: brew is silly, but it's better than the alternatives on osx

19:24 Raynes: And this is the least shitty of all of them.

19:24 technomancy: I don't know of any other good ones

19:24 Raynes: technomancy: I need one that's actually useful.

19:24 technomancy: amalloy: I don't dispute that

19:25 Raynes: Nix is great and all, but I have things to do besides making packages for everything I ever use.

19:25 bbloom: brew has been 1) fast 2) (generally) up-to-date and 3) not-horribly-broken... which is not something that can be said for any other OSX package manager

19:25 Raynes: My only problem with brew is that at least 70% of the packages I've ever tried to install would break while installing in one way or another.

19:25 Fortunately they fix these problems relatively fast.

19:26 * technomancy blinks

19:26 bingo: Well any way, I have been struggle of trying to run lein but it is complaining of depencies. I was running lein deps, and i still havin ghte same issue.

19:26 Raynes: (70% is an exaggeration)

19:26 bbloom: Raynes: clearly.

19:26 technomancy: stockholm syndrome much?

19:26 bbloom: meanwhile, plan 9 namespaces would dramatically simplify every package manager ever.

19:27 pjstadig: my only problem with driving on the road is that 70% if the time i die on the way to my destination

19:27 technomancy: pjstadig: other than that, the weinermobile is a great form of transportation

19:28 Raynes: But fortunately the paramedics resuscitate you relatively fast?

19:28 technomancy: it's aerodynamic and stuff

19:28 Raynes: Not sure if that metaphor goes all the way here.

19:29 pjstadig: (it was an exaggeration)

19:29 Raynes: Touché.

19:31 patchwork: 70% of all exaggerations result in developer death

19:31 bbloom: i myself has died literally thousands of times

19:37 weavejester: I think I've figured out why core.memoize/memo-ttl occassionally excepts

19:37 Unfortunately I'll need to use JIRA to report it *sigh*

19:40 amalloy: weavejester: send fogus an email, and maybe he'll fix it for you in secret

19:40 rationalrevolt: ,(let [o '+] (o 1 2))

19:40 clojurebot: 2

19:40 weavejester: amalloy: I think I might raise it on clojure-dev first. I'd like a second opinion or two

19:40 rationalrevolt: am i not doing this right?

19:40 Bronsa: I still don't understand what's preventing contrib libraries from using github issues

19:41 amalloy: rationalrevolt: '+ is a symbol, not the addition function

19:41 + is the addition function

19:41 patchwork: ,(let [o +] (o 1 2))

19:41 clojurebot: 3

19:41 weavejester: Do symbols act as functions to maps, the same as keywords?

19:41 amalloy: yesz

19:42 weavejester: ,('+ {'+ 2})

19:42 clojurebot: 2

19:42 weavejester: ,('+ {'+ 2} :not-found)

19:42 clojurebot: 2

19:42 weavejester: ,('+ {'+ 3} :not-found)

19:42 clojurebot: 3

19:42 weavejester: ,('+ 3 :not-found)

19:42 clojurebot: :not-found

19:42 weavejester: Just checking :)

19:43 rationalrevolt: So yep, ('+ 1 2) is the same as (get 1 '+ 2)

19:44 rationalrevolt: It tries to lookup a key '+ on 1, but since 1 isn't a map it fails and returns the failure result, which has been set to 2.

19:44 amalloy: i thought that was supposed to throw an exception in 1.5 now

19:44 looking things up in a non-map

19:44 weavejester: ,*clojure-version*

19:44 clojurebot: {:major 1, :minor 5, :incremental 0, :qualifier "RC6"}

19:44 amalloy: ,(contains? 4 3)

19:44 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: contains? not supported on type: java.lang.Long>

19:44 amalloy: ,(get 4 3)

19:44 clojurebot: nil

19:44 amalloy: apparently it's just the contains? check, not get

19:45 Bronsa: amalloy: the get patch didn't get into 1.5 afaik

19:47 rationalrevolt: thanks weavejester

20:01 bingo: Hi Anyone, I would like to get someone who has experience install leiningen on mac osx 10.8.2

20:02 amalloy: https://github.com/technomancy/leiningen/blob/master/README.md#installation

20:02 bingo: let me try again.

20:16 bttf: why can't i :use two different namespaces that have the same method defined ?

20:16 all calls to that method are explicity dereferenced to their respective namespace

20:17 amalloy: bttf: you want require, not use. use is explicitly for non-aliased names

20:18 bttf: amalloy: but can i require without aliasing ?

20:19 wait what is the aliasing part ... (require foo.bar as bar) or (require foo) so that i only have to type bar

20:19 (require foo.bar :as bar)

20:20 Bronsa: (require '[foo.bar :as bar])

20:20 or (ns .. (:require [foo.bar :as bar]))

20:20 bttf: oh right

20:22 ok seems i was confused about require

20:24 mynomoto: technomancy: I did the fun project of find repetitions in code. But still no luck turning it into a lein plugin. And it was not that fun :) https://github.com/mynomoto/lein-repetition

20:26 If someone knows how to make this works as a lein plugin I'd be glad. Can't require the project namespace.

20:26 technomancy: huh, why do you need it to be a lein plugin

20:26 ?

20:28 err--why do you need to cross the boundary between leiningen and the project?

20:28 can't you do it exclusively through static analysis?

20:29 mynomoto: technomancy: Doesn't need, just trying to learn something new.

20:30 technomancy: sure

20:30 mynomoto: It needs to know if a var is bounded in the ns or it will make it generic.

20:30 technomancy: oh, ok

20:31 I guess you can't assume all vars are created by def or defn because of macroexpansion

20:31 it looks like you're trying to require plugin namespaces from inside eval-in-project though; that's probably where it's breaking

20:32 you can only require things from :dependencies

20:32 mynomoto: technomancy: But I can change the project dependencies right?

20:33 Or could put everything in one file...

20:33 technomancy: mynomoto: you could add to :dependencies but that can get hairy when profiles come into play

20:34 if you can run everything inside the project process it's simpler

20:34 just say "add this to :dependencies and then run lein run -m repetition.finder" or something

20:34 or if the code to be run in the project isn't that big you could build it up as one big form like `lein test` does

20:35 but that gets unmanageable once you have more than a page or so

20:36 mynomoto: Ok, I will try the lein run way. Thanks.

21:01 rocco``: is there a way to access a thread if you deleted the reference to it

21:01 I mean a function that's running in that thread

Logging service provided by n01se.net