#clojure log - Mar 02 2012

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

0:02 hugod: choffstein: you have a require for com.newfoundresearch.ttm09.data in each test namespace?

0:02 choffstein: yep

0:02 Oh, probably because I am 'using' in the test namespace with a :reload? I wonder if I qualify the namespaces if the import won't clash

0:02 hugod: with :reload or :reload-all? those don't tend to work well with defrecords

0:03 each time a defrecord is evaled, it generates a new class

0:03 choffstein: Ah, gotcha. Thanks.

0:04 Eventually I'll learn all these little things

0:04 hugod: I think that gets everyone on their first foray into records and protocols

2:07 tsdh: Is there a better way to check if a Var is a protocol than testing if its value is a map with keys (:on-interface :on :sigs :var :method-map :method-builders)?

3:18 zawzey: Hi, there's a macro i'm trying to use, which does a "def foobar xyz" internally. But I want to be able to pass the foobar macro variable as a string, instead of as a symbol. How can I do this?

3:18 accel: My needs: convert a Graphics2D to a SVG. Is Apache Batik the way to go? (I'm surprised Java doesn't have a builtin library.)

3:22 AimHere: zawzey, you tried (symbol "abcde") ?

3:22 zawzey: AimHere: yes, it fails with ava.lang.RuntimeException: First argument to def must be a Symbol

3:23 raek: zawzey: are you sure you are not executing the def in the macro body, rather than returning code that contains the def?

3:25 zawzey: eg: defmacro setvar [input val] `(def ~input ~val))

3:26 (setvar foobar 3) works

3:26 but (setvar (symbol "foobar") 3) doesn't

3:27 raek: zawzey: sounds like you want to use the intern function instead

3:27 tsdh: zawzey: Because a macro doesn't eval its args.

3:27 AimHere: (defmacro wibble [s] (let [f (symbol s)] `(def ~f "Garble"))) worked for me

3:27 zawzey: tsdh: yeah, i was reading about the intern functiona s well

3:27 tsdh: zawzey: Your macro expands into (def (symbol "foobar") 3) which is not valid.

3:28 zawzey: tsdh: well it's not my macro, it's some lib's macro, i guess i'd have to re-write it..

3:29 or a wrapper around that as what AimHere suggested

3:30 tsdh: Speaking of the name setvar, I don't think it's a good idea anyway.

3:30 zawzey: tsdh: i know, that's just a simple example ;)

3:31 tsdh: ok

3:33 Can anyone provide an example of how to use `extenders'?

3:34 For me all of (extenders MyProt), (extenders 'MyProt), (extenders #'MyProt) return nil, although I have a deftype that extends the protocol.

3:36 Hm, checking the code, it just does (:impls prot), but none of my protocols has such a key...

3:41 (extends? MyProt MyType) works though, because that tries implements? first before falling back to :impls.

5:35 ljos: Hi - is there no exponent fuction in the standard library or am I blind?

5:36 amalloy: &(Math/pow 2 5)

5:36 lazybot: ⇒ 32.0

5:36 amalloy: &(apply * (repeat 5 2))

5:36 lazybot: ⇒ 32

5:38 babilen: ljos: ... or use numeric-tower's expt function.

5:38 ljos: I was just not expecting to have to call a seperate library. But ok. This works.

6:39 Wraithan: I'm having trouble with clj-redis. I've read the code, and am pretty sure I am using it correctly but still nothing. I am calling (init :url "redis://localhost:6380") but it is connecting to my redis instance that is running on port 6379. From what I understand of the code (and running snippets of it myself in SLIME) this should work.

6:50 bsteuber: -

7:10 beardmigration: Can anyone help me with emacs and slime configuration? Tearing my remaining hair out here.

7:10 vijaykiran: beardmigration: what's the problem ?

7:11 I use slime/emacs - so I *might* be alble to help

7:12 beardmigration: I get a stack dump starting with:

7:12 Exception in thread "main" java.lang.Exception: No such var: util/universal-path (jack_in.clj:27)

7:12 at clojure.lang.Compiler.analyze(Compiler.java:5205)

7:12

7:12 when I try M-x clojure-jack-in

7:13 This is within a lein project.

7:13 lein swank seems to start up when I run it.

7:13 vijaykiran: can you start lein swank separately and attach slime-con ?

7:14 beardmigration: Last time I tried no - different error - let me try again an report. Thanks vijaykiran.

7:17 "open-network-stream: make client process failed: connection refused, :name, SLIME Lisp, :buffer, nil, :host, 127.0.0.1, :service, 4005, :nowait, nil"

7:17

7:17 babilen: beardmigration: I would also recommend to tell us more about your setup and in particular how you installed lein/swank/... -- I assume that you used "lein plugin install swank-clojure 1.4.0", but that might not be the case. (cf. https://github.com/technomancy/swank-clojure)

7:18 beardmigration: Yes correct babilen.

7:19 The lib directory of the lein project has swank-clojure-1.4.0.jar in it.

7:19 vijaykiran: I have swank-clojure-1.3.4 in my ~/.lein/plugins and from a new project I "lein swank" and in emacs I use M-x slime-connect

7:19 beardmigration: Is 1.4.0 not recommended then?

7:20 I'm on emacs-snapshot & debian.

7:20 vijaykiran: I don't know - I've been happily using 1.3.4 and never bothered to upgrade.

7:20 babilen: beardmigration: I would also check if you have any related elpa packages installed (in particular clojure-mode) and the versions of those packages. It works fine here with 1.3.4, but I'll give 1.4.0 a shot in a second.

7:20 * vijaykiran uses GNU Emacs 24.0.93.1 on mac

7:21 vijaykiran: let me try with 1.4.0 plugin as well.

7:21 beardmigration: My ./lein/plugins has swank-clojure-1.3.4.jar in it. Which has precedence - that or the one in the local project?

7:21 babilen: Works fine here -- beardmigration: how did you install lein and which elpa packages do you have installed? Something else in ~/.lein/plugins/ ?

7:22 beardmigration: You don't need a local installation -- I would recommend to install 1.4.0 globally (i.e. with "lein plugin install swank-clojure 1.4.0") -- Didn't you say that you did follow the instructions?

7:23 vijaykiran: 1.4.0 plugin works too

7:23 beardmigration: OK babilen - I'll give that a go.

7:23 babilen: beardmigration: I am a bit confused why you have 1.3.4 if you ran "lein plugin install swank-clojure 1.4.0" and even more confused how you ended up with an installation in a local project.

7:25 * babilen recommends to get rid of the dev-dependency (or how did you install 1.4.0?) and to run "lein plugin uninstall swank-clojure 1.3.4 ; lein plugin install swank-clojure 1.4.0"

7:25 babilen: beardmigration: Which OS are you using and how did you install leiningen?

7:25 vijaykiran: he said, emacs-snapshot on debian

7:26 babilen: vijaykiran: That wouldn't install leiningen :)

7:26 beardmigration: OK my .lein/plugins now has 1.4.0

7:26 I'll give it a go.

7:26 vijaykiran: remove dev dependency in your project.clj too :)

7:26 beardmigration: @vijaykiran - good point.

7:27 babilen: (run "lein deps" and make sure that the local install is gone)

7:29 beardmigration: Which Debian release? (Just asking, because it would make me really happy if you would use my Debian packages. That would give you, among other things, bash-completion for lein commands ;)

7:30 beardmigration: mint-lmde actually

7:31 debian testing

7:31 in effect

7:32 I'd be happy to use your releases babilen - where would I find them?

7:33 babilen: beardmigration: My packages are in Debian testing/unstable -- http://packages.debian.org/sid/leiningen -- No idea which version is in mint.

7:33 beardmigration: so I can start again with lein and try an apt-get etc.?

7:35 babilen: beardmigration: I am note sure how well those packages integrate into mint (and it looks as mint doesn't have them) -- Is clojure-jack-in working now?

7:36 clgv: is there any difference between: (let [k (first group-keys)] (fn [row] (get row k))) and (fn [row] (get row (first group-keys)))?

7:37 beardmigration: UNfortunately not slime-connect gives:

7:37 or: Not connected.

7:37 Connecting to Swank on port 4005..

7:37 error in process filter: slime-intern-indentation-spec: Wrong type argument: listp, 1

7:37 error in process filter: Wrong type argument: listp, 1

7:37 error in process filter: slime-intern-indentation-spec: Wrong type argument: listp, 0

7:37 error in process filter: Wrong type argument: listp, 0

7:38 error in process filter: or: Can't find suitable coding-system

7:38 error in process filter: Can't find suitable coding-system

7:38 mouse-minibuffer-check: Minibuffer window is not active

7:39 raek: beardmigration: be sure to not have any other installations of slime, "slime-clj", or ritz

7:39 beardmigration: and clojure-jack-in gives me a exited abnormally with -1

7:39 raek: *be sure to not have them installed at all

7:39 beardmigration: OK - I'll just check packages.

7:40 raek: make sure you don't have it through apt too

7:40 then, restart emacs

7:40 Wraithan: Nvm my question earlier, noob clojure mistake.

7:40 raek: swank-clojure comes bundled with a version of slime that works for it

7:40 beardmigration: No slime-clj is not installed

7:40 raek: and clojure-mode loads that one

7:40 beardmigration: and no slime?

7:41 beardmigration: checking...

7:41 the man says slime is an unistalled package.

7:41 raek: if you want to use clojure-jack-in, the simplest way is to make sure slime isn't installed at all

7:41 beardmigration: Folks there are so many versions of the definitive guide to emacs and clojure - which is currently definitive?

7:42 Or is that an indelicate question.

7:42 raek: beardmigration: the swank-clojure docs

7:42 babilen: beardmigration: Also restart emacs and paste a list of *all* elpa packages that you have installed to a pastebin of your choice along with "ls -l ~/.lein/plugins/"

7:42 beardmigration: I may have a go on a slightly more virginal laptop.

7:42 babilen: beardmigration: You want https://github.com/technomancy/swank-clojure (or the README there) and nothing else.

7:42 Wraithan: Or have SLIME configured correctly. I do both CL and clojure and clojure-jack-in works just fine for me, as well as when I use SLIME for CL

7:42 raek: beardmigration: also paste the contents of your ~/.lein/plugins dir

7:45 beardmigration: ls ~/.lein/plugins

7:45 lein-swank-1.4.1.jar swank-clojure-1.4.0.jar

7:45 So the packages on marmalade should be good?

7:46 babilen: beardmigration: Yes -- Could you try without lein-swank please? (lein-swank has been deprecated in favour of swank-clojure)

7:47 beardmigration: how do I call swank-clojure?

7:48 raek: lein swank

7:48 that functionality has been in swank-clojure for a long while

7:48 beardmigration: Check - that's what I've been doing.

7:48 raek: the lein-swank plugin probably cause problems

7:48 babilen: beardmigration: Have you removed lein-swank 1.4.1? Is it working now?

7:49 beardmigration: just a mo..

7:49 raek: beardmigration: so, for the most minimal setup you only need: 1) *one* version of swank-clojure installed as a plugin (no other version, and no :dev-dependencies) and 2) a recent clojure-mode.el in emacs

7:49 babilen: beardmigration: Just out of interest: It looks as if you followed outdated instructions on how to setup your environment. Where did you find them?

7:50 beardmigration: reddit.us...erm he has two posts.

7:50 I followed the more up to date.

7:50 raek: hehe, this one? :-) http://riddell.us/ClojureSwankLeiningenWithEmacsOnLinux.html

7:51 babilen: argh! reddit.us *really* needs a much lower ranking on google

7:51 beardmigration: That's the one.

7:51 babilen: *sigh*

7:51 beardmigration: A sucker born every day...

7:51 Still I know now.

7:51 raek: I think the original version of it predates leiningen

7:51 so it's *that* old

7:51 beardmigration: Erm now slime-connect whinges about coding

7:51 babilen: err -- riddell.us :-D

7:51 lazybot: The riddell.us tutorials are much more highly-ranked on Google than they deserve to be. They're old and way too complicated. If you're trying to install Clojure...don't! Instead, install Leiningen (https://github.com/technomancy/leiningen/tree/stable) and let it manage Clojure for you.:-D

7:51 babilen: lazybot: shush

7:52 beardmigration: Ah - sounds like I've got a certain amount of unpicking to do.

7:52 Well it will make my emacs init.el a darn sight shorter...

7:53 raek: beardmigration: the clojure-jack-in method doesn't use an installed version of slime at all. if you can run slime-connect then you obviously have some version of slime installed

7:54 if you end up using the slime-connect method, be sure to have (setq slime-net-coding-system 'utf-8-unix) somewhere

7:54 or otherwise slime will crash if you use non-ascii chars

7:54 (clojure-jack-in takes care of this automatically)

7:55 beardmigration: Different error now but still no C-x C-e goodness.

7:55 Right I'm going to tear down, use the clojure-mode in marmalade.

7:55 And just use lein to manage clojure.

7:55 babilen: beardmigration: How did you "manage" clojure until now?

7:56 ah ... riddell.us -- Yeah, essentially undo whatever is mentioned in there.

7:56 lazybot: The riddell.us tutorials are much more highly-ranked on Google than they deserve to be. They're old and way too complicated. If you're trying to install Clojure...don't! Instead, install Leiningen (https://github.com/technomancy/leiningen/tree/stable) and let it manage Clojure for you.there.

7:56 beardmigration: Might even try the version of lein the those @babilen repositories

7:57 I downloaded and put it in my path I think. It's all beginning to be a bit of blur. Must unpick and keep better notes this time.

7:57 Thanks all. Is there anyting else you recommend?

7:57 raek: chekc with lein version

7:57 1.7.0 is the latest stable one, I think

7:58 babilen: beardmigration: I have *no* idea how well they integrate into LMDE as they also depend on clojure packages that might not be in LMDE. Ask in #linuxmint-help on irc.spotchat.org about that. (Or install pure Debian and I talk you through it in #debian) -- The standalone leiningen installation should work just fine though, but provides less integration with the complete system. (e.g. no bash-completion, no docs in /usr/share/docs/, ...)

7:59 beardmigration: I should install pure debian after mint's shenanigens - just time is limited and mint is working well in the main.

8:05 How does this look for debs on LDME:

8:05 sudo apt-cache show leiningen

8:05 Package: leiningen

8:05 Version: 1.6.1-1

8:05 Installed-Size: 1280

8:05 Maintainer: Debian Java Maintainers <pkg-java-maintainers@lists.alioth.debian.org>

8:05 Architecture: all

8:06 Depends: ant, clojure1.2, libbackport-util-concurrent-java, libclassworlds-java, libclucy-clojure, libjaxp1.3-java, liblucene2-java, libmaven-ant-tasks-java, libmaven2-core-java, libplexus-container-default-java, libplexus-interpolation-java, libplexus-utils-java, librobert-hooke-clojure, libwagon-java, openjdk-6-jre | openjdk-7-jre | sun-java6-jre

8:06 Recommends: rlwrap, clojure-contrib (>= 1.2.0)b

8:07 babilen: beardmigration: That is an old version of leiningen -- I packaged 1.7.0 some time ago

8:09 beardmigration: I would recommend to install leiningen via "lein self-install" for now as I have absolutely no idea if you can use my packages on LMDE

8:10 beardmigration: OK - although I can't see anything that's going to bork immediately in your dependencies.

8:11 They seem to be there in mint.

8:11 babilen: beardmigration: Use http://packages.debian.org/sid/leiningen (but you may keep the pieces if it breaks)

8:12 beardmigration: I will arrange them in the growing work-in-progress that I'm giving the working title of 'trying to execute my first clojure s-exp'.

8:13 actually I've already done that - it's the emacs bit that I want.

8:13 BTW does clojure-mode do auto-completion or anything like?

8:14 llasram: beardmigration: clojure-mode doesn't, but ac-slime does

9:55 choffstein: Is there a way to perform a map over a transient vector without making it persistent first?

9:57 stuartsierra: choffstein: I don't think so. Transients are only useful for building up a structure.

9:57 RickInGA: do any of the Clojure books talk about transients?

9:58 stuartsierra: RickInGA: Mine does, briefly. ;)

9:58 sadger: hello! have a problem loading contrib.repl-utils into my namespace it cant seem to find it when i do (use 'clojure.contrib.repl-utils) im using the nailgun server for vim and yes the jar is on my classpath

9:58 RickInGA: cool, I will check it out!

9:58 vijaykiran: Guys, how can I debug/fix "NoSuchMethodError clojure.lang.Numbers.lt(II)Z clojure.data.json/write-json-string (json.clj:208)" ?

9:58 choffstein: stuartsierra: Maybe I can do a deep copy of the transient?

9:59 vijaykiran: It is coming from a lib I'm usin .. anyone has any pointers ?

9:59 stuartsierra: RickInGA: Full disclosure: it's in a chapter on "Performance" which is somewhat obsolete as of Clojure 1.3

9:59 choffstein: I don't understand. But my guess is no.

10:01 choffstein: stuartsierra: well, I have a transient vector that I want to alter, but I need to use the data in the transient vector to figure out how to update it.

10:01 so the update function is dependent on the internal data

10:03 stuartsierra: choffstein: Usually the problem with transients is that you're trying to use them differently from persistent data structures. Try writing your function with persistent data structures first.

10:03 choffstein: stuartsierra: I already wrote it with persistent data structures and now I am trying to make them transient :)

10:03 stuartsierra: ok

10:03 Kototama: hi, is there a way to specify which URL 'lein ring server' opens?

10:03 stuartsierra: sorry, I'm out of advice :)

10:04 Kototama: i changed the root with the context macro and i would like lein ring server to start at /mycontextpath instead of /

10:12 clgv: choffstein: since vectors are random access data structure and random accesses are possible on transient vectors you can define a map on transient vectors via (defn map-tv [f v] (map #(f (v %)) (range (count v))))

10:12 but the question that remains - do you *really* want to?

10:27 choffstein: clgv: Awesome. Thanks!

10:28 stuartsierra: At that point you've probably lost any performance benefit you were getting from using transients in the first place.

10:31 clgv: stuartsierra: probably.

10:33 napping: would that be any different from (defn map-tv [f v] (map #(f (v %)) (range (count v))))

10:33 would that be any different from (defn map-tv [f v] (map f (persistent! v))), rather

10:34 clgv: napping: yes. he couldnt continue using 'conj! on v

10:35 napping: but I dont know whether it's worth it at all

10:35 napping: right, persisent! closes by side effect

10:36 clgv: the most performant implementation of map-tv would have to use a loop-recur, I think

10:36 napping: how about a build-tv which lets elements be computed from the vector so far?

10:37 If "alter" means completely rebuild, why not close the one transient and start a new vector?

10:38 mk: I'm trying to learn clojure by writing a simple http server, but I'm not sure where to begin. Any help is appreciated.

10:39 napping: You know http and java sockets?

10:40 maybe do some clojure programs involving concurrency without real network traffic to figure it out

10:40 mk: yes. I've chosen to write one because I've written this server in java, so really it's a port. I'm just not sure what it means to port...

10:41 clgv: mk: whats your goal? the server or delivering some content?

10:41 mk: I could just use clojure's various java hooks to do things (or just call methods I've already written), but I don't think that's the way to learn

10:41 stuartsierra: mk: All of the networking and I/O will be calls to Java code anyway. You'll learn about Java interop, but not much about the language itself.

10:41 clgv: mk: you could use ring to build a webpage.

10:41 mk: at the moment, it's just to make the server return a simple webpage containing all of my request headers etc.

10:42 napping: the point is to use clojure-style concurrency to manage multiple connections, right?

10:44 mk: napping: just a single connection. A http server covers a lot of ground in terms of the... boring but necessary parts of the language (string parsing, io, etc.)

10:45 napping: I'm not very experienced myself, but I think a lot of that stuff goes by calling to Java

10:45 not that string parsing couldn't, but for http in particular there should be thoroughly tested libraries you'd prefer to use

10:46 stuartsierra: mk: most of the "boring" parts of Clojure are just Java interop

10:46 TimMc: mk: I would recommend instead trying to do some project that actually has a desirable end product.

10:46 stuartsierra: e.g. I/O, sockets

10:46 TimMc: mk: Otherwise you're going to have a hard time really seeing the language for what it is.

10:47 (and people will constantly ask you why you're reimplementing X or Y :-P)

10:48 mk: TimMc: this project has one - request headers :) Then I can work up to file service, then a proxy, then a crawler.

10:48 TimMc: Let me put it a different way -- make something new.

10:49 mk: like what?

10:49 TimMc: Do you keep an ideas file anywhere? "I wish I had a ___"

10:49 then pick one and write it

10:50 mk: "a http server written in clojure" :)

10:50 RickInGA: hehe

10:50 mk: that's literally in my file

10:51 napping: I think trying to use features of a new language to write a program you already understand is pretty reasonable as well

10:51 mk: is the main concern that it'll mostly be about java interop?

10:52 stuartsierra: mk: That's my concern. Not that an HTTP server written in pure Clojure wouldn't be interesting.

10:53 napping: If it only handles a single connection at a time, it will probably mostly be java interop

10:53 TimMc: mk: At first, you'll effectively be writing Java with Clojure syntax. It's not what I would recommend to a newcomer.

10:53 mk: I think one worry is that I'll end up using java idioms and so on, but I'm trying to make sure I avoid that, and I have to start somewhere

10:53 pjstadig: happy open source friday: is there a chance that http://dev.clojure.org/jira/browse/CLJ-942 can get a look today?

10:53 stuartsierra: pjstadig: it's been discussed already

10:54 fmardini: Hello, a noob question about namespaces, I have two files starting with (ns foo.core) each def-ining stuff, but can't see things between the two

10:54 clgv: mk: you could also start to learn clojure via 4clojure.com

10:54 stuartsierra: fmardini: you can't do that.

10:54 TimMc: fmardini: One namespace per file and vice versa.

10:54 napping: which may not be that bad, I learned a bit writing a simple swing program, and going "hey, I can use a doto here", and making some macros and stuff

10:54 fmardini: thanks guys

10:55 TimMc: fmardini: and there's a strict correspondence between file name and path and the namespace name.

10:55 pjstadig: cool

10:56 stuartsierra: i'd be glad to answer questions, hop on skype, pair, or whatever

10:56 mk: clgv: thanks for the link - that site looks good. I'd like to try a proper project though, since I think it makes anything much easier to learn.

10:56 fmardini: TimMc: thanks, makes sense!

10:57 stuartsierra: pjstadig: thanks. I am not working on tickets today, but I will pass the word on.

10:57 clgv: mk: well the easy tasks at 4clojure provdie a (non complete) roundtrip through language basics. so it could be a good start

10:57 TimMc: mk: In general, +1 on having a proper project, yes.

10:57 mk: how are events handled in clojure, since it's a "timeless" functional language?

10:58 and threads, for that matter

10:58 TimMc: mk: http://www.clojure.org/state is a good introduction to Clojure state management on the theory side of things.

10:58 mk: clgv: yeah - I'll definitely look through them

10:59 TimMc: in practical terms, you use reference types in transactions http://www.clojure.org/refs or as atomically mutable cells (atoms, agents)

11:00 uvtc: TimMC: thanks for your help yesterday regarding trying to package a script which would take command line args. Just noticed that I managed to totally miss where you wrote I needed a "-main" fn.

11:02 TimMc: haha, OK

11:03 mk: I think I understand a few of those ideas (I watched a bunch of talks by Rich at http://www.infoq.com/author/Rich-Hickey ). I get the ontological/platonic distinctions, but I'm not sure how that works in practice since I see the REPL as a calculator (where the process ends after evaluation)

11:05 TimMc: mk: So for example, you could have some vars pointing to ref objects that contain global application state.

11:05 mk: is that the proper way to see the REPL?

11:05 TimMc: hold on

11:05 mk: ok

11:06 TimMc: mk: Then, from multiple threads, it is easy to safely hammer on the refs in (dosync ...) blocks without worrying about locks.

11:07 mk: Sure, the REPL is just a dev tool. You can launch an application from it, though -- and then muck with it while it is running. Much more than a calculator.

11:09 mk: what I mean by calculator is that... this is the only place that I really see the process living. In java, it lives in various threads, and then runs through code top-to-bottom. In javascript, it waits for new blocks of javascript to be handed to it, via script-tag loads, or events.

11:10 napping: in the repl you get an answer when your expression is done, but there may still be other threads and things running

11:10 mk: in clojure, it seems that the process waits around for me to hit enter at the REPL

11:10 napping: what causes them to start?

11:11 napping: if you start them

11:11 or maybe if loading a file starts them

11:11 mk: sure, but say I have a gui app (or a server) - threads can start on events, yes?

11:11 TimMc: sure

11:12 mk: and does clojure magically start threads when it notices that it can do so?

11:12 TimMc: Nothing is magic.

11:12 mk: s/magic/abstraction

11:13 napping: you can load a GUI app, and poke at it with the repl while using the windows

11:13 TimMc: I mean, you can spawn off threads whenever you like.

11:14 napping: I usually ran my little time tracking program like that, because I'd never gotten around to putting a GUI for doing things like "oops, subtract 5 minutes from this timer and add it to the other"

11:14 mk: how do I disconnect from a given thread of execution? in java, you use thread.start, which returns control to me. Is that the way in clojure, too?

11:14 napping: that's one way

11:14 mk: are there better ways?

11:14 napping: clojure functions end up being java objects that implement runnable

11:15 so you can make a (Thread. (fn [] ...)) and later (.start it)

11:15 TimMc: &(doc future)

11:15 lazybot: ⇒ "Macro ([& body]); Takes a body of expressions and yields a future object that will invoke the body in another thread, and will cache the result and return it on all subsequent calls to deref/@. If the computation has not yet finished, calls to deref/@ will block, un... https://refheap.com/paste/918

11:16 napping: agents and futures end up using threads as well

11:16 mk: what does it mean to invoke the body?

11:17 TimMc: call it

11:17 err, run it

11:17 mk: is it a good idea to conceive of that as "them" typing the expression into their own REPL?

11:17 TimMc: Nope, because the results are not printed.

11:18 and all the expressions are read at the same time, then compiled and evaluated together later

11:18 so it's not really a Read-Eval-Print Loop.

11:18 mk: not to my repl of course - but can I imagine that I've told another person connected to the REPL to just execute that code whenever a specific thing happens?

11:19 TimMc: sure?

11:20 mk: why the question mark? will that view get me into trouble later?

11:20 napping: It may be misleading about a lot of details of how and when names get looked up, and various other things

11:20 mk: napping: hmm. In what ways?

11:21 TimMc: Well, it ignores things like how (binding ...) works, and shared refs, and blocking....

11:22 mk: what do you mean? (err, perhaps pick the easiest example)

11:22 TimMc: mk: Here's an example. (def x 5) followed by (* x x) will work fine in the REPL, but as a function body (fn [] (def x 5) (* x x)) it will not (besides the terrible idea of putting a def inside a defn).

11:24 err, bad example, that works because of def-hoisting...

11:24 napping: how did you expect it to break?

11:24 mk: I don't know enough about lisp to see how that works - I still have some problems understanding how defs or scope of defs works

11:25 TimMc: napping: Unable to resolve x. But the compiler plucks out the def during AST-building time.

11:25 mk: defs aren't scoped in Clojure.

11:25 napping: anyway, threads are more fundamental than repls

11:26 mk: napping: a repl is just another thread, right?

11:26 napping: so you have multiple threads running code, and some are running repls

11:26 mk: I'm not sure what a def does, aside from the fact that I have to use it in certain examples that I've typed out...

11:26 TimMc: mk: (require '[clojure.string :as str]) and then (str/join \, (range 5)) works fine on the REPL, but not inside a fn body.

11:27 napping: Is there an easy way to get multiple repls in the same process?

11:27 I don't know how to manually start a swank listener thread

11:28 TimMc: mk: def creates and a var (a mutable cell of sorts) and interns it into a namespace (makes a mapping in the namespace from a symbol to the Var object)

11:28 s/and a var/a var/

11:28 defn is short for def + fn

11:29 mk: what's a cell, and internment?

11:30 clgv: mk: I would suggest that you read one of the good introductory books. That will get you started much faster.

11:31 jcrossley3: mk: coming from java, it's best to think of vars as ThreadLocals

11:32 mk: clgv: I have, but if you have a suggestion for a chapter that explains what those concepts particularly well, I'd like that

11:32 clgv: mk: which one did you read?

11:33 TimMc: mk: "cell" and "interning" are not Clojure technical terms -- they're more general programming terms

11:34 mk: clgv: parts of sicp a while back, and a few other books for lisp. I don't recall the names of the ones for clojure, but I could try to search my history if it's important

11:34 dnolen: mk: I suggest not thinking about the details of vars too much for a long time - def & defn simple associate values to names in a namespace. how it works is mostly irrelevant for day to day programming.

11:35 clgv: mk: not that important. my start was "Programming Clojure"

11:36 napping: I've read "Joy of Clojure" and the reference at clojure.org, and I don't think the process of reading and resolving symbols was explained very precisely

11:36 mk: are namespaces structured in any way? (for example, in javascript, prototypes check their parents for the existence of a var, and java has a shallow instance/static "namespace" pair)

11:37 napping: Did I miss something that would explain where #'name is needed to reflect redefined things promptly?

11:39 dnolen: mk: namespaces are just simple mappings of names to values - there's little else that they do.

11:40 napping: that's usually never necessary - sometimes required to allow redefinition when working with Java libs.

11:42 napping: I'm redefining with slim functions that are called in ring or Swing handlers

11:42 mk: dnolen: if a name doesn't exist in the namespace, what happens?

11:42 napping: Sometimes I need to write (#'foo ...) instead of (foo ...) to immediately get the new behavior after reevaluating a (defn foo ...)

11:42 dnolen: mk: an error

11:43 napping: I think reading a painstakingly precise description of name resolution about five times would probably do it

11:43 mk: dnolen: ok, so there's no parent namespace to check - it's all very flat

11:43 dnolen: mk: yep

11:45 napping: I'm confused that (= (resolve 'x) #'x) - at least a the repl

11:45 mk: ok, so I have a namespace N, which is very much a map. Now I call def, and this has the sideeffect (?) of setting a key to a value

11:46 napping: mk: for ordinary purposes, you write (def x ...), and now x has been defined and later lines in the file can use it

11:47 mk: ok. And it's not a rule of replacement?

11:47 napping: I'm asking for pointers to thorough descriptions so I can get edge cases involving reloading code in a running program.

11:48 dnolen: napping: you should never need #'foo as far as I know.

11:48 napping: (a filename in the compiler would do, if you think that's best)

11:48 tmciver: napping: not sure if it's been mentioned yet but if you update your code you must (use :reload 'your-ns) in the repl.

11:50 napping: :reload sounds like an important thing, but isn't that if a file is changed?

11:51 tmciver: napping: yes, that's the point. If you change a file you're working on the changes are not automatically reflected at the repl. In fact simply calling (use 'your-ns) is not enough; you must use :reload (or :reload-all).

11:51 napping: I'm using C-x C-e to feed new definitions to SLIME

11:52 dnolen: tmciver: not necessary with C-x C-e

11:52 tmciver: dnolen: true. I always forget about that!

11:53 dnolen: of course, that's only for emacs users.

11:55 napping: this first example might be a ring thing, but if I (defroutes pages ...), then (def app (-> pages wrap-params)) and use ring-serve to serve app

11:56 dnolen: tmciver: that applies to any environment that supports evaluating forms one at a time

11:56 napping: yes that's what I was saying, Java libs tend to be static, you need the var to work around it.

11:56 napping: a change in the pages isn't reflected unless I also redefine app

11:57 but if app is defined as (-> #'pages wrap-params ...), it is picked up immediately

11:57 dnolen: napping: yep

11:58 napping: hmm, serve expands into a use of var

11:58 tmciver: dnolen: are you saying C-x C-e works in environments other than emacs? Which ones?

11:58 napping: I did not realize it was a macro

11:58 tmciver: the pasting a single form into the repl bit, not the exact keystroke

11:59 If I'd been running a clojure.jar directly and retyping a defn it could be the same story

12:00 dnolen: I know you can "need the var to work around it", I don't understand enough about how symbols usually work or how they differ from #' to see how that works around it

12:00 though I might have been confused by thinking ring-serve's serve was an ordinary function

12:01 TimMc: tmciver: It's about eval'ing top-level forms sequentially, not the command itself.

12:01 tmciver: napping: I think I'm missing something. You can always paste code into a repl. what's that got to do with C-x C-e?

12:02 napping: that if I'm redefining code by something like pasting code into a repl, any problems with changes showing up has nothing to do with :reload ing file

12:08 or does it? so far I've only been redefining things in a leaf namespace

12:12 dnolen: napping: it's less complicated then you think. if you give ring a value, that will get hard coded as the handler - there's no good way to get Jetty to update that value. By passing a var you're just adding a level of indirection. Jetty will extract the value inside the var everytime

12:12 tmciver: napping: not sure. I typically just (use ...) (in the slime repl) the code I'm working on.

12:13 TimMc: I think you're talking past each other.

12:14 napping: I think I get it now - when code containing a symbol is compiled, the symbol is resolved now, and if it resolves to a var the compiled code will get the value from the var when it's executed

12:14 dnolen: napping: yep

12:14 napping: so function bodies mentioning def'd thing tend to work because they read the var when they are called

12:14 dnolen: napping: no that would be slow

12:14 napping: The wrapped handler didn't update because it was just an expression evalauted at def time

12:15 How does (def x 1) (defn test [] x) (def x 2) (test) pick up 2 then?

12:16 dnolen: napping: I'm not familiar with the details of that machinery

12:16 napping: I don't see why it would be particularly slow for a function refering to global var to read from the var when it runs

12:17 a bit slower, but a single field access shouldn't be horrible

12:19 #' helps when something is evaluated right away (like my (def app ...)), because it makes the difference between the callable thing that's getting wrapped being the particular fn the name maps to at the moment, and the var itself (acting as a callable thing)

12:23 tmciver: napping: it's been a while since I've looked at ring but there is middleware that I believe solves your problem: ring.middleware.reload (https://github.com/mmcgrana/ring)

12:24 dnolen: napping: slow is relative - but in tight loops any indirection kills perf

12:25 ibdknox: napping: if you used Noir you would get reloading for free

12:25 napping: It seems like I need to read Compiler.java for the full story

12:26 tmciver: I think that handles just about everything but my problem :)

12:28 which was that the top level handler had been sufficiently evaluated that no namespaces or even vars were consulted

12:28 works pretty nicely for changes deeper in the code

12:29 tmciver: napping: it sounds like you might be doing some voodoo that I'm not familiar with. Don't think I can help.

12:29 dnolen: napping: I never use #' except setting a dynamic handler for Ring. that the only issue that you have as far as I can tell. I agree it's useful to dig into Compiler.java, but it's just implementation details to support traditional Lisp programming. ClojureScript doesn't have these implementation issues because JS is already very dynamic.

12:30 napping: ibdknox: that's reloading from files, right?

12:32 dnolen: Do e.g. Scheme and Common Lisp agree enough on things like how interning and symbol resolution work that it's precise to say "traditional Lisp programming"?

12:32 dnolen: napping: they agree on the important point - redefinition should work and the good implementations make sure that's not slow

12:33 mk: what's the documentation command?

12:33 napping: It's not obvious to me there's one right answer to the question of exactly what should be affected by redefinition

12:34 If you tried hard enough, you could track which functions had a hand in computing integers, and re-evaluate them too :)

12:34 beffbernard: Is there any way to use the hostname url for a noir/hiccup app? (include-js …) and (include-css …) I'm finding that these are relative to the route.

12:34 dnolen: napping: my experience as a programmer is that redefinition in Common Lisp ad Scheme and Clojure - "just works", barring the various host-y things in Clojure

12:37 hiredman: clojure-py seems to be adopting :static semantics for vars that are not :dynamic, so redefintion won't "just work" there

12:37 (it's like they don't even care)

12:38 ibdknox: napping, it's reloading from anything

12:39 though I haven't been paying attention to exactly what your use case is

12:39 napping: hiredman: isn't static already default?

12:39 hiredman: no

12:39 :static links directly, not through a var

12:40 ibdknox: beffbernard: just put / in front of them?

12:40 hiredman: makes redefintion a pain

12:40 or did, dunno if :static is still supported

12:40 napping: doesn't seem to do anything

12:41 ibdknox: my case is that I'm pushing new definitions through slime, and sometimes they are not picked up

12:41 ibdknox: napping: try noir

12:41 you can add defpages to your heart's content

12:41 or redef them

12:41 or whatever you want

12:41 beffbernard: ibdknow: Worked, thanks

12:41 ibdknox: the only thing I can't do deterministically is remove them

12:41 hiredman: (def ^:static foo (fn [x] 2)) (defn bar [] (foo)) (def foo (constantly 4)) (bar)

12:41 ibdknox: gotta run

12:41 back in a bit

12:42 napping: It's working with a #', but I'll be trying Noir eventually

12:42 dnolen: :static does do anything anymore as far as I know

12:43 doesn't

12:45 napping: your issue is entirely about resolution not surviving the interop barrier - Jetty don't know nuttin' about Clojure.

12:49 napping: because of interop, the handlers have to evaluate down to some object that can be handed off

12:51 but I think you can already see the core of the problem in this:

12:51 (def f identity) (def op (comp f inc)) (def f double) (op 1)

12:52 why u no double?

12:54 dnolen: napping: there's no problem there - think about that some more.

12:54 napping: I understand now, but that's why my redefinitions were not picked up

12:55 mk: what does (fn [[x & xs]] ... do?

12:55 dnolen: napping: no, that's a different issue entirely.

12:55 TimMc: mk: Destructuring of arguments.

12:55 dnolen: napping: not related at all

12:55 TimMc: x is bound to (first ...) of first arg, xs to (rest ...) of first arg

12:57 mk: & is the first arg?

12:57 lazybot: java.lang.RuntimeException: Unable to resolve symbol: is in this context

12:58 mk: thanks lazybot

12:58 RickInGA: the & indicates there may be a variable number of args

12:59 mk: I don't follow why having a vector in the arguments vector... does that.

12:59 napping: dnolen: no? I can also get the code to behave as expected by eta-expanding (def app (-> pages wrap-params)) to (defn app [& args] (apply (-> pages wrap-params)) args)

13:00 as hoped

13:01 RickInGA: mk: (defn add-a-bunch [x & xs]

13:01 (apply + x xs))

13:01 (add-a-bunch 1 2 3 4 5)

13:01 dnolen: napping: like I said think it about it so more

13:01 some

13:02 RickInGA: mk x is bound to 1, xs has '(2 3 4 5)

13:02 napping: I think I understand what's going on there

13:02 when the higher order function is applied, the arguments evaluate to a value, which is what gets wrapped up in the returned closure

13:02 and after that no redefinition I do will replace it

13:03 TimMc: mk: fn is a macro, it does all the fancy syntax -> boring code conversion.

13:03 mk: what gets bound to &?

13:03 TimMc: nothing

13:03 RickInGA: mk: the & just indicates that xs has a variable number of arguments, it doesn't actualy take a value

13:03 mk: is & the same type of thing as x?

13:04 RickInGA: mk: if the function takes [x xs] it can only take 2 params. if it has [x & xs] it takes 1 or more

13:04 mk: the language might have been designed where [x :foo xs] does the same?

13:06 TimMc: sure

13:06 napping: ,(let [& 3] (+ & 2))

13:06 clojurebot: 5

13:06 TimMc: mk: Technically, it's not even the language -- it's the macro.

13:07 Macros are how you extend the language. :-)

13:07 *it's the fn macro

13:08 mdeboard: man mount

13:08 oop

13:29 harrison: man mount lol

13:41 sorenmacbeth: technomancy: heads up: lein-swank 1.4.1 tries to require [swank.util.sys :as util] in jack_in.clj, and it doesn't exist causing jack-in to fail

13:42 technomancy: sorenmacbeth: oh yeah; I have a fix locally but haven't pushed it out; thanks for the reminder

13:48 sorenmacbeth: technomancy: no worries, quick question for you: does lein compile call lein javac first by default? if not, is there something I can add to my project.clj to make it do that?

14:12 technomancy: I assume it's just an ordering thing right? javac is called first, then compile?

14:12 technomancy: sorenmacbeth: sounds like it, but I couldn't say for sure

14:12 I've never used javac

14:17 vijaykiran: Hi all - how can make lein to fetch the latest snapshots ?

14:20 technomancy: vijaykiran: the underlying maven API doesn't expose a way for leiningen to do that

14:20 you probably want to use checkout dependencies for that though

14:22 solidsnack: Hello. I have recently installed clojure with homebrew on OS X. I can not load the math contribs

14:23 Do I need to add something to Leinigen?

14:23 I mean, to project.clj?

14:29 tmciver: ~contrib ;; solidsnack

14:29 clojurebot: Huh?

14:29 tmciver: ~contrib

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

14:30 tmciver: solidsnack: looking at that page, it looks like you might want clojure.math.numeric-tower

14:30 vijaykiran: technomancy: ok - thx

14:30 solidsnack: tmciver: And I put it in, uhm, project.clj?

14:30 It doesn't come stock?

14:31 tmciver: solidsnack: no. Here's the github page for it: https://github.com/clojure/math.numeric-tower

14:32 I didn't see it on clojars.org

14:32 TimMc: I don't think any core jars end up on clojars.

14:32 Some other Maven repo instead.

14:33 ibdknox: they end up on maven central, don't they?

14:33 tmciver: TimMc: where do you get the lein dependency string for such a lib?

14:34 TimMc: Good question. Should be in the readme!

14:34 but [org.clojure/math.numeric-tower "1.3.0"] is my guess

14:35 tmciver: solidsnack: try putting that ^ as an entry for :dependencies in project.clj

14:39 solidsnack: tmciver: Found it -- http://mvnrepository.com/artifact/org.clojure/math.numeric-tower/0.0.1

14:39 tmciver: cool. Good to know.

14:40 technomancy: sorenmacbeth: pushed out lein-swank 1.4.2

14:41 sorenmacbeth: technomancy: cool. I made a sample project I can reproduce that bug with now

14:41 technomancy: it seems to be related to whether or not lein deps runs or not

14:42 technomancy: oh yeah, deps has to clear out the classes dir; maybe it's running too late

14:43 sorenmacbeth: want me to throw this project up on github and file an issue?

14:43 technomancy: please

14:43 sorenmacbeth: technomancy: ok

14:46 solidsnack: I can not figure out how to load this math library in the REPL...

14:47 (:use org.clojure.math.numeric-tower)

14:47 (:use clojure.math.numeric-tower)

14:47 None of these work.

14:47 tmciver: (use 'org.clojure.math.numeric-tower)

14:48 Or better yet: (require '[org.clojure.math.numeric-tower :as math])

14:48 then prefix the functions with math/

14:48 when you call them.

14:49 solidsnack: Also, make sure you run 'lein deps' after updating your project.clj.

14:52 solidsnack: tmciver: Yes, it has placed it in a jar in lib

14:53 I can load it with (:use ...) but not (use ...)

14:53 However, I can not use the function.

14:53 (expt 2 2) does not work, for example

14:54 Here is what I'd like to do: (def the-distant-future (- (Math/pow 2 31) 1))

14:54 tmciver: solidsnack: (:use ...) can only be used in the ns form.

14:54 solidsnack: But using Clojure's math libraries instead.

14:54 tmciver: Oh, hmm.

14:54 TimMc: solidsnack: :use is a keyword, use is a function

14:54 solidsnack: Well, I am using `lein repl' to try these things.

14:54 I see.

14:54 (:use ...) evaluates to nil

14:54 TimMc: &(:use {:use 5})

14:54 tmciver: solidsnack: (Math/pow ...) is Java interop; not the function from the math lib.

14:54 lazybot: ⇒ 5

14:55 muhoo: if i were going to chart stuff, what do you recommend? jfreechart?

14:55 sorenmacbeth: technomancy: done - https://github.com/technomancy/leiningen/issues/428

14:56 solidsnack: tmciver: Right.

14:56 tmciver: So, I'd like to stop using it :)

14:56 technomancy: sorenmacbeth: you have a workaround for now though, right?

14:56 solidsnack: (use 'org.clojure.math.numeric-tower)

14:56 This fails, so I have some other problem, I guess.

14:57 hiredman: why the org?

14:57 sorenmacbeth: technomancy: yeah, I just run it twice when it fails

14:58 technomancy: or run lein deps first I guess, to make sure that deps doesn't run in the middle

14:58 TimMc: solidsnack: You're getting Maven group/artifact names and library namespaces confused.

14:58 They are quite often similar but not teh same.

14:58 solidsnack: Oh...

15:00 (use 'clojure.math.numeric-tower)

15:00 Okay, that works fine.

15:00 Thanks everyone.

15:00 TimMc: solidsnack: And in your ns block, that's (:use [clojure.math.numeric-tower :only (pow)])

15:01 (Only use :use with :only, for the sake of sanity.)

15:04 Iceland_jack: TimMc: that's beautifully palindromic ;)

15:04 > Only use :use … :only …

15:05 technomancy: more of a chiasm really

15:05 emezeske: TIL: chiasm

15:13 shaolynn: I'm trying to run a noir/aleph app using "lein ring server", but I get the following error:

15:13 java.lang.IllegalArgumentException: No implementation of method: :consumer of protocol: #'lamina.core.channel/ChannelProtocol found for class: nil

15:13 it happens when I try to send a message via websocket

15:13 has anyone seen this problem before?

15:14 hiredman: the code reloading the noir does won't work nicely with protocols

15:14 shaolynn: hiredman: I'm not sure I understand. Can you please elaborate?

15:17 hiredman: Do you know of a good workaround?

15:17 hiredman: shaolynn: code reloading in general doesn't work nicely with protocols, you end up defining a "new" protocol and have a bunch of objects which implement the "old" protocol

15:17 depends

15:18 shaolynn: Here's my server.clj file:

15:18 https://gist.github.com/1960995

15:19 Is there anything I can do differently to get ring to run this thing?

15:19 dnolen: shaolynn: don't use ring reloading

15:19 shaolynn: Ok, I'll try that. Thx!!!

15:20 dnolen: shaolynn: it does mean you'll need to provide the handler as a var if you want to compile incrementally and see changes

15:20 technomancy: ring reloading doesn't attempt to just reload what's changed?

15:20 shaolynn: For now I just need to get this thing deployed.

15:20 dnolen: technomancy: it does but pretty bad in the presence of deftype/record/protocol/interface/etc

15:21 shaolynn: I removed "wrap-reload", but I still get the same problem.

15:21 technomancy: dnolen: sure, I'm just surprised that it would complain about an internal aleph protocol

15:21 dnolen: shaolynn: then it's probably something else, unexpected nil

15:21 technomancy: usually "don't use protocols" suffices; that makes it look like the advice needs to be upgraded to "don't use libraries that use protocols"

15:23 TimMc: On the menu today: Nil Surprise

15:23 dnolen: technomancy: I'd change that to don't use library features that reload namespaces on save.

15:23 or file changes

15:24 technomancy: interactive development is way more valuable than protocols are

15:24 shaolynn: dnolen: I'm super new to this - the problem happens when I try to send a message via websockets. What could be causing this to break with "lein ring server" but not "lein run"?

15:25 dnolen: technomancy: they are less convenient, but I haven't run into much trouble with them myself. In more dynamic hosts a non-issue, CLJS FTW ;)

15:25 technomancy: hm; well I have yet to run into a case where multimethods were a bottleneck

15:25 dnolen: shaolynn: no idea, makes sense to ask on the Aleph ML

15:26 technomancy: and the uniformity of everything being a var is wonderful

15:26 dnolen: technomancy: we've gone over this before multimethods rock :) But lots of cases where they are too slow.

15:26 technomancy: dnolen: right; just saying I'm happy that I've never found myself in any of those cases.

15:38 RickInGA: ~method_missing

15:38 clojurebot: Gabh mo leithscéal?

15:38 pjstadig: ,(= 4M 4)

15:38 clojurebot: false

15:39 pjstadig: ^ is that intentional?

15:39 it was true in 1.2

15:40 ,(= 4N 4)

15:40 TimMc: &(== 4M 4)

15:40 clojurebot: true

15:40 lazybot: ⇒ true

15:40 hiredman: :(

15:40 TimMc: pjstadig: == is not =

15:40 pjstadig: true

15:40 TimMc: are you sure it was =?

15:40 ,*clojure-version*

15:40 clojurebot: {:interim true, :major 1, :minor 4, :incremental 0, :qualifier "master"}

15:40 pjstadig: but why is 4N = to 4

15:41 and why was 4N = 4 in 1.2

15:41 TimMc: &(class 4N)

15:41 lazybot: ⇒ clojure.lang.BigInt

15:41 hiredman: M is floating point

15:41 pjstadig: well BigDecimal

15:41 TimMc: because 4N and 4 are both integer types

15:41 hiredman: *shrug*

15:41 pjstadig: in 1.2 (= 4N 4) was true in 1.3+ it is false

15:42 dnolen: ,(= 1 1.0)

15:42 clojurebot: false

15:42 dnolen: ,(== 1 1.0)

15:42 clojurebot: true

15:42 dnolen: pjstadig: changed along w/ the other numeric stuff

15:43 TimMc: pjstadig: (= 4N 4) => true in 1.3

15:43 do you mean M?

15:43 pjstadig: hehe

15:43 TimMc: pjstadig: (This would be even more confusing if we were speaking instead of typing.)

15:46 pjstadig: ok well that makes sense

16:05 hmm...maybe the issue is somewhere else

16:05 we have a bunch of tests that are failing now because it is trying to compare a bigdecimal to a long

16:06 but i'm not sure why we have bigdecimals in the first place

16:06 mefesto: I have a clojure program that I'd like to run as a service. Is upstart a good choice or is something else preferred?

16:08 pipeline: upstart is an init daemon

16:08 you probably want a processmonitor + init script to start the monitor

16:08 say, monit, or supervisord

16:08 mefesto: pipeline: i'll look into those. thanks for the tip!

16:10 hugod: I here systemd is up and coming for that too

16:14 TimMc: Tanuki... can't figure out if there's a free version for FL/OSS projects.

16:19 pjstadig: apparently JDBC only supports BigDecimal even though our columns are BigInts

16:19 our tests passed fine with 1.2 because of looser equality comparisons, and now they fail

16:19 RickInGA: wow, good to know

16:20 pjstadig: really annoying

16:20 ibdknox: the big decimal stuff really sucks :(

16:34 hagna: man org.apache.commons.exec sheesh I really need an example of what I want to do

16:34 doug: how can i have a sequence of forms evaled, like in a block?

16:34 like whatever the body of a let is called...

16:34 clojurebot: 'Sea, mhuise.

16:34 TimMc: clojurebot: forget like whatever the body of a let |is| called...

16:34 clojurebot: I forgot that like whatever the body of a let is called...

16:35 TimMc: stupid bot

16:35 doug: nice

16:35 mefesto: doug: wrap them in a (do ...) form?

16:36 doug: mefesto++

16:36 yup

17:00 hagna: how do I init an InputStream? (InputStream. ) gives an instantiation error

17:02 TimMc: hagna: I think that's an interface or abstract class.

17:02 hagna: (java.io.InputStream. ) does the same

17:03 TinMc: not sure what you mean anyway

17:04 tmciver: hagna: you can't directly instantiate an Interface or abstract class. you'll have to look for a concrete implementation to instantiate.

17:04 _ulises: hagna: what do you need an InputStream for?

17:05 tmciver: hagna: try a FileInputStream maybe? See: http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html

17:07 hagna: _ulises: to pass it to pumpHandler of apache.commons.exec and interact with a subprocess's stdin and stdout

17:08 tmciver: ok that's good to know; I wonder which concrete implentation I want

17:09 _ulises: hagna: fair enough, but keep in mind that InputStream is an abstract class (I believe) so you need to instantiate a concrete class such as FileInputStream if you want to read from a file

17:11 hagna: _ulises: ok got it. I need the type that will let me send strings from clojure

17:12 _ulises: hagna: interactively?

17:14 hagna: _ulises: yeah basically

17:18 _ulises: hagna: perhaps there's some useful stuff in clojure.java.io

17:18 TimMc: hagna: Without providing the bigger picture, you're going to get misleading help.

17:19 hagna: TimMc: ok then let me try the big picture I'm trying to get more familiar with clojure by writing a bot to play zork over irc

17:20 TimMc: and you want some Apache util to pump streams back and forth?

17:20 technomancy: hagna: feel free to steal liberally from https://github.com/technomancy/mire

17:21 hagna: TinMc: org.apache.commons.exec is for spawning the process and talking to stdin and out. so yes

17:21 technomancy: thanks I saw that the other day

17:26 ibdknox: holy shit

17:26 http://www.wired.com/

17:27 that game programming header is an article on the cljs game editor I did

17:27 hiredman: nice

17:28 technomancy: webmonkey is a wired subsidiary?

17:28 did not know that

17:28 congrats

17:29 ibdknox: technomancy: they apparently got bought a couple years ago

17:37 tmciver: ibdknox: wow, they picked that up fast!

17:39 ibdknox: tmciver: yeah, I'm a little surprised

17:57 zzach: Server socket at port 12345 ist defined with (def server-socket (new java.net.ServerSocket 12345)) and (def client-socket (. server-socket accept)) . First connection to this socket is working, second connection is hanging. Is it possible to set an option to refuse the connection for the second and further connection attempts?

18:20 scriptor: hmm, homebrew is hanging up on the lein self-install part

18:20 anyone else having this problem?

18:20 ibdknox: don't use homebrew to install lein

18:21 scriptor: :(

18:22 ibdknox: I ran into the same thing

18:22 ended up uninstalling it and just doing it from the repo

18:22 so much easier

18:22 scriptor: so just downloading the lein script?

18:22 ibdknox: yep

18:22 muhoo: ibdknox is famous!

18:23 ibdknox: hah

18:23 technomancy: wait, what's wrong with homebrew?

18:23 ibdknox: top of HN is way more exposure than wired is I think, actually

18:23 technomancy: I always tell people to use whatever they're already using to install stuff

18:23 muhoo: HM is certainly cooler

18:23 technomancy: (unless it's macports)

18:23 muhoo: HN

18:24 technomancy: if it's macports then "you are using macports" is a more immediate problem than "you don't have leiningen installed"

18:24 muhoo: wired was super hip in like 1995

18:25 RickInGA: is the story on wired.com right now?

18:26 ah, see it, nm

18:26 clojurebot: Huh?

18:26 ibdknox: it might just be that wired traffic doesn't click through

18:26 RickInGA: I am watching the inventing on principle right now, it is amazing... I can't wait to see what you did

18:28 ibdknox: I built his game editor :)

18:31 RickInGA: I like his binary search editor... so procedural... maybe I should go back to c#

18:32 * technomancy would love to implement livetrace for emacs

18:32 technomancy: you might want to store tracing values as metadata on the function, but that might just get cluttered

18:38 ibdknox: technomancy: it wasn't clear to me how often I would benefit from having what he showed with the binary search

18:38 I don't have many free vars like that, and they don't change...

18:39 would you just show the result of that scope?

18:39 RickInGA: with recursive functions, it would be nice to see what gets returned each time through

18:39 technomancy: yeah, also for reductions

18:40 ibdknox: it seems like it wouldn't be that hard to build

18:40 the only thing I have trouble with is knowing what to show

18:41 technomancy: and where

18:41 ibdknox: yeah

18:41 technomancy: I'm not too keen on the side-by-side approach

18:41 ibdknox: you'd want it inline?

18:41 RickInGA: I think it would get messy inline

18:41 ibdknox: we tried that at msft, it didn't work very well

18:41 technomancy: oh yeah?

18:41 ibdknox: it did when you were at a breakpoint though

18:42 RickInGA: I get furstrated when intellesense covers up something I am trying to typee

18:42 technomancy: RickInGA: I'd put it after EOL

18:42 but that would get ugly if it wrapped

18:42 RickInGA: docable window?

18:42 dockable

18:42 technomancy: I've never seen that done well

18:43 ibdknox: I had a very cool solution to all of this

18:43 I dunno how well it would work for Clojure though

18:43 RickInGA: The repl is great for learning because you type, run, see

18:44 ibdknox: the structure of clojure code is very different than C# and VB

18:44 RickInGA: this takes repl to a new degree

18:44 technomancy: ibdknox: it's nice that let-bound stuff usually has one binding per line

18:44 but function parameters don't have that property

18:44 ibdknox: yeah

18:45 I think if I were going to do it, my first pass would be the side-by-side

18:45 RickInGA: in Victor's video, he had 2 parameters, which were in 2 lines on the display

18:45 technomancy: it definitely makes sense as a starting point

18:45 RickInGA: then he skipped a line before his variable declarations

18:45 ibdknox: I'm not sure we have sufficiently good UI capabilities in either emacs or VIM to do anything really cool

18:45 that's one thing I do miss about the team I was on

18:45 the editor was WPF

18:46 we could literally try whatever the hell we wanted

18:46 technomancy: yeah, if it doesn't work over SSH I'm not interested

18:46 jodaro: i need to register for clojure west

18:46 which means i need a friend

18:46 ibdknox: jodaro: yes you do

18:46 Chris Granger will do

18:46 jodaro: excellent

18:46 ibdknox: though, if someone else wants it it would actually save them money

18:46 RickInGA: yeah, watching victors video the first couple minutes I was thinking that he rebuilt the zaml editor

18:46 jodaro: ok

18:46 RickInGA: use me

18:46 Rick Hall

18:47 I don't have any clojure friends :)

18:47 jodaro: ok rick

18:48 RickInGA: do you need any more info from me, or a referral?

18:48 nlogax: keep your enemies clojure

18:49 ibdknox: should just need your name

18:49 ~rimshot

18:49 clojurebot: Badum, *tish*

18:49 jodaro: looks like thats it

18:49 RickInGA: ~orm

18:49 clojurebot: Object-Relational Mappers are the Vietnam of computer science.

18:49 RickInGA: I love that one!

18:49 jodaro: i used your name and it let me in

18:50 Your registration is complete.

18:50

18:50 RickInGA: cool

18:50 ibdknox: RickInGA: having written a couple now, it's true

18:50 RickInGA: I liked SubSonic for .net

18:50 I want to check out Massive, which is by the same guy, Rob Connery

18:51 jodaro: ORM and webapp frameworks

18:51 RickInGA: then, of course, i do want to check out Korma

18:51 jodaro: i wrote a "port" of struts in perl once

18:51 it sucked

18:51 ibdknox: lol

18:51 jodaro: but it worked

18:52 ibdknox: that's really the measure of good software ;)

18:52 jodaro: cool, so clojure west and erlang factory this month

18:53 i'm going to more conferences in one month than i've been to in like two years

18:53 ibdknox: well done :)

18:53 RickInGA: ClojureWest will be my first

18:54 I just wish I started clojure a few months earlier, Durham I can drive to

18:54 ibdknox: MSFT used to send me to a bunch

18:55 jodaro: you can drive here too

18:55 its just ... much further

18:55 now clojure maui ... you won't be able to drive to that one

18:55 RickInGA: you don't know me... I debated for days before I bought a plane ticket

18:55 I have a lot of people I could visit along the way...

18:56 jodaro: now i know you. you are my clojure friend.

18:56 RickInGA: haha, good point

18:56 jodaro: its like blood brothers

18:56 only hygeinic

18:56 RickInGA: no, if it were scheme it would be hygenic

18:57 jodaro: damn

18:57 we are both wrong

18:57 hygienic

18:57 RickInGA: :)

19:01 Raynes: https://refheap.com/paste/868 New theme. Less likely to make your eyes bleed.

19:02 Going to make it switchable soon, because some people like amalloy like the bright theme.

19:06 Hah, I just realized I posted a link to a Ruby paste in #clojure.

19:06 https://refheap.com/paste/920 Here is a Clojure paste with the new theme.

19:07 technomancy: ~guards

19:07 clojurebot: SEIZE HIM!

19:07 ibdknox: ~kill

19:07 clojurebot: Huh?

19:07 ibdknox: hm

19:07 qbg: slut

19:07 :p

19:07 mk: what's the info command for the bot?

19:07 ...nevermind

19:07 ibdknox: ~kill it

19:07 clojurebot: Huh?

19:07 mk: ~recur

19:07 clojurebot: Excuse me?

19:08 ibdknox: what was the kill it with fire one?

19:08 qbg: ~dance

19:08 clojurebot: Excuse me?

19:08 ibdknox: Raynes: nice btw

19:08 mk: what does recur do?

19:08 qbg: tail self recursion

19:08 (basically)

19:08 mk: don't follow

19:08 aperiodic: it's the only way to do recursion without consuming stack

19:09 otherwise you'll get stack overflow errors if you do a lot of recursion

19:09 mk: hmm

19:09 Raynes: $kill

19:09 lazybot: KILL IT WITH FIRE!

19:09 ibdknox: ah

19:10 qbg: It lets you loop

19:10 AimHere: Wel there's also the trampoline function for coroutines

19:10 qbg: trampoline still uses recur internally

19:11 aperiodic: well, i guess "only way" isn't true

19:11 AimHere: That's just an engineering decision. Recur could have used trampoline ;)

19:12 mk: I tried to get doc on it, but it's a macro, and I don't understand macros yet

19:12 qbg: recur is a special form

19:12 mk: are special forms a type of macro?

19:12 TimMc: nope

19:13 qbg: special forms are primitives

19:13 TimMc: They're actual honest-to-god compiler built-ins.

19:13 technomancy: you can treat them like macros for the most part

19:13 RickInGA: (defn triangle [^long n]

19:13 (loop [c 0 n n]

19:13 (if (zero? n)

19:13 c

19:13 (recur (+ n c) (- n 1)))))

19:14 that function calculates 'triangle' numbers using recursion

19:14 mk: I'm looking at: (fn [s n] (if (= n 0) (first s) (recur (rest s) (dec n))))

19:14 qbg: 1.3 lets you do (doc recur)

19:14 TimMc: mk: There are two places you can recur to: fns and loops

19:15 mk: Are you familiar with the concept of teh "tail position" in an expression?

19:15 mk: my version of that was: (fn r [q n] (if (= n 0) (first q) (r (rest q) (- n 1))))

19:16 qbg: mk: That is basically nth, if you don't know what it does

19:16 mk: qbg: yep. It's #21 on 4clojure.com

19:16 TimMc: probably not sufficiently

19:16 TimMc: It's essential to understanding recur.

19:17 RickInGA: the second one you posted, the function calls itself by name

19:17 recur gives you the same behavior, but the compiler actually rewrites it as a loop

19:18 qbg: If the last thing a function does is return a result of another function, it can instead just have the other function return the first function's caller

19:18 TimMc: instead of allocating a new stack frame each time

19:18 qbg: *return to the first function's caller

19:19 mk: I don't understand yet. so looking at: (fn [s n] (if (= n 0) (first s) (recur (rest s) (dec n))))

19:20 there's a function, a conditional, first makes sense... then suddenly, recur

19:20 qbg: Consider your first version of the function

19:20 AimHere: (defn triangle [n] (if (= n 0) 0 (+ n (triangle (- n 1))))) <- This would be a 'simpler' recursive triangle function, but since the result of the recursion has things done to it, you can't use recur to make it tail recursive

19:21 qbg: r returns the result of evaluating r

19:21 RickInGA: mk: do you understand how it works if your function had a name and if the function called itself?

19:22 mk: RickInGA: I wrote the second version I posted, and I think that (fn name ... names the function, so yes (I hope)

19:22 qbg: Yes it does

19:24 RickInGA: by replacing the function name with recur you get the same behavior

19:24 qbg: Since r is returning the result of r, we can have (second) r return the result directly instead of having it first return it to the first r.

19:24 RickInGA: the function calls itself again, and rebinds the parameters to the new values

19:25 mk: oh. Yeah, I see that now. I had one solution typed up across several lines, but now I'm looking at them beside each other

19:25 RickInGA: the benefit of this is that it does not ACTUALLY call itself, it rewrites itself as a loop, which does not use the stack

19:25 mk: how does recur know which function to grab if the function isn't named?

19:25 qbg: Inner most

19:26 (loop also counts here)

19:26 RickInGA: the trade off of using recur though is that you can only call it from the 'tail position', which is the last thing the function does

19:26 mk: qbg: can I specify some outer function?

19:26 qbg: No

19:26 AimHere: Some lisps are magic enough to do the tail recursion thing without any explicit 'recur' type calls.

19:27 Apparently clojure is hampered a little with the JVM

19:27 qbg: We need loop/recur because of the JVM

19:27 mk: yeah, I heard that mentioned in a talk

19:27 qbg: With native code (or appropriate emulation), you can have general tail call optimization

19:27 One way to emulate it is to use trampoline

19:27 RickInGA: I need to run, talk to you all later

19:27 qbg: tail recursion = goto

19:28 mk: what counts as "the last thing the function does"?

19:28 qbg: The last thing computed

19:29 mk: (fn [s n] (if (= n 0) (first s) (recur (rest s) (dec n)))) ?

19:29 what counts as the last thing computed there?

19:29 qbg: On the recursive side, the recur

19:29 This is enforced by the compiler

19:29 ,(fn [x] (+ 1 (recur (inc x))))

19:29 clojurebot: #<CompilerException java.lang.UnsupportedOperationException: Can only recur from tail position, compiling:(NO_SOURCE_PATH:0)>

19:30 qbg: Above you can't use recur because you still need to add one to the result of the recursion

19:30 Understand?

19:31 AimHere: ,(fn [x] (+ 0 (recur (inc x))))

19:31 clojurebot: #<CompilerException java.lang.UnsupportedOperationException: Can only recur from tail position, compiling:(NO_SOURCE_PATH:0)>

19:31 AimHere: Just checking if the compiler was smart enough to optimise out that + 0 preemptively

19:31 qbg: Clojure doesn't do magic like that :)

19:32 mk: so there can't be anything between the function, and the recur, is how I'm seeing it

19:32 qbg: It has to immediately return the result of the recur

19:33 mk: so even #(identity (recur (inc x))) wouldn't work (if I typed that right)

19:33 s/x/%

19:33 qbg: Correct

19:34 AimHere: Unless the clojure compiler is intermittently magic

19:34 qbg: Which it isn't

19:34 mk: interesting

19:34 AimHere: Damn you Rich. I need more magic in my lisp environment

19:35 qbg: Magic comes at a price

19:36 If you want magic, check out continuations :)

19:36 mk: it gets away with (if true (recur...)) though, because if is an... "upwards" construct, if that makes sense, but (+ 0 (recur...)) fails because it tries to mess with the value as it's falling back down from recur

19:37 qbg: There is nothing left to do in the if version; that decision has already been made

19:37 mk: Are you familiar with assembly?

19:38 mk: qbg: familiar but not proficient

19:38 qbg: A form is in tail position if you can replace the CALL with a JMP

19:38 That way your callee will return to your caller

19:39 mk: so numerous forms can be in tail position

19:39 qbg: For general TCO yes

19:39 mk: it's not about being in the last position of a list at all

19:39 AimHere: Yep. You can have more than one recur

19:39 qbg: Due to the JVM, you can only have recur

19:39 mk: TCO?

19:39 clojurebot: yes please

19:39 qbg: tail call optimization = replacing the CALL with the JMP

19:39 mk: ah, right

19:40 qbg: The JVM doesn't let you jump to other methods

19:41 mk: ok, recur makes much more sense now. Do I need to worry about the implementation, or should I treat it as the magic way to make recursion not die, only to be used in the tail position?

19:42 qbg: It doesn't matter :)

19:42 mk: yay abstraction

19:42 qbg: I think you can't recur across try though

19:43 Which makes sense if you think about i

19:43 *it

19:44 mk: that would make sense, because a try is really a ... throw is a special type of return, while try is a special type of conditional statement

19:44 qbg: If there is an exception thrown, there is still stuff to do!

19:44 mk: yeah - for one, you have to figure out which catch block it goes to

19:45 qbg: Namely you have to execute the catch block

19:45 mk: in java, sometimes we return null, and do a if(result==null){...}, other times we throw Ex, and put a }catch(Ex e){...} after it

19:46 qbg: And hopefully log it :)

19:48 mk: I don't think I'm a fan of exceptions, but I'm not sure what else there is

19:49 (I'm also not a fan of null)

19:49 qbg: throw new RuntimeException(e);

19:49 Or throw a checked exception without declaring it :)

19:52 mvid: does anyone here use heroku for a clojure app?

19:54 kisielk: does anyone have suggestions as to who to follow on 4clojure.org ? :)

19:54 mk: kisielk: I'm following the top N people, sorted by problems solved

19:55 kisielk: kind of weird that it doesn't let you look at whatever solutions you want once you've solved a problem

19:55 mk: ~4clojure

19:55 clojurebot: Excuse me?

19:55 kisielk: would be nice if you could aggregate / vote / comment on all solutions

19:56 hm, what's the power operator / function in clojure?

19:56 mk: kisielk: yes, I was thinking the same. many of the solutions are identical (or nearly so), so it would be better to just have a counter of the most common ones

19:59 are there comments in clojure?

19:59 xeqi: ,(Math/pow 3 4)

19:59 clojurebot: 81.0

19:59 kisielk: mk: of course

20:00 mk: kisielk: what are they?

20:00 qbg: ;

20:00 ; this is a comment

20:00 There is also the comment macro (rarely used)

20:00 mk: thanks

20:01 qbg: ,http://gunfacts.info/

20:01 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: Invalid token: http://gunfacts.info/&gt;

20:01 qbg: ,[1 #_2 3 4]

20:01 clojurebot: [1 3 4]

20:01 qbg: And that comment

20:01 Rarely used also

20:01 Just use ;

20:01 kisielk: I find the comment macro is useful if I have a module that has some functions that don't work yet, syntactically, but I want to save it and use it anyway :)

20:02 qbg: The downside of comment and #_ is that they have to be well formed

20:02 mk: kisielk: why can't you use ; for that?

20:03 muhoo: because it screws up the syntax highlighting

20:03 kisielk: mk: because I don't want to put a ; in front of n lines of code

20:03 mk: muhoo: ah

20:03 kisielk: where n > some small number :)

20:03 qbg: Maybe some day we'll have #| |#

20:03 mk: kisielk: your editor might have a "put a comment marker in front of selected lines" command hotkey

20:04 muhoo: #|o_o|#

20:04 kisielk: mk: it does actually

20:04 muhoo: sideburns :-)

20:04 kisielk: but that still means selecting the block of code

20:04 whereas I can just add (comment then jump to the bottom and add another paren

20:04 same thing I guess

20:04 just seems nicer :)

20:04 mk: your editor might have a "select the current block of code" hotkey :)

20:04 kisielk: mk: yeah, it has that too :p

20:05 I guess I just find it more aesthetically pleasing not to add a whole bunch of characters to my code :)

20:05 kenneth: hey, so i have this function: https://gist.github.com/098a1a56b8fcbbd87859. when i try to use it like this it errors out (arity error): ((derivative 3 #(+ %1 2)) 3)

20:06 i'm a total newbie, trying to pick it up by translating an algorithm i've already written in functional ruby

20:06 mk: kenneth: try 4clojure.com too

20:07 qbg: Missing paren

20:07 (f (+ x dx)

20:08 That code is also spread over more lines than it needs to be, IMO

20:09 kisielk: also you should probably use 2-space indents

20:09 those 2 things combined make it pretty hard to read near the bottom

20:09 qbg: You're actually calling (f (+ x dx) (f x))

20:10 kenneth: right, totally. nice catch, thanks

20:10 i still haven't quite gotten lispy indentation rules

20:10 qbg: #(/ (- (f (+ % dx)) (f %)) dx) is what I'd do

20:11 You can also replace (- 0 precision-magnitude) with (- precision-magnitude)

20:12 kenneth: ah neat

20:12 is % equivalent to %1?

20:12 qbg: Yes

20:12 kenneth: sweet

20:13 qbg: You can't nest the short hand anon functions though

20:13 kenneth: is there a way to make sure this function accepts a function with arity 1as argument only?

20:14 qbg: Do you really care?

20:14 There is no type system to enforce it

20:14 mk: kenneth: what do you expect it to do if that's not the case?

20:14 (not compile, throw an exception, return null...?)

20:15 qbg: If the function doesn't have a one arity form, it will cause an exception

20:15 Functions can have multiple arities

20:15 kenneth: i guess i don't care, is it not convention to do sanity checks in clj?

20:15 i'm used to doing a bunch of error checking to make sure i'm passed sane data

20:15 TimMc: kenneth: There are preconditions, but you can't use them to check arities.

20:16 kenneth: other quick question, in REPL, what does 1N mean in the output

20:16 qbg: I wonder if you could use reflection...

20:16 A bigint 1

20:16 They're contagious, like doubles

20:16 ,(+ 1 1N)

20:16 clojurebot: 2N

20:17 qbg: ,(+ 1 1.0)

20:17 clojurebot: 2.0

20:17 TimMc: qbg: Depends how fn* is implemented.

20:17 If it overrides AFn with just a few .invoke methods, sure.

20:17 qbg: TimMc: I'd assume that that fn* wouldn't override the unused arities in AFn

20:17 kisielk: kenneth: if you like strict checking like that, you might want to try Haskell some time ;)

20:18 kenneth: kisielk: i don't like it, i'm just used to having to do it

20:18 so a language where it's convention not to care is actually awesome to me

20:18 qbg: You should be good then

20:19 kenneth: sweet

20:19 kisielk: kenneth: coming from Ruby, I thought you'd be used to that :)

20:19 kenneth: kisielk: ruby is neat, but i also have to do a LOT of php and objective-c

20:20 mk: kenneth: I think the language designer compares type systems and unit tests to driving along the highway using those roadside barriers

20:20 qbg: It is duck typing taken to another level :p

20:20 mk: No, that is that TDD is like driving by running into the guardrails

20:20 kenneth: another question: is there a good way to do a real limit in clojure? i couldn't find one in ruby

20:21 kisielk: mk: that was just with respect to testing

20:21 qbg: kenneth: you mean mathematical?

20:21 kenneth: like, limit as h->0 for random-fn

20:21 yes

20:21 kisielk: there's probably some math libraries from Java you could use for that

20:21 qbg: There would be so many edge cases to consider

20:21 TimMc: ,(set (for [m (.getDeclaredMethods (class get)) :when (= (.getName m) "invoke")] (count (.getParameterTypes m))))

20:21 clojurebot: #{2 3}

20:21 qbg: Limits are interesting beasts

20:22 TimMc: qbg: ^ arities of #'get

20:22 or rather of get

20:22 (It is much easier if you have the var.)

20:22 mk: right, guardrails. And was it just tests? In the presentation I saw I thought he'd mentioned types shortly before, but I could be mistaken

20:22 qbg: Just tests from what I remember

20:23 TimMc: That's TDD done badly, of course. He's a bit too harsh on test-heavy development IMHO.

20:23 qbg: types are proofs, and are more powerful

20:23 Yeah, he isn't saying that tests have no value

20:23 It is just that you need to take into account other factors when designing code

20:23 kisielk: yeah, but he also seemed to say in that presentation (if we're talking about "Easy Made Simple" here) that having a hard proof of your code is not usually necessary

20:23 TimMc: kisielk: Simple Made Easy, but yes

20:24 kisielk: or was it Simple Made Easy

20:24 that's the one :)

20:24 qbg: Someone needs to do a parody called "Easy made simple"

20:24 kisielk: although I think it works the other way around too ;)

20:24 TimMc: Easy Made Complex: A primer for Java

20:25 mk: yes, that presentation. (His other ones at http://www.infoq.com/author/Rich-Hickey are great, too)

20:25 kisielk: actually it was that talk that got me to actually start learning Clojure

20:25 mk: kisielk: same here

20:25 kisielk: that and the fact that I'm getting sick of writing shitloads of unittests for the stateful code we have here

20:25 qbg: "stateful code"... Well there's your problem

20:26 kisielk: qbg: well, it's hard to teach everyone in your organization new ways of programming

20:26 qbg: especially when most of them are from a non-programming background

20:26 qbg: Could be worse

20:26 kisielk: qbg: and are almost actively opposed to actually learning the details of programming :/

20:26 qbg: Most projects where I work don't have much if any in the way of tests

20:26 kisielk: oh definitely

20:26 it's actually not so bad

20:27 just every once in a while one of the scientists decides it's a great idea to put their algorithm in a class

20:27 which has a bunch of random methods that add new attributes to the class instance

20:27 and rely on being called in a particular order

20:27 muhoo: oh gawd, i did some work recently for a customer who did java-style TDD without the T

20:27 qbg: wat

20:28 kisielk: those are the ones that make me angry

20:28 qbg: Did they use Coffee instead? :p

20:28 kisielk: IDD, insanity driven development

20:28 muhoo: it was all "oh, we'll just refactor it later"

20:28 but there were no tests to refactor to

20:28 kisielk: heh

20:28 qbg: You don't need tests when you have QA

20:28 muhoo: object spaghetti. i got so miserable that it sent me screaming, into the arms of clojure :-)

20:29 qbg: aka Questionable Assurance

20:29 muhoo: when i saw rhickey's presentation slamming OOP, it was like "MY SAVIOR!"

20:29 kisielk: sometimes my manager tries to use that when we bring something up in code review

20:29 "We should do it this way.." "Well, we can do it that way later, if we need to "

20:29 mk: clojure offers some immutable libraries for java, right?

20:29 alandipert: mk: you can use clojure's immutable collections from java

20:29 TimMc: kisielk: The term for that is "technical debt".

20:29 qbg: The data structures are written in java

20:29 kisielk: TimMc: yeah, fortunately we usually manage to convince him otherwise :p

20:30 TimMc: kisielk: This is an important phrase, since it speaks the language of business.

20:30 qbg: But they aren't generified

20:30 mk: is that just the clojure.jar that I see in my eclipse project?

20:30 qbg: yes

20:30 mk: I think those should be promoted a bit more

20:30 qbg: You also get a really old version of ASM with clojure.jar :)

20:30 kisielk: anyway, coming from Python Clojure has been fairly easy to get going with, it almost feels familiar

20:31 qbg: There was a library that separated out the Clojure collections and added generics

20:31 TimMc: kisielk: Except you can put dictionaries in sets. Ain't that somethin'? :-P

20:31 That was the final straw for me in Python -- non-hashable data structures.

20:32 kisielk: TimMc: you can put dictionaries in to sets in Python, if you subclass them and add __hash__ :)

20:32 qbg: TimMc: That is a good thing though

20:32 kenneth: okay, i put in a little rounding code to round limits which are almost correct

20:32 qbg: Having .hashCode on every object in java is broken

20:32 kenneth: https://gist.github.com/d76a89e5416d46952799 can you critique this? does this make senze?

20:32 sense*

20:32 kisielk: TimMc: also in Python 3 there's a proposal to add FrozenDict

20:33 qbg: kenneth: Too much on one line now :)

20:33 mk: I'd like to have someone explain composite values to me one day

20:33 qbg: mk: you mean like vectors, etc.?

20:33 kenneth: qbg: how would you break this up?

20:33 qbg: as being values?

20:33 kenneth: introduce let

20:34 (/ (- (f (+ % dx)) (f %)) dx) could probably be one local

20:34 mk: yeah. I don't mean data structures (list vs vector, different performance characteristics and all that), I mean just the basic (1 2)

20:35 kisielk: mk: the new Clojure book from OReilly is pretty good

20:35 TimMc: qbg: Broken in that things should have to declare they are hashable?

20:35 qbg: They're mutable

20:35 TimMc: Oh! Yeah.

20:35 qbg: identity hash code is the only thing that makes sense for a mutable object

20:35 mk: kisielk: I know the basics, but I don't understand what data of that form is supposed to represent

20:36 TimMc: Right, so Python "solves" that by removing hashability.

20:36 qbg: TimMc: Right

20:36 mk: for example, if we're dealing with a 2d point, we can use (2 3), or {x:2 y:3} - which one is right?

20:36 TimMc: yuck, never thought about it that way

20:37 kenneth: an, interesting i didn't think of that qbg. how's this? https://gist.github.com/759d8403cd16b6415cb1

20:37 qbg: mk: The second one is probably better from a readability point of view

20:37 kenneth: Better. (/ (round (* d precision-magnitude)) precision-magnitude) is a rounding idiom and should probably be pulled out

20:38 solidsnack: Should I use this for string operations? http://richhickey.github.com/clojure-contrib/string-api.html

20:38 lazybot: Nooooo, that's so out of date! Please see instead http://clojure.github.com/clojure-contrib/string-api.html and try to stop linking to rich's repo.

20:38 solidsnack: Woah.

20:38 qbg: At which point you could get rid of the let, or break down d

20:38 mk: qbg: perhaps. What I want to know is, what's the proper way to represent a point?

20:38 is it just a pair of numbers?

20:39 solidsnack: It is so cool that there is a bot for that.

20:39 mk: treating it as a map has disadvantages, in that you can't iterate over the dimensions (for higher-dimensional points)

20:39 kisielk: mk: however you like

20:40 or whatever suits your use case :)

20:40 antares_: mk: you can use a vector of 2 or a full blown record. Maps are also an option but records behave just like maps in many ways.

20:40 qbg: You could also use a defrecord

20:40 mk: kisielk: yeah, but that's a bit like answering "lisp or java" with "whichever you'd like" :)

20:40 qbg: You also have rectangular vs polar coords

20:40 kisielk: mk: I usually use vectors, personally

20:40 mk: one of them might be better, and there might just be a good wholesome way to think about composite values

20:40 kenneth: qbg: how about this https://gist.github.com/43d40ee5e9b12619ca1b

20:41 kisielk: mk: for 3d points it can also be advantageous to use vectors of 4 elements

20:41 mk: kisielk: 4?

20:41 kisielk: mk: http://stackoverflow.com/questions/3847743/4-element-vector-3d-math

20:41 qbg: kenneth: Looking good. The formula for deriv should be familiar to the reader, so you probably don't need to break down d

20:41 TimMc: mk: Just use [1 2] until it gets painful and you decide that something else is better.

20:42 If you don't need to present this in a public API, it's all good.

20:43 kisielk: hm, it's pouring rain and I didn't bring my jacket to work, that makes leaving difficult :(

20:43 mk: TimMc: perhaps, but I'm not just talking about simple points. There are substantially more complicated composite values out there

20:44 qbg: kenneth: Now it just needs docstrings

20:44 :)

20:45 mk: vectors and maps seem to just define names for the points (properties), but perhaps there's some sort of abstracted way to define the properties themselves

20:45 qbg: getter fns?

20:45 kisielk: Vector.getX()

20:46 mk: fns?

20:46 kisielk: see, it's encapsulated :P

20:46 kenneth: qbg: is there doc on how docs work in clojure?

20:46 qbg: (defn foo "docstring!" [x] ...)

20:46 Docstring and [x] are on new lines

20:46 (by convention)

20:47 TimMc: mk: You make a bunch of fns that can create and manipulate a certain abstraction.

20:47 *instances of a certain...

20:47 qbg: kenneth: The reason for that is that defn can have multiple arities

20:48 mk: maybe a better way to explain what I'm getting at is with a line(segment). lines can be defined using two points, or a single point with length and rotation, etc.

20:48 so now you have a composite "line value"

20:48 is it two points? is it a point and length and rotation?

20:49 qbg: mk: Sounds like you want a protocol so you don't care

20:49 mk: not really. It's something else, and you can get these other, primitive values by calling various things on the line composite value

20:50 where by "things" I mean :x1 :y1, :distance, etc.

20:50 qbg: protocol?

20:50 qbg: like an interface in Java

20:50 Only you can extend them to preexisting types and classes

20:51 TimMc: mk: Collection of fns.

20:51 That's all you need.

20:51 qbg: (single dispatch on type multimethods grouped together)

20:52 mk: ah, so the function part of a java object

20:53 qbg: You could define a Counted protocol (with count as the only protocol method in this case), and extend the protocol to various types

20:54 So then you can do (count "foo"), (count [1 2 3]), (count '(1 2 3)), (count <your type here>), etc.

20:55 mk: yeah, maybe. what I want, I think, is to hide the particular thing a protocol gets applied to. I don't need to know how a line is actually represented. It can be just a magic (abstracted) primitive value, as far as I'm concerned

20:56 qbg: That is what you with protocols

20:56 TimMc: mk: Do you understand that you can get the *exact same effect* by passing the mysterious objets around to various fns that collectively define an abstraction?

20:56 qbg: You don't care what it is, just that the appropriate protocols are defined for it

20:57 amalloy: yes, TimMc, exactly what i was about to say

20:57 protocols are a nice feature that clojure has, but you don't need them to accomplish the goal of abstraction

20:57 TimMc: mk: Seriously, don't mess with protocols until you are much more comfortable with Clojure, They are an advanced topic!

20:58 mk: TimMc: I'm not. They were suggested by others in response to my (vague) complaints about composite values

20:58 qbg: If you don't have multiple impls of 'lines', protocols are overkil

20:58 *overkill

20:58 amalloy: (defn make-line [a b] ...) (defn get-a [line] ...) (defn get-b [line] ...) (defn get-length [line] ...). if you want to, you can define a different way to make lines, and reimplement get-a, without changing the users of get-a

20:58 SICP has a bunch of material on this idea, in scheme

20:59 TimMc: algebraic something or other

20:59 mumble mumble

20:59 mk: amalloy: what gets returned by those functions?

20:59 amalloy: mk: by which? make-line returns "a line", represented in a way that the user doesn't care about

21:00 get-a returns one of the points in the line

21:00 qbg: This is merely the good parts of OO

21:00 mk: amalloy: can the user peek and see how it's represented?

21:00 TimMc: always

21:00 amalloy: *shrug*

21:00 TimMc: No matter what you do.

21:01 mk: then it's not what I'm talking about.

21:01 TimMc: then you're on crack

21:01 amalloy: probably, and if that bothers you you're hopelessly entrenched in Java

21:01 mk: relax

21:01 * TimMc relaxes

21:02 TimMc: mk: Even with interfaces, in Java, client code can always use reflection to poke around and find out the implementation details.

21:02 qbg: If you just care that it isn't a preexisting data structure, you can always use a ton of deftypes

21:02 mk: there are good reasons to hide that stuff. I'm not just talking about points here. If you expose it by returning a map, you'll have programmers using the map's :x and y:, or what have you

21:03 amalloy: spend your effort on enabling programmers to do good things, not on forbidding them to do bad things

21:03 TimMc: There's only so much you can do about programmers who do not respect the published API.

21:04 qbg: Values are immutable, so exposing those details doesn't hurt in that way

21:04 mk: TimMc: reflection is as good as not part of the spec. I'm not being paranoid about encapsulation, I just don't want to expose things by default

21:04 amalloy: qbg: that's not really true

21:04 muhoo: "I, am an API, and you must respect mah authoroitah!"

21:04 TimMc: qbg: I think the concern here is casual misuse of implementation details.

21:04 qbg: (by that way = by mutating them)

21:05 amalloy: if someone does start using implementation details, it means you can't change them without breaking them. nobody said anything about mutating

21:06 TimMc: alexbaranosky: I'm ready to learn midje.

21:06 amalloy: but just...tell them not to do that. you don't need huge wrought-iron guardrails

21:06 mk: it isn't true at all. By exposing those values, you get people writing code that makes use of them. But you might want to use a different representation of the same value (imagine a serious performance constraint)

21:06 qbg: Perf constraint -> code that uses them in the wrong way is broken

21:06 * -> code that uses them in the wrong way is broken

21:07 emezeske: IIRC you can still get at private vars. Which is good -- you have to jump through enough of a hoop that you can't complain when the library author changes that private implementation detail

21:07 TimMc: alexbaranosky: I have a function that shells out, and it's a little too complicated to set up a testing environment for the command. So... I can mock the shelling out?

21:07 qbg: emezeske: Yep, @#'namespace/private-var

21:08 mk: there might not even be private vars. There might just be function calls.

21:08 qbg: (use that for tests only if at all!)

21:08 emezeske: qbg: Yeah, that!

21:11 mk: can values be created from scratch in clojure? eg: new Object()

21:12 emezeske: ,(Object.)

21:12 clojurebot: #<Object java.lang.Object@1d40019>

21:12 scottj: ,(new Object)

21:12 clojurebot: #<Object java.lang.Object@18b1fdb>

21:14 yoklov: How can I do this better: https://gist.github.com/1963683

21:15 TimMc: yoklov: You just want to deinterleave a collection?

21:15 yoklov: yup

21:15 mk: amalloy: sometimes there's not much of a difference between enabling good things and forbidding bad. The good thing in this case is "stop thinking of it as a point pair - it's just a line"

21:15 yoklov: while maintaining order

21:16 qbg: ,((juxt first second) (partition 2 [1 2 3 4 5 6 7 8]))

21:16 clojurebot: [(1 2) (3 4)]

21:16 TimMc: try again :-)

21:16 amalloy: &(apply map vector (partition-all 2 (range 10)))

21:16 lazybot: ⇒ ([0 2 4 6 8] [1 3 5 7 9])

21:16 qbg: Yep, fail sauce there

21:16 TimMc: &(apply map vector (partition-all 2 (range 9)))

21:16 lazybot: ⇒ ([0 2 4 6 8])

21:17 amalloy: haha

21:17 yoklov: lol

21:17 amalloy: well, don't do it if it's not evenly divisble, silly

21:17 kenneth: so i have this algorithm that does a loop until something is found. what's the best way to write this in clojure

21:17 ?

21:17 TimMc: just sayin'

21:17 amalloy: I'm actually having trouble understanding that result. Give me a minute.

21:17 amalloy: TimMc: one of the colls has length 1 instead of 2

21:17 TimMc: (I thought it would only lose one value.)

21:17 amalloy: so map stops

21:18 TimMc: yes, got it

21:18 amalloy: if you drop the -all, it just loses the last pair, which probably makes more sense

21:18 TimMc: &(apply map vector (partition 2 (range 9)))

21:18 lazybot: ⇒ ([0 2 4 6] [1 3 5 7])

21:18 TimMc: righto

21:18 kenneth: is it side-effecty?

21:19 reading, writing, mutating...

21:19 kenneth: TimMc: it's not

21:19 qbg: kenneth: (first (filter ...)) might work for what you're doing

21:19 TimMc: kenneth: (loop [...] (if ... ret-expr (recur ...)))

21:19 kenneth: it's a gradient descent algo, here's the ruby code i'm trying to translate https://gist.github.com/bafcc45bd9ae332c1238

21:20 yoklov: if it makes a difference, I don't care that the seqs are vectors… my implementation doesn't handle odd vectors really either, as the last element of the 2nd is nil in that case

21:20 TimMc: &(apply map vector (partition 2 2 [nil] (range 9)))

21:20 lazybot: ⇒ ([0 2 4 6 8] [1 3 5 7 nil])

21:21 TimMc: (if you had wanted that)

21:21 yoklov: Huh

21:21 i hadn't haha, but that's interesting that that works

21:21 TimMc: partition is fantastic, it can do all sorts of overlap and skip tricks

21:21 well, not all sorts, just those, really

21:22 yoklov: that's nifty

21:22 TimMc: kenneth: So you need to push some state around in a loop until some condition is triggered, yeah?

21:22 kenneth: that's the way i did it in ruby

21:23 can't think of a functional way off the top of my head

21:23 TimMc: loop is going to be the most straightforward translation

21:23 yoklov: its a weird problem because it goes by the index of the collection as opposed to its values, couldn't use something like reduce because of that

21:24 TimMc: but you could easily do something with (first (filter (iterate ...))) if you're only hammering on one data structure.

21:24 qbg: (first (drop-while (reductions ...))) might work

21:24 Or TimMc's one

21:24 TimMc: reductions is only useful if you're folding in some collection

21:25 mk: how should one decide between Programming Clojure, and Joy of Clojure? or are there better books?

21:26 yoklov: i'll probably just stick with my (now modified to return different lengths) current function

21:26 oh

21:26 hm

21:26 yeah.

21:27 qbg: mk: Programming Clojure (1st edition) is a bit old

21:27 2nd edition is being worked on though

21:28 mk: I should go with Joy, then?

21:28 qbg: Do you really need a book is another question

21:29 TimMc: yoklov: Stick with loop for now. There's not necessarily much to gain from converting it into a more functional approach immediately.

21:29 mk: it would be nice to have a go-to place for explanations of things I run into

21:30 qbg: I knew too much when I read JoC to have a well informed position on it

21:30 mk: what was your over-informed position?

21:30 qbg: I already knew everything :)

21:31 I think I liked programming clojure better though

21:31 emezeske: I read JoC knowing basically nothing about Clojure or Lisp in general

21:31 mk: gotcha :)

21:31 emezeske: And I liked it quite a bit

21:31 qbg: I hope the second edition is as good as the first :)

21:31 yoklov: yeah, i think think there might be a chance that this function won't get called with a seq of odd length anyway

21:32 ivan: I kind of wish JoC was twice as long

21:33 qbg: All of the books should be much longer :)

21:33 TimMc: yoklov: Wait, you're not the one with the ruby code. I'd use map vector partition instead of loop.

21:33 qbg: And dive into really awesome topics

21:34 mk: qbg: perhaps academic papers etc. are more your thing?

21:34 what sort of topics?

21:34 qbg: LiSP is a really awesome book

21:34 yoklov: haha, alright.

21:35 qbg: Yeah, programming languages (mainly Lisp) are my thing.

21:35 yoklov: qbg: LiSP is great

21:35 qbg: 13 interpreters and 2 compilers!

21:36 yoklov: yup, that sounds like the right number haha

21:37 qbg: I remember only being able to count 11 interpreters though

21:38 yoklov: I sorta was a little bored with JoC also because i had been writing scheme for a while, but I think that might have just been mostly a kneejerk reaction.

21:39 qbg: Programming Clojure was a required textbook for a class. JoC took over a semester to arrive. :)

21:41 yoklov: strange, didn't realize clojure was old enough for any schools to start teaching it

21:42 qbg: This was about a year and a half ago.

21:43 mk: what year was the course aimed at?

21:43 qbg: That class existed because of my passion for Clojure

21:44 It was CSci 4409, so undergrad juniors/seniors

21:44 yoklov: what was the subject of the course?

21:44 qbg: It was clojure with ~2 weeks of erlang at the end

21:45 http://cda.morris.umn.edu/~elenam/4409_fall10/index.html

21:45 yoklov: oh, alright, that makes sense

21:46 qbg: We did a parking lot simulator :)

21:46 (in the same sort of vein as the ant colony program)

21:48 Also, we did Hadoop completely wrong

21:48 yoklov: that makes sense. had the subject been anything other than concurrency, I might have complained about clojure being too complex to be interesting pedegogically (but that's just my bias as someone who used to TA a course in scheme)

21:48 *too complex compared to scheme :p

21:48 dnolen: holy moly - PersistentVectors scream on V8

21:48 qbg: Do not have 20 hadoops file systems on multiple boxes but on the same vfs

21:49 dnolen: Benchmark?

21:49 mk: what did scheme introduce that was much different from mccarthy's lisp?

21:50 qbg: lexical scope

21:50 yoklov: yeah.

21:51 qbg: yoklov: Clojure could be a useful replacement for Scheme in an intro course if the error messages were better

21:52 IDE tooling is getting there with CCW

21:52 yoklov: eh.

21:52 i'm not sure about that

21:53 qbg: Racket has the advantage of subseting the language though

21:53 yoklov: I don't see any real benefits to teaching an intro course in clojure, and the comparitive complexity of the language hurts it.

21:54 dnolen: qbg: slower than arrays but I can't believe JS has come to the point where this can work at all

21:54 yoklov: besides, the best intro textbook was written in scheme :p

21:54 dnolen: qbg: access times on a PersistentVector of a million items is within 4X-5X of JS arrays

21:54 qbg: yoklov: In return you get lazy seqs as a topic to consider, and the language is more useful in later courses

21:55 dnolen: PersistentVectors are smoking fast on V8

21:55 yoklov: the course I TA's used lazy sequencess

21:55 dnolen: qbg: seems like most of the optimization strategies used in Clojure can easily be applied to CLJS and they will work on modern JS runtimes.

21:55 ibdknox: dnolen: sweet

21:55 qbg: Now we're cooking with gas!

21:55 yoklov: streams are SICP section 3.6 (maybe 3.5)

21:55 dnolen: ibdknox: no more stupid slow copy on right ;)

21:55 write

21:56 qbg: streams are more ugly though IMO

21:56 ibdknox: dnolen: is this in a branch somewhere?

21:56 yoklov: clojure's lazy seqs are "magic" though.

21:56 streams have an understandable implementation

21:56 dnolen: ibdknox: no I just ported the Java to see if it was worth bothering at all

21:56 Java -> JS

21:56 qbg: yoklov: not really any different

21:56 ibdknox: sweet

21:57 I assume there's optimizations to be done there too that would make them even faster then

21:57 qbg: dnolen: Didn't go the gvec route?

21:57 yoklov: no difference between an implementation in java versus using `delay` and `force` to implement your own?

21:57 dnolen: qbg: no PV should be implemented in CLJS, but CLJS needs an optimization pass first

21:58 mk: I'm on eclipse, and hitting f11 after changing code takes an annoyingly long time. Is there a way to quickly restart the program with .clj changes applied?

21:59 qbg: yoklov: That is basically how it works in Java. Clojure has the advantage that all of that is built in and all of the built ins use it

21:59 mk: Just load the modified file?

21:59 Into the running instance

21:59 dnolen: https://github.com/swannodette/persistent-vector

21:59 mk: qbg: how?

21:59 qbg: It can create non-reproducable states, but can be worth it

22:00 mk: in CCW?

22:00 It is in the Clojure menu

22:00 dsantiago: dnolen: That's pretty cool. Was wondering when CLJS was gonna get the real persistent data structures.

22:00 qbg: 'Load file in REPL'

22:00 yoklov: qbg, I'm not saying it works differently in java, I'm saying the students will come out with a much deeper understanding of streams if they implement them themselves

22:00 mk: yes, ccw

22:01 will this clear the current state back to default?

22:01 qbg: yoklov: True, but Clojure allows for laying some of that foundation sooner

22:01 dnolen: dsantiago: there's tons of optimization work to do, real persistentn data structures is part of that.

22:01 qbg: It depends on how you would teach it

22:02 The main issue in either case is that 1 semester is pretty short

22:02 dsantiago: Probably worth keeping the copy on write ones around.

22:02 qbg: dnolen: I'm assuming no persistent maps yet, right?

22:02 dnolen: qbg: this was just an experiment to see if V8 could perform well with this kind of code

22:03 qbg: Good enough

22:03 dnolen: qbg: now that we see that it does, yes, all the data structures should get ported

22:03 written in CLJS - and the compiler should be able to produce JS code that is competitive w/ this JS

22:03 qbg: We need a punny name for a Clojure web framework on node right now

22:03 yoklov: I'd want to teach it by having them implement it themselves. I don't think a single semester is too short of a time to work with, but if you have to explain the langage as well as the concepts it becomes so.

22:04 the benefit of scheme is that the language is incredibly simple

22:04 dsantiago: qbg: seijure

22:05 mk: pretty amusing but potentially insensitive

22:05 qbg: yoklov: The one thing I found lacking about my intro csci class is that after it we went to Java

22:06 Given such a setup, Clojure might be useful for the dividends paid in later classes

22:07 yoklov: right, but then you're sacrificing teaching computer science for teaching a specific platform.

22:08 qbg: The languages are a means to an end anyways

22:08 Clojure is still fairly simple, but it is more industrial, which has disadvantages

22:09 yoklov: clojure's much more complex than scheme in both syntax and semantics.

22:09 ztellman: wow, just came across the discussion of my libraries from a week ago

22:09 those are some heated words

22:09 yoklov: which is why it's useful.

22:09 and scheme isn't

22:10 qbg: IIRC, HtDP uses () and []

22:10 yoklov: SICP > HTDP, besides iirc they're totally interchangable

22:10 they are in racket, at least.

22:10 ibdknox: ztellman: ?

22:11 qbg: Yeah, SICP is awesome

22:11 Still, if you use HTPD (like my school has for the past few years), you have to explain that syntax anyways

22:11 ztellman: ibdknox: http://clojure-log.n01se.net/date/2012-02-24.html#18:12b

22:11 qbg: loop/recur could actually be an advantage over Scheme when it comes to tail recursion

22:12 ztellman: not that the code doesn't warrant it

22:12 qbg: I remember that potemkin discussion!

22:12 yoklov: ah, we use SICP. Still, how complex is "these are totally interchangable and theres no difference", versus [] is a vector and () is a list and in clojure the arglist has to be a vector as does the bindings of a let form... etc

22:12 ztellman: but honestly, don't judge until you try to create a map with slightly altered behavior

22:12 ibdknox: ztellman: ah, my argument was that it shouldn't matter

22:12 ztellman: until you walk a mile in my lazy-map shoes...

22:13 ibdknox: yeah, it's mostly just funny

22:13 I got a google alert on the madman comment

22:13 qbg: What I really don't like about HtDP is the lack of let from what I've seen

22:13 yoklov: and i disagree about your statement re: loop/recur.

22:13 qbg: How do you not cover let?

22:13 yoklov: HtDP doesn't cover let?

22:14 ztellman: ibdknox: also, the performance issues are going to become a thing of the past soon :)

22:14 qbg: From what I've seen of the problems from that case, they use nested defines instead

22:14 (I haven't actually taken a look at HtDP)

22:15 yoklov: I've never used HtDP or read it, I don't know.

22:15 ibdknox: ztellman: that's awesome :D

22:16 ztellman: noir works very cleanly with aleph and I've been directing folks looking to do websockets to it

22:16 technomancy: let is just syntactic sugar for lambda

22:16 yoklov: SICP covers it http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-12.html#%_sec_1.3.2

22:16 qbg: When I took the course we used "Scheme And The Art of Programming"

22:17 yoklov: even explaining its expansion in terms of lambda (which is crucial for understanding parts of chapter 4 later)

22:17 ztellman: ibdknox: once I get these things out the door, I'd like to implement https://github.com/ry/node_chat using a variety of protocols

22:17 TimMc: ztellman: I'm just amused that you wrote out all those invoke arities. :-)

22:17 ztellman: TimMc: would you believe someone actually did that for me?

22:17 it was a pull request

22:17 TimMc: haha, nice!

22:17 ztellman: let me see if I can track it down

22:18 TimMc: Whoa, does postwalk strip-namespaces do what I think it does?

22:18 That's hella handy.

22:19 ztellman: ibdknox: I'd like to do it using noir, is the reason I mention it, I'll track you down when I'm getting started on that

22:19 also, check this out: https://github.com/dthume/aleph/commit/47d343edd37120d71534349bcacf9e52ecf30972

22:19 it's the best pull request ever

22:19 I had to keep it

22:21 ibdknox: ztellman: haha that's awesome

22:21 get everyone else to do it ;)

22:21 ztellman: ibdknox: I would have just written a macro to generate it

22:21 but that sort of hard work deserves a permanent home in potemkin

22:21 ibdknox: :)

22:22 ztellman: home to, among other things, unify-gensyms: https://github.com/ztellman/potemkin/blob/master/src/potemkin/macros.clj#L22

22:22 TimMc: My obsessive-compulsive tendencies make me want to check that for typos. >_<

22:22 ztellman: all gensyms followed by ## are forced to the same gensym, even if they're generated in different syntax-quotes

22:22 technomancy: how did you know it wasn't an emacs macro?

22:22 qbg: sick

22:22 ztellman: technomancy: I choose to believe it wasn't, the world's a more absurd place that way

22:24 technomancy: tellman's razor

22:24 ibdknox: lol

22:24 ztellman: I like it

22:24 qbg: Awesome: (namespace/import-macro namespace/import-macro) ;; totally meta

22:24 ztellman: potemkin's a great project

22:24 an awful project too

22:24 qbg: an awfully great project?

22:25 yoklov: ztellman: have you ever had a use for that one?

22:25 ztellman: yoklov: which one?

22:25 yoklov: unify-gensyms

22:25 ztellman: oh, sure

22:26 technomancy: back in my day we had to let-bind our gensyms!

22:26 ibdknox: gensyms are currently fucking up my form comparisons :p

22:26 technomancy: I mean, let-bind explicit (gensym) calls

22:26 qbg: Yeah, those good ol' days

22:26 ztellman: so if you have something like `(let [x# 1] ~@(map (fn [x] `(… x#) …)))

22:26 that doesn't work

22:26 because they're gensymed in different scopes

22:27 TimMc: Yep, I use explicit (gensym ...) calls for those currently.

22:27 ztellman: you end up having to explicitly call (gensym …) outside the scope

22:27 qbg: Too bad syntax-quote is a reader thing

22:27 yoklov: that is strange, i had no idea.

22:28 ztellman: TimMc: me too, then I wrote https://github.com/ztellman/lamina/blob/perf/src/lamina/core/pipeline.clj#L236

22:28 which had like eight explicit gensyms

22:28 and I got sick of it

22:28 technomancy: isn't there any danger of unify-gensyms accidentally collapsing gensyms with false positives?

22:28 ztellman: technomancy: it assumes no one else is using ## as a suffix

22:28 but if you call unify-gensym on an inner form, it re-normalizes it

22:28 technomancy: ztellman: oh I missed that part

22:28 TimMc: technomancy: Back in MY day, back when Fortran wasn't even Three-tran... we used our names in gensyms to prevent collisions: timmc__foo-project__123

22:29 technomancy: hah; three-tran

22:29 nice

22:29 TimMc: it's from a song

22:29 ~kids these days

22:29 ztellman: so you can protect against getting unified by an outer scope

22:29 clojurebot: Get off my lawn!

22:29 TimMc: clojurebot: back in the day?

22:29 clojurebot: I don't understand.

22:30 yoklov: `(fn [f#] (f#))`, err, why do you need a gensym there?

22:30 ztellman: also, I'm actually pretty confused by all the hate on import-fn, what's not to like about being able to decouple the presentation of your API and the structure of your code?

22:30 TimMc: clojurebot: back in the day is http://www.stevemacdonald.org/lyrics/wiwab.html

22:30 clojurebot: You don't have to tell me twice.

22:30 TimMc: technomancy: ^

22:31 And I wasn't kidding about using your name in symbols.

22:31 except that I'm not actually that old

22:31 ztellman: yoklov: as opposed to #((%)) ?

22:31 technomancy: TimMc: yeah, I occasionally write elisp, so I know that pain =(

22:31 no module system

22:31 TimMc: eep

22:31 yoklov: or just (fn [f] (f)), isn't f scoped so that it doesn't matter what you call it?

22:32 ztellman: if you declare an ungensymed variable inside a macro, it will try to resolve it

22:32 yoklov: oh, you know, that makes sense.

22:32 technomancy: TimMc: most elispers cheat and use their initials

22:32 but that's just asking for trouble!

22:33 yoklov: i don't write many macros but i've been constantly confused by their error messages when i do.

22:33 TimMc: org_DOT_timmc_DOT_foo-project_123

22:33 ztellman: yoklov: basically just gensym everything that isn't explicitly defined elsewhere

22:33 TimMc: I'll quote you as "basically just gensym everything"

22:34 gensym until it stops working

22:34 qbg: gemsyms, gemsyms everywhere

22:34 yoklov: lol, thats what ends up happening but i've never really got why it was needed there. I didn't realize it resolves the things that weren't gensymed

22:35 qbg: that and you don't want name conflicts

22:35 (usually)

22:35 TimMc: &`(f f#)

22:35 lazybot: ⇒ (clojure.core/f f__9425__auto__)

22:35 yoklov: well, right, but i gensym those

22:36 TimMc: :-)

22:36 yoklov: things like (fn [f] (f)) i wouldn't have though

22:36 and would have gotten an error

22:36 amalloy: clojurebot: qbg is <reply> <qbg> basically just gensym everything

22:36 clojurebot: c'est bon!

22:36 TimMc: amalloy: or ztellman maybe

22:37 if you're into correct quoting and that sort of thing

22:37 ztellman: my battlecry

22:37 TimMc: s/quoting/attribution/

22:37 amalloy: oh. i can't read

22:38 technomancy: interesting; defproject is the only defmacro in leiningen

22:42 wow, Opa is listed as a distinct language on github

22:42 popularity: #71

22:42 TimMc: Never heard of it.

22:42 technomancy: just above Ioke

22:43 TimMc: it sounded to me like a web framework for ocaml, but I guess it claims to be a distinct language

22:44 ibdknox: Opa is weird

22:44 talios: Opa is a language from memory - but it serves client/server side in the same source file ( same method even )

22:44 Was a very…. odd looking setup.

22:44 ibdknox: http://opalang.org/

22:45 zakwilson: Oh, good. ibdknox is here!

22:45 * ibdknox hides

22:45 zakwilson: ibdknox: I'm looking for docs on Korma's join.

22:45 talios: they changed to a JS like syntax now? interesting

22:45 ibdknox: zakwilson: I haven't generated 0.3 docs yet :/

22:46 zakwilson: (join :inner :some-table-or-ent (= :some.key :some.otherkey))

22:46 or

22:46 technomancy: can't find any lang rankend lower on github than opa

22:46 ibdknox: (join some-ent)

22:46 (join some-ent (= ...))

22:46 zakwilson: ibdknox: join is new? It responded... poorly to trying to use where, or the map syntax used by where.

22:46 ibdknox: the map thing won't work.. though I guess it could

22:47 it's not new, but it did change

22:47 zakwilson: It seems Bad that join and select wouldn't use a similar syntax.

22:47 technomancy: huh; html literals. everyone hates that in scala; I wonder if the same problems apply here.

22:47 ibdknox: zakwilson: they use the same syntax

22:47 zakwilson: Like... the sort of Bad thas SQL itself has.

22:47 ibdknox: (where (= :blah 1))

22:47 zakwilson: I think all the examples use maps with where.

22:48 (where {:blah 1})

22:48 or (where {:blah [> 1]}), etc...

22:48 ibdknox: I generally prefer that syntax

22:48 but it doesn't seem right in this case

22:48 (join some-ent {:blah :cool})

22:48 doesn't really make sense

22:49 whereas (join some-ent (= :blah :cool)) does

22:49 let me take a look at why it doesn't work

22:49 zakwilson: I'm not sure, but without docs, I figured anything that works for where should work with join (and actually, I assumed join would USE where)

22:51 ibdknox: huh?

22:51 like implicit joins?

22:51 those don't work in some dbs

22:51 it uses the join syntax

22:52 TimMc: zakwilson: Do you mean converting JOIN constraints into WHERE constraints?

22:53 zakwilson: No, I just mean that you would write (join foo (where (= :bar baz))) instead of (join foo (= :bar baz)) because select is that way.

22:54 ibdknox: huh?

22:54 it's a join clause

22:54 do you mean with?

22:54 with does that

22:55 zakwilson: btw there are docstrings for all of this. I just fixed the map thing for you too :)

22:55 weavejester: I think I should probably drop Clojure 1.2 compatibility in my libraries…

22:55 In new versions anyway

22:55 Is anyone still using 1.2 for projects?

22:56 zakwilson: No. I mean that one would write (select foo (where (= :bar baz))), and it seems like a strange thing that join is different.

22:56 weavejester: I am because some library, I think it's clojureql wasn't on 1.3 last I checked.

22:56 I'm working on getting off clojureql, so I don't really object in principle.

22:57 ibdknox: weavejester: we are :(

22:57 weavejester: ibdknox: Would Ring 1.1 depending on Clojure 1.3 impact you then?

22:58 technomancy: weavejester: there are still a number of internal private projects still on 1.2

22:58 TimMc: zakwilson: I think that's the SQL WHERE clause you're looking at there.

22:58 rsenior: weavejester: I started migrating projects to 1.3 this week, will probably take a while

22:58 zakwilson: ibdknox: thanks for the fix, BTW. I'm going to proceed to not use it right now.

22:58 ibdknox: weavejester: I believe so, though with some diligence I think we can get off 1.2.. just hasn't been in the cards

22:58 TimMc: ibdknox: What is blocking you?

22:58 technomancy: weavejester: what's the motivation? is it just to use the handy ^:metadata notation?

22:58 weavejester: Maybe I'll keep 1.2 compatibility around then

22:58 ibdknox: zakwilson: haha, I think the confusion is in how korma is mapping directly to SQL

22:59 technomancy: becaues that's really the only thing I've noticed since upgrading to 1.3 in Leiningen

22:59 weavejester: technomancy: No real motivation other than 1.3 being new and shiny :)

22:59 zakwilson: TimMc: in clojureql, one writes (select foo (where ...)) and (join foo bar (where ...)). I'm wondering why Korma isn't that way.

22:59 ibdknox: zakwilson: where creates a WHERE while (join) will create JOIN blah ON blah.id = cool.id

22:59 technomancy: (plus bugs related to that silly RTE-wrapping)

22:59 if the ^:metadata syntax were backported to 1.2.2 I'd be tempted to stick with it

22:59 zakwilson: ibdknox: yes, that's the cause of my confusion.

23:00 weavejester: 1.2 just feels old, but… there's no reason not to support it. There's nothing in the Ring 1.1 and Hiccup 1.0 snapshots that rely on it.

23:00 ibdknox: zakwilson: korma adheres to SQL as much as possible

23:00 zakwilson: ibdknox: SQL makes puppies whimper and hide under the bed.

23:00 ibdknox: TimMc: I think we're relying on a couple of stupid things that still need contrib. I don't remember what off the top of my head though.

23:01 technomancy: weavejester: it's old but trusty

23:01 ibdknox: zakwilson: not really, in this case I would argue that this solution is actually more succinct and obvious

23:01 mk: how do I use aleph with ccw?

23:01 zakwilson: Anyway, confusion cleared up. I can now proceed to replace some more CQL.

23:01 weavejester: ibdknox: Do any of your internal projects use Hiccup?

23:02 ibdknox: weavejester: all of mine do in some fashion

23:02 weavejester: ibdknox: Do you think the Hiccup namespace rearranging for 1.0 would cause you problems?

23:02 TimMc: ibdknox: I see, transitive deps.

23:02 ibdknox: weavejester: I wholeheartedly agree with that change and have no issue with fixing those cases

23:02 weavejester: I don't mind it if it's things I can fix

23:03 1.3 is a bit harder

23:03 technomancy: weavejester: have you seen lein precate?

23:03 ibdknox: since as TimMc said, it's transitive dependencies :(

23:03 weavejester: ibdknox: So far that seems to be the consensus. I do want to fix the Hiccup namespaces.

23:03 technomancy: Nope...

23:03 technomancy: What does it do?

23:03 technomancy: weavejester: the idea is that upgrades to non-backwards-compatible versions can be automated

23:04 ibdknox: weavejester: just let me know when and I'll go through everything in Noir/the docs and fix it up

23:04 technomancy: lein precate > project.clj # and you're compatible with leiningen 2

23:04 https://github.com/technomancy/lein-precate

23:04 zakwilson: Did I hear something about cake and lein merging?

23:05 technomancy: zakwilson: aye

23:05 TimMc: technomancy: Does precate use some fancy new surface-form-preserving reader that I haven't heard about yet?

23:05 weavejester: ibdknox: It'll have to coincide with Ring 1.1, as ring-devel depends on the old version

23:05 technomancy: TimMc: no, you lose comments and indentation unfortunately

23:05 I would love to preserve that, but no such thing exists

23:05 zakwilson: Will there be any rough edges if I update?

23:05 weavejester: technomancy: Ohh - is it just for project.clj transitions from lein1 to lein2?

23:06 technomancy: zakwilson: wait another week or so and there will be a preview release of lein2

23:06 weavejester: yeah

23:06 weavejester: just an idea; don't know if it'd be practical for you

23:06 * zakwilson can wait.

23:06 weavejester: I'll take a look tomorrow

23:09 mk: how can I start using aleph from inside eclipse/ccw?

23:10 zakwilson: ibdknox: I'm using select* and (modifier "distinct") and getting SELECT ["distinct"] ...

23:10 mk: it seems to need lein and defproject (Unable to resolve symbol: defproject), but there's no info on what I should do with this

23:10 ibdknox: zakwilson: yeah that was a bug in one of the betas

23:10 zakwilson: I just pushed beta5

23:10 zakwilson: ibdknox: yay!

23:11 Oh. I was on alpha9. I thought I was on beta4. I don't know how this happened.

23:11 Let's see what explodes!

23:11 ibdknox: should just be fixes

23:12 I think

23:12 zakwilson: I have a very faint memory of there being some reason I couldn't use beta4, but it might have just not been on clojars when I tried to use it or something silly.

23:13 Anyway, I hope it doesn't sound like I'm complaining. I really like your stuff.

23:13 ibdknox: not at all! Glad someone's using it :)

23:14 zakwilson: In three projects.

23:14 including client work: http://renthubnyc.com/

23:14 ibdknox: sweet

23:15 semperos: in my project.clj, I have :source-path set to "src/clj" and :java-source-path set to "src/java"

23:15 zakwilson: I'm excited to have work to show off that isn't some private internal tool I can't send people to play with.

23:16 semperos: but when I do `lein compile`, I get errors from code inside "src/java"

23:16 thought `lein compile` was only meant to compile Clojure source?

23:17 ibdknox: is there a way to read code without invoking reader-macros? and subsequently expand them later?

23:17 amalloy: ibdknox: slurp :P

23:17 ibdknox: lol

23:18 amalloy: (because really, everything's a reader macro. ( is a reader macro that reads until a matching ) and puts the results into a list)

23:18 ibdknox: ok, how about a good way to remove all gensyms from a form then?

23:18 technomancy: semperos: it's assumed that if you have java code, your clojure code is dependent upon it

23:18 zakwilson: Yay! beta5 makes everything better

23:18 amalloy: huh?

23:18 technomancy: semperos: leiningen 2 will have more flexibility in this regard

23:18 semperos: technomancy: understood, thanks

23:18 ibdknox: amalloy: I'm reading files and comparing the forms to determine which top-level forms have changed. Gensyms totally fuck that up for me

23:19 since they'll always be different after very read

23:19 amalloy: hmm

23:19 ibdknox: my naive thought was to walk to code for symbols, if the name has a # in it remove it

23:19 semperos: technomancy: will have, or already does if I pull it down from Github and use that lein instead?

23:19 ibdknox: the code*

23:19 amalloy: i'm not sure you can do that

23:20 not if you invoke read

23:20 you have to just compare the strings, i think. use the reader to determine where forms start and end, and compare the string sources inside those bounds

23:21 technomancy: semperos: it's already implemented if you want to give it a run

23:21 semperos: technomancy: sweet, will do

23:21 technomancy: though that part in particular may not be documented; you want to add a :prep-tasks ["compile"] to defproject if you want javac to not be automatically invoked

23:22 and maybe that will work! if it doesn't please open an issue; I'm headed off for now

23:22 ibdknox: amalloy: the thing is that I don't really want adding a new line to cause everything to be "changed"

23:22 semperos: technomancy: sounds good, thanks for the tip

23:22 ibdknox: so this seemed like a clever solution

23:22 technomancy: hope it works well for you

23:22 ibdknox: lol

23:22 amalloy: ibdknox: it's a clever solution that doesn't work, though, right?

23:22 so...

23:22 ibdknox: well, if I just walk the form and remove all symbols with a name containing # and it would

23:22 amalloy: gensyms don't have # in them

23:23 &'`(fn [x#] x#)

23:23 lazybot: ⇒ (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/fn)) (clojure.core/list (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list (quote x__9440__auto__)))))) (clojure.core/list (quote x__9440__auto__))))

23:23 ibdknox: ,(read-string "#(inc 1)")

23:23 clojurebot: (fn* [] (inc 1))

23:23 ibdknox: ,(read-string "#(inc %)")

23:23 clojurebot: (fn* [p1__55#] (inc p1__55#))

23:23 TimMc: those are double gensyms or something

23:24 ibdknox: for some reason, those are the only ones that are screwing me up

23:24 TimMc: &`#(%)

23:24 amalloy: ibdknox: are you sure? `(fn [x#]) should be different every time you read it

23:24 lazybot: ⇒ (fn* [p1__9448__9449__auto__] (p1__9448__9449__auto__))

23:24 ibdknox: I'm doing this only with clj code, so no macros will be read in it

23:24 cheating, I guess

23:24 amalloy: huh?

23:25 TimMc: ibdknox: cljs, you mean?

23:25 ibdknox: sorry

23:25 yes

23:25 TimMc: I like the "read it twice" idea.

23:25 amalloy: cljs still supports ` though, doesn't it? even if you don't use it for macros

23:26 i guess it doesn't really matter, because nobody will put gensyms in it if you're not generating code

23:26 ibdknox: TimMc: I did too, but there's no way to do it right?

23:27 TimMc: some kind of parallel treewalk to find mismatched symbols...

23:28 ibdknox: amalloy: yeah, like I said, cheating

23:28 TimMc: I guess the worst-case scenario here is where one gensym changes to another.

23:29 ibdknox: What happens if you chop off all #"__.*" from symbols?

23:30 Read twice, if it changes, chop off the __.* and call that the gensym root.

23:30 ibdknox: that would probably work

23:31 TimMc: Then horrible people who put double-underscores in their variable names wouldn't even be affected.

23:31 ibdknox: so with this stuff, you can do my live game editor with your own editor :)

23:31 TimMc: nice!

23:32 ibdknox: I guess you can't redef gensym -- the reader is in Java.

23:32 ibdknox: that was my initial thought

23:32 TimMc: Any reputable third-party readers for CLJS?

23:33 They'd have to be fast-moving to keep up.

23:33 ibdknox: I don't know of any

23:36 TimMc: ibdknox: I'm imagining doing terrible things to clojure.lang.RT#id, which is what gensym (but probably everything else too) uses

23:36 It's an AtomicInteger.

23:36 ibdknox: lol

23:36 like resetting it each time?

23:36 that sounds like a disaster

23:36 TimMc: It's subclassable; you could replace it.

23:37 check the call stack...

23:37 ibdknox: :p

23:40 TimMc: Looks like LispReader.java is pretty solid -- uses var thread bindings to maintain a mapping of gensyms.

23:40 (in syntaxQuote)

23:41 mk: if code in a .clj file has a defn, can I replace that function in some way via the repl?

23:45 ibdknox: TimMc: https://refheap.com/paste/922

23:46 TimMc: ibdknox: So that will chop all gensyms down to their bases.

23:46 ibdknox: yep

23:47 TimMc: Swapping g and g# in a form will be ignored; is that OK?

23:47 ibdknox: well, I just changed it to leave the __

23:47 so then that shouldn't be an issue

23:47 TimMc: Ah! Interesting.

23:49 Raynes: Emergency, the refheap iguana is missing!

23:50 ibdknox: hah. that worked

23:50 TimMc: woot

23:51 and you didn't even have to subclass AtomicInteger and use .setAccessible true on RT!

23:51 (pretty much any hack feels OK in comparison to that)

23:52 ibdknox: lol

23:52 yeah pretty much :p

23:52 time to learn how eventsource works

23:52 TimMc: "Mom, dad... the good news is, I'm not pregnant! The bad news is, I may have slightly damaged the car."

23:53 Always frame the discussion.

23:57 ibdknox: lol

23:58 TimMc: ibdknox: So the idea here is to have the live game editor notice a changed file on disk?

23:58 ibdknox: yeah, checks to see if any of the forms changed, if they did, compiles them (much much faster than normally) to js and beams them to the client

Logging service provided by n01se.net