#clojure log - Oct 09 2011

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

0:13 khaliG: can't wait for clojurescript support to be added to slime.. this is so cool :)

0:15 dnolen: khaliG: totally.

0:18 Arafangion: Ah, other langauges do have atoms, after a fashion.

0:20 And limited forms of agents.

0:20 * Arafangion is thinking of Python, ObjC, and C#.

0:20 Arafangion: Although python itself doesn't really have any form of agent.

0:20 brehaut: a lot (most) of the features of clojure are not new; they are carefully chosen and designed to integrate well together

0:22 Arafangion: It seems that clojure has managed to avoid the typical flaws new langauges have - they typically try to be too simplistic.

0:22 khaliG: haha is that a backhanded compliment?

0:22 ibdknox: Clojure is pretty simple

0:22 dnolen: Arafangion: ibdknox: on the surface. Implementation is very much "Worse Is *not* Better"

0:23 under the hood is some complicated stuff.

0:23 ibdknox: Sure

0:23 under the hood of C# is some crazy stuff too

0:23 Arafangion: C# is not exactly a simplistic language.

0:23 ibdknox: but I would say Clojure is far simpler than C#

0:24 Arafangion: Although the earlier versions of it probably were, for a java-inspired language.

0:24 ibdknox: what is your basis of comparison then?

0:24 dnolen: Simplicity-the design must be simple, both in implementation and interface. It is more important for the interface to be simple than the implementation.

0:24 khaliG: ibdknox, c++ obviously

0:24 ibdknox: lol

0:24 dnolen: http://www.jwz.org/doc/worse-is-better.html

0:26 ibdknox: I'm in the interface is what matters camp.

0:26 dnolen: ibdknox: yes, Dick Gabriel does not disagree

0:26 Arafangion: ibdknox: Consider Scheme and Go.

0:26 ibdknox: they are both very simple languages, although Go does try to break new ground in at least one area.

0:27 ibdknox: Arafangion: Go isn't really simpler than python or ruby

0:27 dnolen: Arafangion: Scheme and Go both screw up the simple part.

0:27 Arafangion: Could you elaborate?

0:27 ibdknox: Scheme is also not a particularly practical language

0:27 dnolen: Go channel - puke

0:27 * ibdknox hides

0:27 dnolen: Scheme - concrete types which can't be replaced - puke

0:28 Arafangion: Heh, ok. :) I gotta go, friend arrived. :(

0:28 ibdknox: actually no one in here probably disagrees

0:29 Very few languages are internally consistent

0:29 it's hard to suggest simplicity without that though

0:31 dnolen: Is the "worse is better" philosophy widely held?

0:32 dnolen: ibdknox: I would argue yes. But the reason why is complex - it often gets foisted on us - time constraints, programming languages etc

0:36 ibdknox: dnolen: hm, I think my argument is that complexity seeps into any non trivial system, and that the general purpose of building the system to begin with is to provide an interface to something that is otherwise difficult. The greatest value is derived from maintaining a simple abstraction to hide the fact that the implementation is likely painful. There are certainly times where you have to swing one way or the other... bu

0:36 t in general a thing isn't very useful if it's too complicated to use efficiently

0:37 dnolen: ibdknox: we are in agreement. and that's a fundamental Clojure stance.

0:37 "reasoning under concurrency is totally lame", let's fix that by any means necessary is Clojure's MO.

0:38 ibdknox: indeed

0:57 todun: hi. I'm new to clojure and on here, it was recommended I use clooj and 4clojure.

0:58 how do I install clooj? there are download instructions but no install instructions at the github repo.

0:58 amalloy: todun: the jar should be executable

0:59 todun: where do I get newbie style tutorials that can ease me into learning clojure?

0:59 amalloy: there is no jar included.

1:00 amalloy: sure there is. look on github, click Downloads in the upper-right

1:00 https://github.com/downloads/arthuredelstein/clooj/clooj-0.2.4-standalone.jar looks like the current release

1:01 ibdknox: hm

1:01 what happened to try-clojure?

1:01 khaliG: todun, whats your programming background?

1:02 amalloy: ibdknox: interesting. dunno, i'll try restarting it

1:02 todun: khaliG: I'm new in general, but I've tried a few languages with different paradigms.

1:02 khaliG: familiar with many but very uncomfortable in all languages.

1:06 amalloy: ibdknox: resurrection succeeded

1:06 ibdknox: yay!

1:06 todun: http://try-clojure.org/

1:07 todun: ibdknox: thanks will do.

1:07 ibdknox: the more tutorials the merrier :)

1:19 Arafangion: ibdknox: Fair enough - I find that professionally, "worse is clearly better".

1:19 ibdknox: As long as any issues are managed - it's usually much better to get a product out the door than to spend a year longer on it.

1:22 (And wow, that ds.js is insane)

1:22 ibdknox: I have a simple cljs implementation of D3 in Pinot :)

1:22 Arafangion: ibdknox: I can't bear to think about a pinot implementation. :)

1:23 ibdknox: huh?

1:24 Arafangion: I seemed to think if pinot as an esoteric 'visual' language based on abstract art?

1:25 ibdknox: http://github.com/ibdknox/pinot

1:26 Arafangion: Intruging.

1:32 * Arafangion is reminded how he has barely scratched the surface in software development.

1:33 kab3wm: ibdknox: I just started using Noir to build a content management system. Really loving Noir. I'm still new to Clojure ( even Lisp ), but building a web app is helping me figure things out.

1:33 ibdknox: kab3wm: awesome :)

1:36 kab3wm: have you run into anything you wish was better explained/is confusing?

1:37 kab3wm: ibdknox: well, everything is confusing at the moment.. but I'm getting the hang of it. My issues are more with poorly documented libs. Like congomongo. But I've got basic CRUD stuff working with Noir and a MongoDB at the moment.. so hopefully it's mostly down hill from here.

1:38 zakwilson: Congomongo has great documentation as long as you're willing to read the source.

1:38 amalloy: Arafangion: you're thinking of Piet

1:38 Arafangion: kab3wm: "downhill" is usually a bad thing. ;)

1:38 amalloy: Indeed, I was.

1:38 kab3wm: zakwilson: yes, that's been working.

1:39 zakwilson: But yeah, docs would be nice some day.

4:36 sritchie: has anyone used the google maps api with clojurescript?

5:12 _khaliG: wanting to use #(..) syntax but wanting to ignore the parameter/s. is there a way?

5:20 amalloy: yes, but don't do it

5:21 _khaliG: amalloy, for swing callbacks - dont often use the event e, for instance

5:21 amalloy: _khaliG: so just write (fn [_] (...))

5:21 _khaliG: amalloy, lol i have but its ugly

5:23 amalloy: *shrug* turn your head and squint if it helps you. it's not ugly,and it's better than #(do %& (...))

7:52 tdrgabi: regarding the utf8 issue earlier, it appears to be an emacs thing. it was set to a different locale somehow. I run M-x dos-to-utf8 on the whole file and now my characters are nice

7:54 Arafangion: What was the utf8 issue?

8:22 daniel___: can anyone suggest an equivalent to ord() in python? a function that returns the unicode code point of a char?

8:26 think i found it (codepoints s)

8:26 jaley: hey guys - has anyone here had much luck with clojure and android? i'm getting a weird NPE from core.clj (Properties.load() call defining *clojure-version*) before my code is executed afaik. google searching revealed nothing :/

8:35 Arafangion: jaley: Hmm, I don't know if clojure works on android. You do know that android does NOT run java?

8:36 jaley: It's using the Dalvik VM.

8:36 daniel___: java.lang.Exception: Unable to resolve symbol: codepoints in this context (NO_SOURCE_FILE:7) can anyone help me out?

8:37 i thought i required clojure.contrib.string

8:37 Arafangion: daniel___: I think java strings are essentially UTF-16 arrays?

8:38 daniel___: ok Arafangion, just gunna try something

8:38 what does that mean in terms of what i want to do?

8:39 jaley: Arafangion: yeah - there are a few success stories around. there's even a clojure REPL app on the android market actually :D

8:39 daniel___: im trying (- "a" "b")

8:39 Arafangion: jaley: Neat. :)

8:39 jaley: Arafangion: plus some helloworld examples on various blogs

8:39 Arafangion: jaley: That's awesome. :)

8:40 jaley: Arafangion: Android actually uses java developer tools, then google provide a tool to translate the bytecode to their dalvik format, so many jvm languages actually "sort of" work. in a broken and annoying kind of way... :/

8:40 Arafangion: This means that it's trivial to use clojure as a single, cross platform language. :)

8:40 jaley: Yes, specifically, dynamic bytecode generation gets broken. :(

8:41 Which breaks Jython, for instance.

8:44 jaley: Arafangion: yeah... it's far from perfect, but apparently basic things should work

8:44 daniel___: i have a repl open... (ns whatever (:require clojure.contrib.string))

8:45 _khaliG: i'm looking forward to writing my android app with clojurescript

8:45 daniel___: (codepoints "a") gives me the error

9:01 bsod1: paredit's C-) is great but I want to disable auto-close parens, how can I do that?

9:03 daniel___: i just needed (clojure.contrib.string/codepoints "a")

9:03 thanks for your help guys!

9:06 gfredericks: daniel___: oh hah. I should have noticed that.

9:07 daniel___: nps :)

9:07 now i need a function that splits a string into a list of individual characters

9:08 st3fan: split?

9:08 daniel___: yeah st3fan, i think so

9:08 what regex will give me each char?

9:08 st3fan: ,(seq "foo")

9:08 clojurebot: (\f \o \o)

9:08 st3fan: there you go

9:09 daniel___: what library is that in?

9:09 and what are the \?

9:09 st3fan: core

9:09 \f is the single character f

9:09 daniel___: ok, let me experiment

9:09 thanks a lot

9:09 st3fan: like 'f' on other languages

9:12 ,(str (join (seq "I love cheese"))(

9:12 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: EOF while reading>

9:12 st3fan: ,(str (join (seq "I love cheese")))

9:12 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: join in this context, compiling:(NO_SOURCE_PATH:0)>

9:13 st3fan: ,(str (reverse (seq "I love cheese")))

9:13 clojurebot: "(\\e \\s \\e \\e \\h ...)"

9:13 st3fan: hm

9:13 ,(str (str-join (seq "I love cheese")))

9:13 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: str-join in this context, compiling:(NO_SOURCE_PATH:0)>

9:14 gfredericks: ,(apply str (reverse "I love cheese"))

9:14 clojurebot: "eseehc evol I"

9:16 Bronsa: ,(reverse "string")

9:16 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.IllegalStateException: replace already refers to: #'clojure.string/replace in namespace: sandbox>

9:16 Bronsa: i think i broke clojurebot :E

9:16 gfredericks: &(reverse "string")

9:16 lazybot: ⇒ (\g \n \i \r \t \s)

9:17 gfredericks: is lazybot to the rescue???

9:17 lazybot: gfredericks: Oh, absolutely.

9:17 Bronsa: i ,(use 'clojure.string)

9:17 and reverse && replace got broken

9:17 gfredericks: Bronsa: somebody will reboot it eventually

9:17 Bronsa: i'm sorry ( ,_,)

9:17 didn't mean to broke it

9:17 *break

9:17 gfredericks: no problem. lazybot still works.

9:20 st3fan: &(str (map #(str %) (seq "Hello")))

9:20 lazybot: ⇒ "clojure.lang.LazySeq@5db0151"

9:20 st3fan: how does str return a lazy seq?

9:26 Bronsa: st3fan: you're trying to str a sequence

9:26 you should apply str to a sequence

9:31 gfredericks: st3fan: you also might like pr-str

9:32 &(pr-str (map str (seq "Hello")))

9:32 lazybot: ⇒ "(\"H\" \"e\" \"l\" \"l\" \"o\")"

9:43 mindbender1:

9:43 gfredericks: mindbender1:

9:44 mindbender1: gfredericks: hi

9:46 gfredericks: :)

9:47 mindbender1: I'm in the process of learning clojure and have read programming clojure and the joy of clojure and my head is spinning...:)

9:49 gfredericks: mindbender1: what sorts of languages are you coming from?

9:50 mindbender1: not a particularly good programmer prior to clojure but I am familiar with java.. so I wanted a language I could grow with

9:51 I intend to work in the erp field with the clojure language

9:52 gfredericks: that sounds fun

9:52 mindbender1: any pointers or red signs?

9:53 Arafangion: With the ERP field, or clojure?

9:54 mindbender1: with clojure in the erp field, especially as I intend extend already popular erp packages with clojure?

9:55 or rather customize them

9:55 cark: in the same vm as your erp packages ?

9:56 mindbender1: yes in the same vm

9:56 cark: so you run the package, and it calls into clojure ?

9:57 i mean, do you intend to have clojure around it, or the other way around ?

9:57 mindbender1: yes or I was thinking clojure.jar would be somewhere on the lib path of the app

9:57 cark: as far as i know you might be loosing the benefit of a repl

9:57 mindbender1: then customizationss will be in a different jar. no touching of classes in the app

9:58 cark: losing*

9:58 mindbender1: actually the app I had in mind is adempiere

9:59 cark: i find it's easier to call java (or even patch stuff) from clojure than the other way around

9:59 mindbender1: yes i intend to call java from clojure

9:59 that is call the classes in the app from my clojure dev environment

10:00 Arafangion: You can't easily call into clojure from java?

10:00 cark: i fyou can use your erp packages as libraries to your clojure app, then you're golden

10:00 Arafangion: yes you can

10:00 Arafangion: only it's annoying when you're used to the ease of developement starting from clojure

10:00 mindbender1: ok you suggest using the erp packages as lib in my app?

10:01 cark: i don't know if it is possible in your case, but if it was me, i would try very hard before going the other way around

10:02 one of the strong points of clojure is interactive developement

10:02 mindbender1: already the app itself allows customizations to be put in a customizations.jar so I was hoping I could write that customization.jar in clojure

10:03 cark: by calling into clojure, you'd need to use the old code->compile->run cycle at least until you have your interface ironed out

10:03 which is very possible, but annoying

10:05 Arafangion: cark: Well, if it were me, I'd define the interface in Java... And implement it in Clojure.

10:05 Which reminds me.

10:05 cark: Arafangion: yes, true

10:06 Arafangion: Does Clojure have a dependency injection framework? (Spring seems to be common...)

10:06 cark: clojure is a functional language

10:06 it does not need a dependency injection framework

10:06 mindbender1: joy of clojure talks about clojure not needing DI

10:07 cark: ,(sort-by identity > [4 3 8 1 2])

10:08 clojurebot: (8 4 3 2 1)

10:08 Arafangion: I'm not so sure about that.

10:08 cark: se how i injected the > function in the sort-by function

10:08 see*

10:08 Arafangion: cark: Yes, so the language itself provides it there. For this langauge, at least. That's awesome.

10:09 cark: Arguably, in the case of python, it does so likewise if you think of the language providing a service locator.

10:09 Twey: DI frameworks are just a workaround for Java treating functions as second-class citizens…

10:09 Arafangion: Twey: That's unrelated.

10:09 Twey: Oh?

10:09 cark: i think it's related

10:09 Arafangion: DI frameworks are a workaround for the proliferation of dependencies caused by writing generic code in OO environments.

10:09 cark: tho i'm no DI guru

10:10 Arafangion: They allow you to replace any dependency with another dependency.

10:10 For example.

10:10 Twey: But you can do that with first-class functions.

10:11 Arafangion: Implementing a function that operates on a stream is better than implementing a function that operates on a file name.

10:11 Because the latter function does not allow you to replace how the file is opened or iterated over.

10:11 Twey: Right

10:11 mindbender1: Arafangion: ? please expantiate

10:11 cark: look at my example again, sort-by is the generic version of sort

10:11 Arafangion: That is dependency injection on a trivial level.

10:11 Twey: I am aware of the concept of DI

10:12 And I assert that first-class functions provide all the necessary features to do that, without a third-party framework

10:12 Arafangion: Now, here's where DI gets annoying.

10:12 mindbender1: Arafangion: references please

10:12 Twey: Okay

10:12 Arafangion: WHen you have, eg, a function that does, well, suppose it's a web spider.

10:13 One of the functions it uses is get-http-protocol-handler

10:13 In a typical, non-oo language, you would have something like: perform_spider(list_of_root_references0

10:14 But... If you're using DI as a design technique, you would have:

10:14 perform_spider(list_of_root_references, http_protocol_handler, generic_sort, ...)

10:14 cark: well in clojure you would have something like this :

10:15 Arafangion: In OO langauges, you typically end up having a heirachy of dependencies.

10:15 mindbender1: and with java 6 CDI was built in

10:15 cark: (defn perform-spider [& {keys [protocol-handler sort-fn ... ]}] ....)

10:15 Arafangion: cark: Aha, and now we get to the meat of it.

10:15 cark: then you can make your factory function, which woudl be the configuration for your application

10:16 Arafangion: cark: You can do the same in say, Java, as well, but one neat thing a "dependency injection framework", is that it will do that wiring up for you.

10:16 cark: it won't

10:16 Arafangion: cark: It will.

10:17 cark: you still need to write the xml configuration

10:17 Arafangion: cark: Ah, that reminds me why I didn't like Spring. :(

10:17 cark: i'd rather write clojure than xml =P

10:17 Arafangion: cark: Apparently, however, you don't have to. I actually come to DI from C#.

10:17 mindbender1: what I read of DI was a matter of handling things like initialization and transaction management services

10:18 Arafangion: cark: And I don't write any XML for my dependency injection, at all.

10:18 Twey: It needs to know which dependencies to use, somehow

10:18 Arafangion: In C#, I use reflection for that.

10:18 cark: Arafangion: at some point you still need to tell your framework which interface you want to use

10:18 Twey: The Spring gets the information from the XML configuration

10:18 The Clojure takes that map argument

10:18 cark: i mean which implementation

10:18 Arafangion: cark: I use conventions.

10:18 Twey: I'm guessing the C# uses annotations or something

10:19 Arafangion: cark: Eg, if I ask for IFoo, then unless I specify otherwise, I tend to mean "Use Foo".

10:19 cark: well then you have a single implementation and you don't need DI

10:19 Arafangion: In my unit tests, if I ask for IFoo, then unless I specify otherwise, I tend to mean "Use a mock<IFoo>".

10:19 Twey: … yeah

10:19 Arafangion: cark: If I didn't haev unit tests, perhaps.

10:20 cark: But in any case, I do have project-specific conventions and only a small number of exceptions.

10:20 (exceptions... excemptions... I think I mean the latter)

10:20 cark: as i said, i'm no DI guru, but i really don't see how you can use a generic functionality without specifying the implementation you will be using

10:21 maybe i've been away from c# and java for too long =)

10:22 my take on it is this : in java/c# you're mostly working with objects, they need to be configured at creation time

10:23 Arafangion: cark: The implementation in my primary project is specified as: "Use the implementation of the same name minus the leading 'I'".

10:23 cark: in clojure you're mostly working with function

10:23 Arafangion: cark: As I said, I use reflection.

10:23 cark: so you configure the function at call time

10:23 Arafangion: ah i get it now

10:24 Arafangion: cark: However, in my unit tests, I do not want to be testing teh dependencies, I want to test the "unit" in isolation.]

10:24 cark: And that, is actually teh main reason I use DI.

10:24 ghiu: hi, can anyone explain to me why (map #(+%1 1) '(1 2 3 4)) works while (map #((let [one 1] (+%1 one ))) '(1 2 3 4)) gives an error?

10:24 Arafangion: cark: So as a result, for the unit test project, I say: "The implementation I want is a dynamically generated mock of type IFoo".

10:24 cark: ,(map #(let [one 1] (+%1 one )) '(1 2

10:24 3 4))

10:24 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: EOF while reading>

10:24 cark: ,(map #(let [one 1] (+%1 one )) '(1 2 3 4))

10:24 clojurebot: (2 3 4 5)

10:24 Arafangion: cark: So I make a real instance of the unit I want to test... With all of it's dependencies automatically mocked out.

10:25 cark: Arafangion: i see, and that's nice

10:25 Arafangion: cark: Extreme DI is pointless in a functional language, I'll agree with that... However...

10:25 ghiu: , (map #((let [one 1] (+%1 one ))) '(1 2 3 4))

10:25 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn>

10:25 Bronsa: ghiu you have an extra pair of parenthesis

10:25 Arafangion: cark: Surely you will have some kind of 'module' that you can define as a "unit", and surely you'll want to test each unit individually?

10:26 ghiu: Bronsa: oh, the one before let?

10:26 Bronsa: yes

10:26 also the one matching that

10:26 ghiu: because it is already the body of the function

10:26 i see

10:26 cark: Arafangion: i must confess i mostly don't do unit testing, i'm all good with behaviour testing

10:26 ghiu: thanks

10:26 Bronsa: np

10:27 Arafangion: cark: By behaviour testing, do you mean system testing?

10:27 cark: Arafangion: higher level testing i guess

10:27 Arafangion: cark: Yeah... Those are important too, but they have this one massive flaw.

10:27 cark: i do small time testing at the repl =)

10:27 Arafangion: cark: They tend to be slow... And if a test fails, you don't actually know what went wrong. You know only that a test failed.

10:28 cark: And I've seen such testing take hours.

10:28 cark: Arafangion: i know i can get away with it because i'm not working in a team

10:28 Arafangion: small-time testing has another massive flaw in that they're not repeatable, and therefore, not useful as a tool when you're doing refactoring.

10:29 cark: I don't think a team has anything to do with it... But it would depend on your requirements.

10:29 cark: i think unit testing is usefull, and i use it a lot then, when you're working on data structures or algorithms

10:29 Arafangion: I wouldn't bother to do more than manual testing for simple scripts and quick projects, for example.

10:30 cark: Case in point: I was able to see exactly what was broken when I *completely changed my VM*.

10:30 cark: From Python(C) to IronPython. (.NET)

10:30 cark: Arafangion: wew that must have been painfull

10:31 Arafangion: cark: It was surprisingly pleasant, but mostly because I stopped short of completing the port. ;)

10:31 cark: hehe ok

10:31 Arafangion: cark: The main thing that stopped me was no expat support. :(

10:32 And #python is currently hostile with using expat.

10:32 cark: anyways, to come back to DI, i find that i don't need so much of that in real life projects

10:32 and genericity is usually pretty localized

10:32 Arafangion: I mostly use it in "real life projects".

10:33 Then again, most of my projects tend to have a LOT of business logic.;

10:33 cark: well mine too

10:33 Arafangion: And they change a lot. :(

10:33 cark: but it's still localized

10:34 Arafangion: And to be honest...

10:34 I don't think I get any productivity improvement for using a DI framework.

10:34 I still use DI, but I don't think using a "DI Framework" gives actual productivity improvement.

10:34 cark: clojure should provide you with this improvement i think =)

10:34 Arafangion: It saves perhaps 2 minutes of refactoring each time I change a dependency, and that'd be updating my unit tests.

10:35 cark: Alas, I won't likely be ablet o use Clojure at work.

10:35 I'd like to, it would solve a number of painful issues I have.

10:36 For instance, between the various JS VM's, .NET, Mono, and Java, I'd be able to have common code everywhere.

10:36 And by extension, they'd share a lot of tests and business logic.

10:37 cark: how come you have to work on all these VMs ?

10:37 Arafangion: I don't, but on windows, I use .NET

10:37 And on the mac, I don't.

10:38 cark: i see

10:38 Arafangion: I use ObjC on the mac.

10:42 I'm off to bed!

10:43 cark: good night !

10:47 eliOcs: hello everyone!

10:57 kephale: in lein does trampoline use jvm-opts? i'm getting a suspicious outofmemoryerror with a huge max on my heap space when using lein trampoline run

11:04 eanxgeek: new to clojure and trying to compile what I suspect is a simple selenium program, http://pastebin.com/cuxdUWPa, getting error Exception in thread "main" java.lang.Exception: Unsupported binding form: (new DefaultSelenium (:host (quote localhost)) (:port (quote 4444)) (:command (quote *firefox)) (:url (quote http://wwww.google.com)))

11:04 any thoughts on what I have done wrong?

11:07 cark: (DefaultSelenium. "localhost" 4444 "Firefox" "www.google.com")

11:07 or something like i

11:07 tit

11:07 it

11:07 !

11:08 what's with all the quoting you're doing

11:08 and (:keyword blah) doesn't mean what you think it means

11:10 eanxgeek: cark: I was wondering if I was messing something up there with the :keyword blah

11:11 cark: keywords are function that look themselves in the map argument

11:11 so

11:11 eanxgeek: cark: when I simplify further, like your above example, I get DefaultSelenium. should be a vector

11:12 cark: ,(:blah {:a 1 :blah 2})

11:12 clojurebot: 2

11:12 cark: paste again =)

11:13 eanxgeek: http://pastebin.com/zi4Pzyhk

11:14 Bronsa: eanxgeek the code should look like (defn fn-name [args] (let [var (Class. args)] (.doStuff var)))

11:14 eanxgeek: I may have over simplified your intention

11:14 cark: eanxgeek: just like bronsa said

11:16 eanxgeek: cark: Bronsa: I think i have that http://pastebin.com/RvBXfYai

11:16 now getting java.lang.IllegalArgumentException: Parameter declaration let should be a vector (NO_SOURCE_FILE:1)

11:18 cark: http://pastebin.com/kjcM0Cra

11:18 mindbender1: please how can I include username and paswword in a URI so that I can access it later with..

11:19 (let [url (URI. (System/getenv "DATABASE_URL"))

11:19 (if-let [user-info (.getUserInfo url)]

11:19 {:user (first (str/split user-info #":"))

11:21 eanxgeek: cark: Bronsa: just as a fyi, I'm actually trying to simplify a snippet of code that someone else had written where they use (let [client (new DefaultSelenium (:host opts) (:port opts)...

11:22 cark: eanxgeek: he's looking up the parameters in the opt map

11:22 eanxgeek: cark: right I figured that out hence why my :host 'localhost doesn't work

11:23 so I have now removed that stuff, trying (let [client (new DefaultSelenium ('localhost) ... but that doesn't work

11:23 still getting show be a vector

11:23 cark: did you look at my paste ?

11:23 * eanxgeek looks

11:24 cark: ('localhost) just doesn't make sense

11:25 eanxgeek: well not sure if this code will work but it compiled

11:25 http://pastebin.com/tbrK1Yhr

11:25 next step is to test in a repl

11:25 cark: man

11:25 it won't work at all

11:25 eanxgeek: heh

11:26 i'm such a noob

11:26 can't i go back to python

11:26 cark: parenthesis are for function application

11:26 (localhost) is like localhost() in javascript

11:26 eanxgeek: ah ok

11:27 now that makes sense

11:27 cark: quoting is something entirely different

11:27 'blah

11:27 that means, the symbol blah

11:27 daniel___: anyone using vimclojure with nailgun? do you just put vimclojure/server in your project.clj? what else did you do to get ng working?

11:27 cark: (blah arg1 arg2) means the function blah called with args arg1 and arg2

11:28 duck1123: eanxgeek: also, have you looked at clj-webdriver? Might be a bit easier to do whatever you're doing

11:29 eanxgeek: duck1123: I have not, as far as I can tell the group I'll be working with is using clojure and selenium-java-x.jar

11:29 cark: you might want starting with basic understanding of clojure

11:30 eanxgeek: yeah I can already tell some of my reading didn't stick :-(

11:30 duck1123: Fair enough, just thought I'd let you know it's out there

11:30 eanxgeek: damn battery... looks like I'm outta here one way or the other

11:30 thanks for the pointers I'll keep banging away at this.

11:32 cark: there's an awefull lot of banging to do =)

11:34 duck1123: are there any libraries or what-not that will allow me to trace when my namespaces are used/required/loaded? I have an issue where one of my nses is using a ns I never declared.

11:36 Well, I just found the problem, but my question still stands

11:36 raek: duck1123: if you're using gen-class there might be old versions of your namespaces in compiled form in the classes/ directory

11:37 duck1123: raek: No, my issue is this is one of the few places where I've used load-file. I use this namespace in that loaded file. That was causing my problem

11:38 I need to find a better way to load this code, but I still face times where I'd like to trace the namespace load order

11:52 is there any way to use xml zip filters to find an element based on the actual element (as opposed to how it looks in the source)

11:53 it looks like the zip filters give me the prefix and the name for the tag, not taking xml namespaces into account

11:56 daniel___: vimclojure/server seems to have broken dependencies...anyone using vimclojure can tell me how they set up their ng server?

12:12 ghiu: hi, i'm trying to pack a .jar file with some functions i've made. when importing it i get a Could not locate deviant_scraper/core__init.class or deviant_scraper/core.clj on classpath

12:12 any help?

12:16 duck1123: ghiu: are you trying to do this manually, or are you using a build tool of some sort?

12:33 daniel___: ,(seq "dsfsdfsdfsd")

12:33 clojurebot: (\d \s \f \s \d ...)

12:37 daniel___: if i have two lists like (\d \f \s \h \q), how can i iterate through both lists doing operations involving each pair?

12:38 by pair, im thinking if it were an array, the values with the same index

12:39 in fact, it could be (1 2 3) and (4 5 6) and I want to do something like 4-1 + 5-2 + 6-3

12:39 duck1123: ,(map (fn [x y] {x y}) [1 2 3] [4 5 6])

12:39 clojurebot: ({1 4} {2 5} {3 6})

12:40 duck1123: ,(apply + (map (fn [x y] (- y x)) [1 2 3] [4 5 6]))

12:40 clojurebot: 9

12:42 daniel___: thanks duck1123, let me take some time to get my head around what you just did

12:42 duck1123: If you call map with multiple collections, it'll call that function with one from each collection

12:43 daniel___: i see, thats neat

12:43 and apply + is basically a summation

12:44 duck1123: (apply + '(3 3 3)) is the same as (+ 3 3 3)

12:44 daniel___: yep, got it

12:45 cheers

12:46 duck1123: you could also use reduce instead of apply. which would be like (+ (+ 3 3) 3) I can never remember which is better in +'s case

12:52 daniel___: ,(seq "dsfsdf")

12:52 clojurebot: (\d \s \f \s \d ...)

12:52 daniel___: this creates a collection of characters

12:53 im having trouble because i need them to be strings of length 1

12:53 raek: the vararg version of + is implemented with reduce

12:53 duck1123: ,(map str "dsfsdf")

12:53 clojurebot: ("d" "s" "f" "s" "d" ...)

12:53 raek: daniel___: (map str "dsfdsf")

12:54 daniel___: ahh ta

12:54 duck1123: raek: so does that mean that given the choice, I should reduce there?

12:55 raek: for str and concat it's better to use apply than reduce

12:55 it depends on the function, I guess...

12:56 (reduce str will create a lot of intermediate immutable strings but apply str will use a string builder)

12:58 duck1123: Does anyone have any suggestions for processing xml in a ns-aware fashion?

12:59 I'm checking out pjt's saxon wrapper, but it returns a single item if the query has only one result

13:06 devn: duck1123: there's another parser thingamajig somewhere

13:07 i think I saw it in reference to a SOAP-specific library

13:07 sorry i dont have a name for you, but that's something to google around for

13:07 daniel___: can someone using a vim repl share how they set it up? im using vimclojure but cant get nailgun to work

13:08 ghiu: is ring robust enough to be used as production server or it is dev-only and requires a deployment under tomcat?

13:10 cark: ring is not an http server ... i'm guessing you're talking about jetty ?

13:11 duck1123: ghiu: There are several sites that I can think of that are using ring in relatively heavy production

13:11 cark: i do use ring in production too

13:11 duck1123: and I believe more people use jetty than tomcat

13:11 cark: with jetty

13:11 ghiu: do you need any reverse proxy in front of it?

13:11 like

13:11 duck1123: ring is more or less container agnostic

13:11 cark: abd it's good enough for hundreds of pages per second

13:11 dbushenko: cark: where do you use ring in production?

13:11 ghiu: you use it under nginx or something?

13:12 cark: jetty + ring, directly

13:12 using it for a telecomunication application, providing information to customers of small telcos

13:12 duck1123: I use nginx in front of aleph. I had some odd issues with caching with apache

13:13 dbushenko: cark: can you share a link? I'm collecting success stories

13:13 cark: nope it's all behind login/password

13:13 the application is sold by the company i made it for

13:14 dbushenko: sad...

13:14 cark: sorry =(

13:15 dbushenko: this is your startup?

13:15 wink: cark: how did you daemonize it?

13:15 cark: nope i'm a freelance programmer

13:15 it's not running as a daemon

13:15 ghiu: the main main of ring repository (https://github.com/weavejester/lein-ring) only shows how to use it for a dev server

13:15 cark: running under solaris

13:16 ghiu: how to use it in production?

13:16 cark: i provide a jar file, and directory structure, i develop under windows, they make it run

13:16 i really don't know much about the unix side

13:17 they have a startup scirpt, it's only running the executable jar

13:17 we had only one solid down time at a customer's site

13:17 because there was a limit to the number of thread jetty was creating

13:18 but after a few hours researching the cause, it was easily fixed

13:18 really no trouble at all besides this one time

13:23 amalloy: ghiu: www.4clojure.com uses ring/jetty/nginx. not a huge load, of course, but it's "production"

13:23 cark: nginx is for the static stuff ?

13:23 or is everything behind a proxy ?

13:30 thoefer: try to start a clojurescript app, but I get a javascript error "No protocol method EventType.event-types defined for type null: null" - anyone encountered a similiar error? That´s the small script: https://gist.github.com/1273934

13:30 all samples work for me...

13:31 justicefries: so am I to understand correctly that templating with most clojure frameworks are done in clojure?

13:31 instead of writing any html/haml/whatever

13:33 duck1123: Some people use templates, but a lot of people just use hiccup to generate html

13:35 dbushenko: justicefries, no, that's not so simple

13:35 moment, let me show you a prooflink

13:36 read this one

13:36 http://www.reddit.com/r/programming/comments/al98b/clojure_and_compojure_to_the_rescue_again/

13:36 breafly: you get an html-page without templating tags, then transform it to hiccup-formatted clojure code using clj-tagsoup and then generate html using hiccup

13:38 wink: amalloy: is there any detailed description/howto for that setup? I haven't really found anything decent to copy yet :P

13:38 amalloy: haha don't copy us. ours is terrible

13:38 wink: I'm doing lein run in a screen. can it be worse? :)

13:39 amalloy: cark: that's what you get for not highlighting me :P. everything is behind a proxy for port-forwarding - that server hosts a half-dozen websites

13:39 cark: hehe ok

13:39 my bad !

13:41 amalloy: wink: about equally bad, i guess. our deploy process is lein deps && kill oldproc && nohup java -cp (...) clojure.main -e (...)

13:42 ghiu: i have exported (leiningen localrepo) a java .jar to my local repository. i've added it to the solution and with leiningen i have it now in my lib/ when i try to include id, i have a java.lang.ClassNotFoundException exception. any idea?

13:44 gfredericks: amalloy: isn't it weird how programmers have been deploying things for decades now and we still think it's hard to do anything that survives a reboot?

13:46 That might just be my least favorite part about linux.

13:53 thoefer: my bad, clojurescript works :)

13:54 ghiu: hmmm, can i import an entire namespace from java or just objects?

13:55 i mean classes?

13:56 daniel__2: ,(map str "dsad")

13:56 clojurebot: ("d" "s" "a" "d")

13:56 gfredericks: ghiu: just classes. You can use gen-class to create a class in your ns that calls functions in the ns.

13:56 depending on what you're doing that may or may not be the simplest approach.

13:59 ghiu: ok, but does it resolves all the dependancies? i mean, if i include class A that has some methods that return class B or require as argument class C, can i use them?

13:59 daniel__2: (apply + (map contstr/codepoints (map str "dasdsa")))

14:00 i get a cant cast lazyseq into number with this

14:00 sid3k: hi all. I solved first 40 problems at 4clojure and now need a free online guide to continue. None of the clojure books has a kindle version. is there any guide considered as the best one by the community?

14:00 bsod1: is there a lazy sort function in clojure?

14:02 gfredericks: daniel__2: that makes sense. What are you trying to do? Add the codepoints in the original string?

14:02 ghiu: it will take care of all the dependencies that you declare in your (ns) declarations...not quite sure what else you might mean.

14:02 amalloy: bsod1: none built in. you can write one pretty quickly though, and JoC does just that

14:02 daniel__2: gfredericks: sum all the integers

14:03 i think i need ([1] [2] [3]) instead of ((1) (2) (3))

14:03 gfredericks: daniel__2: why not (contstr/codepoints "dasdsa") instead of the maps?

14:03 bsod1: amalloy: who is JoC?

14:03 amalloy: joy of clojure

14:03 bsod1: ah, ok, thanks

14:04 daniel__2: gfredericks: not sure what that gives me but let me try

14:04 you're right, thats what i want

14:04 cheers

14:04 gfredericks: :)

14:04 daniel__2: i thought it not be split at the end of it

14:04 amalloy: but a general-purpose lazy sort isn't as useful as something more specific for your problem. like, if you know in advance you need the two largest elements you can do better than lazy-sorting the whole thing

14:04 daniel__2: it might not be*

14:06 but so i learn something, in the case i had a lazyseq and wanted to convert them to numbers?

14:07 gfredericks: daniel__2: if you want to sum up a lazy seq you can use (apply + ...) just like in your example

14:07 &(apply + (range 2 10))

14:07 lazybot: ⇒ 44

14:08 gfredericks: daniel__2: if you mean the case where you have a sequence of sequences like [(3) (4) (8)], you would want to call (map first ...) on it first, to pull them out

14:08 daniel__2: ,(apply + ((1) (2) (3)))

14:08 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn>

14:09 gfredericks: ,(apply + (map first [[1] [2] [3]]))

14:09 clojurebot: 6

14:09 daniel__2: ok, thanks

14:09 gfredericks: ,(map first [[1] [2] [3]])

14:09 clojurebot: (1 2 3)

14:09 gfredericks: yep

14:09 daniel__2: note that if you want to make a list literal (with parentheses), you have to quote it so clojure won't try to evaluate it: ##(map first '((1) (2) (3)))

14:09 lazybot: ⇒ (1 2 3)

14:11 daniel__2: yup, i knew that

14:19 amalloy: note also that if you want to make a list literal you're usually wrong :P. not always, of course, but it's a good rule to start with

14:19 bsod1: I'm sorting a seq with 1000 elements for some tests and learning, after second time I sort the same seq, sorting time decreased to 1/4 of first time, is it because of JVM's optimizations?

14:20 amalloy: sorting a sorted sequence is pretty fast

14:20 run down the line, find out it's already sorted, do no swaps

14:20 bsod1: amalloy: no it's not sorted, I'm not changing the seq, I'm sorting same unsorted seq every time

14:21 amalloy: my sort function is side-effect free, there no changing

14:21 there is no changing*

14:21 amalloy: here's my sort function http://paste.pocoo.org/show/489995/

14:22 daniel__2: can anyone suggest how to change a random character in a string?

14:23 amalloy: oh, you wrote the lazysort. i thought you were using java's sort. still, i can draw no benchmarking conclusions from the sort code without knowing how you are benchmarking

14:23 daniel__2: ##(str \F)

14:23 lazybot: ⇒ "F"

14:23 bsod1: amalloy: (time (qsort (take 1000 (repeatedly #(rand-int 1000))) <))

14:23 amalloy: so it's not the same seq at all

14:24 daniel__2: say i have ("f" "d" "h" "w"), how would i choose a character at random?

14:24 bsod1: amalloy: actually I'm saving this seq to a var but I changed it to paste it here

14:24 daniel__2: and modify it

14:24 gfredericks: daniel__2: rand-nth?

14:24 bsod1: (def t (take 100...))

14:24 gfredericks: daniel__2: never mind

14:24 bsod1: (time (qsort t <))

14:24 gfredericks: daniel__2: for random updates you'll want a vector instead of a list

14:25 amalloy: bsod1: well, (a) the first sort is also creating the sequence, and (b) since your sort is lazy, that (time (qsort)) will do basically zero work

14:25 daniel__2: hmm ok, lets say i have a function (defn mutatestring [string] ...)

14:25 i want to return the string with one char modified

14:26 so ill have a string which i want to convert to a vector of chars?

14:26 bsod1: amalloy: I'm sorting on REPL so qsort is printing the result, so it's sorting all the seq

14:26 amalloy: bsod1: but time is returning before the printing happens, so that's immaterial

14:27 bsod1: amalloy: ok, I'll add (print) over qsort and try again

14:29 gfredericks: daniel__2: I guess if it's a string in and out then the vector would be too much. I'd just take a substring from both sidse and combine them back together using str

14:29 (let [i (choose-index)] (str (subs s 0 (dec i)) (rand-char) (subs s (inc i))))

14:30 daniel__2: ^ that might do it

14:30 amalloy: daniel__2: but if you're doing a lot of this stuff, using a vector as an intermediate representation and converting to a string only when necessary will make your life easier

14:31 daniel__2: it will, let me try and understand both ways

14:31 how would i convert a string to a vector?

14:31 amalloy: &(vec "test")

14:31 lazybot: ⇒ [\t \e \s \t]

14:32 daniel__2: ,(rand-nth (vec "test"))

14:32 clojurebot: \t

14:33 gfredericks: daniel__2: rand-nth was probably a bad suggestion, since that doesn't help you know where to update

14:38 daniel__2: im just playing, how would i modify a character by a small amount? i can get the unicode code point and increment it but im not sure what the opposite of codepoints is to convert it back toa char

14:38 gfredericks: ,(char 77)

14:38 clojurebot: \M

14:39 daniel__2: aaah ok

14:39 mindbender2: anyone familiar with heroku? I'm having troubles getting an app to run with foreman

14:39 daniel__2: this repl in irc is revolutionary

14:40 amalloy: haha daniel__2 it is a pretty old revolution

14:41 wink: amalloy: thanks. yeah, only a bit better :P

14:44 amalloy: &(-> "A" first int inc char str) ;; clojure's compellingly-simple ascii arithmetic...

14:44 lazybot: ⇒ "B"

14:46 daniel__2: amalloy: nice

14:46 clojurebot: amalloy: therfor I return [previous] if rest is empty

14:47 daniel__2: whats ->

14:47 duck1123: shut up, clojurebot

14:47 amalloy: &(use 'clojure.walk)

14:47 lazybot: ⇒ nil

14:47 amalloy: &(macroexpand-all '(-> "A" first int inc char str))

14:47 lazybot: ⇒ (str (char (inc (int (first "A")))))

14:48 duck1123: -> puts second ->> puts last

14:48 they're both great for simplifying code

14:49 daniel__2: doesnt look much simpler to me :S

14:49 whats does first do in this example?

14:50 gfredericks: turns "A" into a char

14:50 ,(first "A")

14:50 clojurebot: \A

14:50 daniel__2: ,(char "A")

14:50 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number>

14:50 daniel__2: hmmm ok

14:50 gfredericks: daniel__2: it works because (first) will start by converting the argument to a seq

14:50 c.f., ##(first "foobar")

14:50 lazybot: ⇒ \f

14:51 amalloy: daniel__2: -> simplifies by turning the code inside-out. you can read from left to right and see the steps in order instead of in reverse order

14:51 duck1123: Take "A", grab the first char, turn it into an int, increment it, thurn it back into a char, thurn that into a string

14:51 amalloy: but it's not super-helpful in this case; -> and ->> are more useful for functions that take more than one arg

14:52 daniel__2: ok, i see

14:52 Vinzent: it helps to preserve natural order of reading here

14:52 amalloy: eg, ##(->> [0 1] (iterate (fn [[a b]] [b (+ a b)])) (map first) (filter even?) (take 40) (reduce +)) ;; add up the first 40 even fibonacci numbers

14:52 lazybot: ⇒ 1655824071758491008590040

14:52 amalloy: wow, that high?

14:53 daniel__2: ,(int (char "#"))

14:53 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number>

14:53 duck1123: they add up, *drumroll*

14:53 daniel__2: ,(int (char "A"))

14:53 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number>

14:53 daniel__2: sorry, oops

14:53 amalloy: duck1123: i think you want

14:53 ~rimshot

14:53 clojurebot: Badum, *ching*

14:54 daniel__2: ,(int (first "#"))

14:54 clojurebot: 35

14:54 daniel__2: hmmm, why am i using codepoints when it seems to be as simple as int

14:54 ,(int (first "$"))

14:54 clojurebot: 36

14:55 gfredericks: daniel__2: because everybody spends their first year of clojure figuring out how their code doesn't need to be nearly as complicated as their first attempt?

14:55 daniel__2: :)

14:55 gfredericks: at least I did. And then another year or two after thaht.

14:57 daniel__2: how long has clojure been around?

14:58 duck1123: 3.5 years?

14:59 daniel__2: thats about the right sort of time to start learning :D

14:59 duck1123: Sept 22 2007

15:04 daniel__2: gfredericks: can you explain (let [i (choose-index)] (str (subs s 0 (dec i)) (rand-char) (subs s (inc i)))) ?

15:05 i substitute s for the string

15:06 and the rand-char?

15:06 i dont want it completely random, i want it just offset

15:06 i cant tell whether you made up these functions or not

15:06 choose-index?

15:07 amalloy: he made up choose-index

15:07 oh, and rand-char

15:10 daniel__2: ok, ill have a go at implementing them

15:15 why is it (.length "abc") and not (length "abc") ? does the . mean something?

15:16 Vinzent: daniel__2, it's a method call

15:16 raek: daniel__2: yes, it's the syntax you use to make a method call on a java object

15:16 Vinzent: (.method obj) in clojure is equivalent to obj.method in java

15:16 raek: so .length is not actually a clojure function at all

15:16 Vinzent: clojure one is count

15:17 daniel__2: aah right

15:17 thanks

15:18 Vinzent: does ^:keyword syntax always creating array-maps? I mean, is ^:foo ^:bar always equivalent to ^{:foo true :bar true}?

15:19 raek: I presume it uses the same way to choose the array map / hash map implementation as usual map literals

15:22 Vinzent: so the limit is 8, if my memory serves me?

15:22 raek: ,(class '{1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7})

15:23 clojurebot: clojure.lang.PersistentArrayMap

15:23 raek: ,(class '{1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7, 8 8})

15:23 clojurebot: clojure.lang.PersistentArrayMap

15:23 raek: ,(class '{1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7, 8 8, 9 9})

15:23 clojurebot: clojure.lang.PersistentHashMap

15:23 raek: looks so

15:28 tdrgabi: Arafangion: a long time ago, you asked "what utf8 issue".

15:29 while using noir and hiccup, something like: [:h1 "På"] looked like P�

15:29 but it was because of my emacs and nothing wrong in clojure/noir

15:29 dnolen: core.match has reached the point where last 10% is 90% of the work :P

15:29 0.2.0-alpha5 being released, probably the last one before cutting beta.

15:29 daniel__2: gfredericks: (let [i (choose-index)] (str (subs s 0 (dec i)) (rand-char) (subs s (inc i))))

15:30 im having trouble with the end cases

15:30 choose-index: (rand-int (dec (count s)))

15:30 that means (dec i) could be -1

15:31 and (inc i) could give an index too high

15:33 gfredericks: ,(subs "foobar" 0 -1)

15:33 clojurebot: #<StringIndexOutOfBoundsException java.lang.StringIndexOutOfBoundsException: String index out of range: -1>

15:33 gfredericks: daniel__2: I guess the dec should probably not be used.

15:33 ,(subs "foobar" 0 0)

15:33 clojurebot: ""

15:34 gfredericks: ,(subs "foobar" 6)

15:34 clojurebot: ""

15:34 gfredericks: I think the inc is correct though

15:35 daniel__2: I don't think choose-index should have the dec either

15:35 daniel__2: ,(subs "foobar" 0 0) doesnt help either though

15:35 clojurebot: ""

15:35 daniel__2: ,(count "ABC")

15:35 clojurebot: 3

15:35 daniel__2: ,(nth "ABC" 3)

15:35 clojurebot: #<StringIndexOutOfBoundsException java.lang.StringIndexOutOfBoundsException: String index out of range: 3>

15:35 daniel__2: thats why i have the dec

15:35 gfredericks: daniel__2: (rand-int 3) never returns 3

15:36 just [0 1 2]

15:36 daniel__2: oh

15:36 :D

15:36 gfredericks: what's wrong with (subs "foobar" 0 0)? If you're replacing the first character then you want the "before" part to be empty, right?

15:36 daniel__2: gfredericks: duh :S

15:37 thanks

15:37 gfredericks: yep

15:39 daniel__2: its still not quite right, at least im not getting exceptions

15:40 gfredericks: no exceptions == no bugs :)

15:41 daniel__2: nvm, found my mistake

15:41 duck1123: just like no failing tests means it's perfect

15:41 gfredericks: duck1123: that's what we tell our clients

15:41 daniel__2: i had (subs s 0 (inc i)) instead of (subs s (inc i))

15:41 gfredericks: that'll do it

15:42 daniel__2: perrrfect :D

15:45 lisps are tricky but definitely fun

15:51 Vinzent: ,(class (meta ^:1 ^:2 ^:3 ^:4 ^:5 ^:6 ^:7 ^:8 ^:9 :foo))

15:51 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Metadata can only be applied to IMetas>

15:51 Vinzent: ,(class (meta ^:1 ^:2 ^:3 ^:4 ^:5 ^:6 ^:7 ^:8 ^:9 'foo))

15:51 clojurebot: nil

15:53 thorwil: dnolen: clojure.core.match, pretty please ;)

15:53 dnolen: thorwil: http://dev.clojure.org/jira/browse/MATCH-28 done

15:53 well not "done" but ok, I'll do that

15:54 thorwil: dnolen: does throwing if no match found vary, i.e. does it transport more information than a nil?

15:54 cool

15:56 raek: ,(class (meta ' ^:1 ^:2 ^:3 ^:4 ^:5 ^:6 ^:7 ^:8 ^:9 foo))

15:56 clojurebot: clojure.lang.PersistentHashMap

15:56 raek: Vinzent: ^

15:56 dnolen: thorwil: throwing would make it easier to determine what failed, but this should probably be a variant of match, like matchr (match-raise ?)

15:56 match by default shouldn't throw I don't think.

15:57 raek: ^{:foo "bar"} (quote baz) and (quote ^{:foo "bar"} baz) are not the same

15:57 thorwil: in my admittedly very limited experience, i stumbled over exceptions where i would have been happy with a nil a few times

15:57 dnolen: thorwil: yeah, it's not friendly at all, http://dev.clojure.org/jira/browse/MATCH-29

16:02 Vinzent: raek, ah, should remember it. But I don't understand why: 'baz returns a symbol, ^ adds meta to the next symbol...

16:03 ghiu: how can i cast a symbol to a string? like :a => "a" ?

16:04 brehaut: ,(name :a)

16:04 clojurebot: "a"

16:04 brehaut: and :a is a keyword, not a symbol

16:04 raek: Vinzent: ^ add metadata to the data structure to the right, which is the list (quote baz)

16:05 dnolen: I'm still amazed that core.match just works w/ ClojureScript

16:05 ghiu: thanks to both :)

16:06 raek: ^{:foo "bar"} (+ 1 2) adds metadata to the _code_ of (+ 1 2), not to the runtime result

16:06 (for that, the 'with-meta' function is used)

16:06 Vinzent: raek, hm, right, ^ is in the reader time and (quote baz) is in runtime

16:07 raek: exactly

16:07 Vinzent: ,(class (meta ' ^:1 ^:2 ^:3 ^:4 ^:5 ^:6 ^:7 ^:8 foo))

16:07 clojurebot: clojure.lang.PersistentArrayMap

16:07 Vinzent: ok, thank you raek

16:20 daniel__2: what do you do if you want more than one line in an if's else statement

16:20 ghiu: how to check if a value is a number? something like string?

16:20 Vinzent: daniel__2, use (do ...)

16:20 gfredericks: daniel__2: you can use (do ...) whenever you need several statements in place of one

16:21 Vinzent: ghiu, number?

16:21 gfredericks: ,(doc number?)

16:21 clojurebot: "([x]); Returns true if x is a Number"

16:21 daniel__2: this is getting bloody confusing

16:21 i've got loop, when, if all jumbled up

16:21 ghiu: Vinzent: thank. it is not documented here http://clojure.org/cheatsheet

16:22 gfredericks: daniel__2: that does sound confusing

16:22 when and if are much more similar to eachother than to loop

16:22 Vinzent: daniel__2, usually you don't need this, because usually there is no side effects...

16:23 daniel__2: i dont think i am thinking of the easiest way

16:23 i have a function that takes 3 arguments [generation source target]

16:23 i want to start at 0 and loop until i reach generation

16:23 gfredericks: (doseq [i (range generation)] ...)

16:24 Vinzent: ghiu, hm, indeed, that should be there is the "test" section...

16:24 gfredericks: doseq is for side effects though. Does your function need side-effects?

16:24 daniel__2: if i havent reached generation, i want to modify source until it passes a test and then pass that new source back into the function

16:25 i dont know what you mean by side-effects

16:25 i think i need to break the problem into smaller pieces

16:25 Vinzent: daniel__2, function have side effects when it modifying some state outside of it

16:25 gfredericks: daniel__2: a "pure function" is one that has no side effects, which means that all it does is take an input and return something completely determined by the input

16:25 daniel__2: no, it should be pure

16:26 isnt that the idea of functional programming? arent all functions ideally pure?

16:26 gfredericks: in functional programming languages it's usually good practice to code in pure functions when it's not too difficult

16:26 daniel__2: yes

16:26 Vinzent: well, maybe not all, but most of them

16:27 gfredericks: daniel__2: your description of "start at zero and loop until ..." is an imperative-sounding description; it's not entirely clear what the functional equivalent would be

16:27 perhaps map, perhaps reduce...

16:27 daniel__2: (defn evolve [generation source target]) ... i want it to pass back a modified source to itself generation times

16:27 brehaut: Vinzent, daniel__2: a function that does not change external state but depends on some changing external state is also impure, e.g. if you get the system time or ask for a random number

16:28 gfredericks: daniel__2: you might want iterate

16:28 daniel__2: yes, i think i do

16:29 gfredericks: then you would call (nth iterated-seq generations) on the result

16:29 amalloy: (nth (iterate #(compute-next-generation % target) source) generations) sounds about right to me

16:29 though i'm just guessing on what "target" is for

16:30 gfredericks: yep that sorta thing

16:30 daniel__2: im trying to evolve a random string into hello world

16:30 amalloy: then yep, my guess is about right

16:30 daniel__2: target is "hello world" so i use it to test the fitness of source

16:30 amalloy: daniel__2: i think you should actually use a fitness function, not a target

16:31 daniel__2: i have a fitness function (defn fitness [source target])

16:31 compares source and target and returns an int

16:31 amalloy: okay. i'd suggest passing that in to compute-next, rather than the target itself

16:31 daniel__2: but then how will i be able to test the fitness on the next iteration?

16:32 ill have lost my target

16:32 amalloy: but i actually meant something slightly higher level: (defn fitness-fn [target] (fn [source] (...do work...))

16:32 then you can create (fitness-fn "hello world") once, and use the function it returns to compare against any number of sources

16:33 daniel__2: i see

16:33 gfredericks: daniel__2: ^ fun with higher-order functions :)

16:33 daniel__2: but then i have "hello world" in my code, and ideally its an argument i pass to main

16:34 gfredericks: then (fitness-fn arg-from-main) instead

16:35 daniel__2: its not pure if it relies on an arg from main though is it?

16:35 thats why i have to pass it in each time

16:36 maybe i just misunderstand the concept of higher order function

16:36 gfredericks: daniel__2: higher order function means a function where some of the args or the return value is also a function

16:37 in this case fitness-fn, as amalloy described, is a higher order function because it returns a function

16:37 daniel__2: right

16:37 gfredericks: it returns a fitness function with a particular target

16:37 you would then take the returned function and use it with iterate

16:38 daniel__2: i think i get it

16:38 gfredericks: I think amalloy suggested it because then the algorithm that does the mutation and such doesn't need to know the details of how the fitness function is computed -- it just takes the fitness function as an argument

16:38 (instead of the target)

16:38 daniel__2: yes, clever

16:41 i dont understand the (nth (iterate line...know any simple examples illustrating this?

16:42 gfredericks: iterate repeatedly applies a function; so ##(take 8 (iterate #(* 3 %) 5))

16:42 lazybot: ⇒ (5 15 45 135 405 1215 3645 10935)

16:43 gfredericks: nth just gives you the element at a particular index of the resulting infinite seq

16:43 so it's equivalent to applying a function n times

16:43 daniel__2: right, like a loop

16:44 or dont know if you know ruby ... n.times ..

16:44 gfredericks: I do know ruby. It's like that, but for pure functions

16:45 not that you _have_ to use pure functions with iterate, but that's the general flavor in contrast to ruby

16:46 e.g., in ruby n.times does not have the aspect of passing the return value of the function back into it as the argument. It just performs some actions for side effects n times

16:46 amalloy: daniel__2: https://gist.github.com/1274144 is a draft of how this algorithm could look if you were evolving integers instead of strings

16:47 and of course to evolve strings instead, you change fitness-fn, and pass different args to start

16:48 daniel__2: you just knocked that up now?

16:48 amalloy: yeah

16:49 you seemed like you could use something more concrete :P

16:49 daniel__2: you are passing sources - more than one source?

16:49 amalloy: daniel__2: working with a pool of candidates every generation

16:50 the easiest choice was to have evolve always keep the survivor pool the same size as the candidate pool, but you could do it differently; i'm no evolutionary-algorithm expert

16:50 daniel__2: ok, thats jumping ahead of what im doing :) im only mutating one source at the moment

16:51 ill take some time to study this and see what i come up with

16:51 cheers

16:51 amalloy: enjoy

16:51 i'm off to lunch, so ask someone else for help

16:52 brehaut: gfredericks: re side-effects in iterate, the docs explicitly state that the function must be free of side effects; that means that iterate has the potential to do reordering of operations in future versions which would produce weird results with side effects.

16:54 gfredericks: brehaut: what operations could be reorderd?

16:55 amalloy: yeah, that's fairly implausible

16:56 brehaut: implausible or not, I'm not sure its wise to encourage people to write code outside of the guarantees of the core functions

16:57 amalloy: brehaut: for some things, like reduce, i agree. but the docs for iterate are just lamely reminding you that pure functions are good; there's no way they could reorder or depend on purity in any way

16:57 gfredericks: it's bizarre that the docs for iterate say such a thing while other functions like split-with do not. And split-with will certainly call your predicate twice as often as necessary

16:59 ,(split-with #(< (rand) 0.8) (range 10))

16:59 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox$eval27$fn>

16:59 gfredericks: gerg

16:59 ,(split-with (fn [_] (< (rand) 0.8)) (range 10))

16:59 clojurebot: [() (2 3 4 5 6 ...)]

17:00 gfredericks: ^ that's when I'd like to know that pure functions are required

17:02 daniel__2: hmm is -fn deliberate on the function name

17:02 gfredericks: not sure what you mean

17:02 daniel__2: seems like its defined fitness-fn and called with fitness

17:02 gfredericks: oh in amalloy's code?

17:02 daniel__2: in amalloy_'s example

17:03 gfredericks: daniel__2: I don't think he made a mistake.

17:03 he let's the result of fitness-fn to the name 'fitness'

17:03 and also uses it as the name of the argument to evolve

17:03 daniel__2: yeah, just seen

17:04 i cant see why he needed to do the let though

17:05 instead of fitness-fn goal

17:05 gfredericks: you mean instead of placing the call to fitness-fn within the anonymous function?

17:06 daniel__2: yeah

17:08 gfredericks: it would have worked the other way, but this way fitness-fn only gets called once, instead of every time the anonymous function is called

17:13 daniel__2: so the iterate function...it will iterate with the return value in place of %

17:13 so whatever it returns goes back in again

17:13 the (take (count ... line

17:16 how can i implement the equivalent of ruby until

17:17 until fitness > old-fitness do mutate(source)

17:17 so keep trying mutations until you get a better fitness

17:27 amalloy: &(doc take-while)

17:27 lazybot: ⇒ "([pred coll]); Returns a lazy sequence of successive items from coll while (pred item) returns true. pred must be free of side-effects."

17:27 amalloy: or drop-while, either way

17:29 daniel__2: im making my evolve recursive, is that a bad idea?

17:30 actually, i dont know how that will work with the iterate

17:30 gfredericks: daniel__2: with iterate, instead of using recursion directly, you just return whatever ought to be passed in to the function the next time

17:31 daniel__2: (take-while condition function) ?

17:31 will repeat function until condition is true

17:31 and then return the result of the passing function

17:31 gfredericks: not a function, a seq

17:32 so you could use take-while with iterate

17:32 ,(first (drop-while #(< % 1000) (iterate #(* 2 %) 3)))

17:32 clojurebot: 1536

17:33 gfredericks: ,(take-while #(< % 1000) (iterate #(* 2 %) 3))

17:33 clojurebot: (3 6 12 24 48 ...)

17:34 daniel__2: right, hmmm

17:34 this is a good brani workout

17:34 brain*

17:35 gfredericks: once you get used to it, looking at imperative ruby code will make you ill

17:35 I guess that may or may not be a good thing

17:35 daniel__2: thats doing something slightly different

17:35 i still want to iterate over n generations

17:36 but for each generation, i want to only take the fitter child

17:36 gfredericks: so you have a collection of children and you want to pick the one with the highest fitness?

17:36 daniel__2: not really

17:37 i dont have a collection of children yet, i just want to iterate my mutate function until the fitness of the child is greater than it was before

17:37 i have (mutate source)

17:38 gfredericks: ah, so (drop-while #(<= (fitness %) fitness-from-before) (iterate mutate this-guy))

17:38 daniel__2: i dont want to accept the result is (< (fitness (mutate source)) (fitness source))

17:38 if*

17:38 gfredericks: maybe remove makes more sense

17:38 (first (remove #(<= (fitness %) fitness-from-before) (iterate mutate this-guy)))

17:41 daniel__2: need paren highlighting in irc :p

17:43 gfredericks: drop-while would still work there, I just like remove better for silly personal reasons

17:43 daniel__2: just compiling for the moment of truth

17:44 need to get a repl in vim

17:44 this takes too long

17:44 gfredericks: daniel__2: what's your workflow?

17:45 daniel__2: at the moment, make changes to the code, compile, execute

17:45 trying small experiments in a repl

17:46 would be good not to have to exit vim to compile

17:46 gfredericks: are you using leiningen?

17:47 daniel__2: ja

17:47 gfredericks: I normally have two windows, one for the repl and one for vim. I can reload the code with (require 'some.ns :reload)

17:47 amalloy: daniel__2: why exit vim? just C-z to suspend it

17:47 daniel__2: amalloy: thats a possibility, i just never thought of it

17:48 gfredericks: daniel__2: no reason it should take you more than a couple seconds to try out the code you wrote

17:48 daniel__2: im getting an invalid number of arguments passed to iterate anyway :(

17:48 ghiu: how can i take a map as input and return the same map with keywords converted to strings? example: {:a 1, :b "23", :c '(1 2 3 {:d [:e :f]})} => {"a" 1, "b" "23", "c" '(1 2 3 {:d [:e :f]})}

17:49 gfredericks: ghiu: (zipmap (map name (keys m)) (vals m))

17:49 bdb_: stringify-keys

17:49 &(doc stringify-keys)

17:49 lazybot: ⇒ "([m]); Recursively transforms all map keys from keywords to strings."

17:50 gfredericks: bdb_: that would fail his example of being not-recursive

17:50 bdb_: as lazybot just informed me :-)

17:50 gfredericks: good ole lazybot

17:50 amalloy: (inc lazybot)

17:50 lazybot: ⟹ 0

17:50 gfredericks: :)

17:51 ghiu: wow, thanks :D

17:51 gfredericks: yezzir

17:52 bdb_: forgive me if this has been discussed to death (feel free to point me towards a blog post or something) but what are people using for durability in clojure servers/services?

17:53 daniel__2: i'd paste some code, but i havent got my vim working since i reinstalled my OS

17:53 "+y doesnt work

17:54 might be something to do with vimclojure, not sure

17:55 https://gist.github.com/1274252

17:55 napping: letters still work as names?

17:56 gfredericks: daniel__2: iterate takes two args, so something is wrong on line 22

17:56 you probably meant (iterate mutate source)?

17:57 amalloy: the function passed to remove also should take an argument

17:57 ghiu: hmmm

17:57 daniel__2: there are two args... the anon function and source

17:57 ghiu: shouldn't this work? (walk #(%1) #(%1) {:a 1, :b "23", :c '(1 2 3 {:d [:e :f]})} )

17:57 amalloy: ghiu: no

17:57 daniel__2: ah wait, line 22

17:57 ghiu: stringify-keys is perfect but i need to stringify any occurrence of any key

17:57 amalloy: #(%1) is basically never what you want

17:57 gfredericks: ghiu: what do you want #(%1) to do?

17:58 napping: It seems a bit odd that a {} pattern treats a vector as indexed by integers, while wrapping it like [& {}] uses apply hash-map and treats it as an association list

17:58 gfredericks: ,(#(%1) #(println "HELLO!"))

17:58 clojurebot: HELLO!

17:58 amalloy: gfredericks: i want it to die in a fire

17:58 napping: Is there any better explanation of that than what I can already see by macroexpanding let?

17:59 daniel__2: amalloy: what was wrong with the function passed to remove?

17:59 gfredericks: daniel__2: you're not using the argument anywhere

17:59 amalloy: daniel__2: it doesn't take any arguments. there's no %

17:59 daniel__2: ah

17:59 ghiu: amalloy: i want to check every form and if it's a keyword, turn it into a string instead

17:59 amalloy: remove calls its function once on each element

18:00 icefox: s

18:00 amalloy: ghiu: just use clojure.walk/postwalk if you want a simple walk; don't rewrite it in terms of walk

18:00 daniel__2: instead of (mutate source) it should be %?

18:00 so (fitness %)

18:00 amalloy: yeah

18:01 daniel__2: kk

18:01 lets see

18:01 amalloy: and as gfredericks says you need to unwrap the args to iterate: (iterate mutate source)

18:02 daniel__2: yeah, done that

18:02 sweet, i get some kind of output

18:02 need more generations :)

18:02 gfredericks: no exceptions == no bugs

18:02 ghiu: amalloy: (walk #((if (keyword? %1) (name %1) (%1))) #(%1) {:a 1, :b "23", :c '(1 2 3 {:d [:e :f]})} ) ?

18:03 gfredericks: oh boy

18:03 amalloy: that has like a hundred parens too many

18:03 daniel__2: will be interesting to see how long it takes for 5000 generations

18:03 50 took longer than i expected

18:03 amalloy: see also ##(doc identity), ghiu

18:03 lazybot: ⇒ "([x]); Returns its argument."

18:03 gfredericks: ghiu: ask us again after you have removed exactly one hundred parens from that expression

18:05 daniel__2: i think i want the opposite of remove

18:05 or the opposite condition :/

18:05 gfredericks: daniel__2: that's filter

18:05 daniel__2: gets as far from hello world as its possible to get

18:06 amalloy: &(doc filter)

18:06 lazybot: ⇒ "([pred coll]); Returns a lazy sequence of the items in coll for which (pred item) returns true. pred must be free of side-effects."

18:06 amalloy: haha awesome, daniel__2

18:06 daniel__2: ok, thanks

18:06 amalloy: let us know what string is farthest away from hello world

18:06 daniel__2: țȑȖǩȊȫȂșǯȽȹȓ

18:06 gfredericks: daniel__2: although it sounds like your fitness function might be backwards

18:06 amalloy: it can be the toy program people write when they stop using a language

18:06 daniel__2: lol

18:06 gfredericks: amalloy: :-D

18:07 that looks like a program hiredman would write

18:07 daniel__2: gfredericks: i've tested my fitness function, works fine

18:07 this is looking better now

18:09 still doesnt seem right, after 50000 generations i have dlk33ndoemgl

18:10 aah, i get why

18:12 when i have [& args] what are the args bound to for use inside the function?

18:13 arg1 arg2?

18:13 gfredericks: the arguments are a list called args

18:13 ,((fn [& args] (pr-str ["My args are" args])) 7 8 :famished)

18:13 clojurebot: "[\"My args are\" (7 8 :famished)]"

18:15 gfredericks: daniel__2: this is your main function?

18:15 daniel__2: yeah

18:15 gfredericks: you could do normal arguments like (fn [foo bar]...), but then your program would probably crash if you didn't get exactly 2 command line args

18:15 daniel__2: i want to make the start args abstract so i can change them on each run

18:15 amalloy: daniel__2: you can probably save a lot of wasted compilation time by dropping the gen-class

18:16 and then using clojure.main, which is a precompiled class in clojure.jar, as your entry point

18:18 daniel__2: ok

18:18 amalloy: better, of course, is to use a persistent jvm like the repl or swank/slime, so that you don't need a -main at all, but that's probably more work

18:19 and i only suggest changing because you were annoyed about compilation time - this is generally not a priority

18:19 daniel__2: yes, ill try and get slime working when i get more time

18:19 its 1:17am and i just want this to work so i can go to bed :/

18:20 brehaut: daniel__2: with the emacs starter kit, slime is much easier to get going than it used to be

18:20 gfredericks: daniel__2: well then your problem is you live in a time zone where it's late.

18:21 daniel__2: yep

18:21 brehaut: daniel__2: bookmark https://github.com/technomancy/emacs-starter-kit/

18:21 daniel__2: brehaut: dont want to learn emacs, would rather stick with vim

18:23 gfredericks: daniel__2: I use vim and it's only mildly painful. If I don't think about it then I don't know what I'm missing.

18:23 daniel__2: sure

18:25 touch README

18:25 oops

18:25 amalloy: hah, i smell a project about to get pushed to github

18:25 daniel__2: lol

18:26 gfredericks: eh? what does touch README do (apart from the obvious)?

18:26 technomancy: actually slime and the starter kit are more or less orthogonal

18:26 amalloy: gfredericks: it's a step github recommends in their "how to create a repo on github"

18:26 technomancy: unless you mean the overall getting started experience is easier

18:26 gfredericks: ah ha

18:27 brehaut: technomancy: yeah the over all experience

18:27 amalloy: they don't like repos without a README, though it doesn't seem like an empty one is any better

18:27 daniel__2: right after i install ssh itll be on there :D

18:27 amalloy: daniel__2: windows?

18:27 daniel__2: no, arch linux

18:28 i reinstalled my ubuntu and arch a couple of days ago

18:28 things are still not all setup

18:28 amalloy: fascinating. i didn't think there were unix distros with ssh not installed

18:28 * technomancy recommends README.md or some other markup language

18:28 gfredericks: yeah that sounds pretty unhelpful

18:28 amalloy: good point, technomancy

18:28 gfredericks: technomancy: README.xml? :)

18:29 amalloy: any day now github will add support for README.clj, just you wait. then we'll have won

18:29 gfredericks: somebody start encouraging that in the java community and see if it catches on

18:29 amalloy: we'll have won the opportunity to escape every damn double-quote we use? :)

18:29 clojurebot: amalloy is <amalloy> just use juxt, it'll be great

18:30 daniel__2: amalloy: arch pretty much makes you choose everything

18:30 gfredericks: (inc clojurebot)

18:30 lazybot: ⟹ 2

18:30 daniel__2: which for me was good, i learnt a lot

18:30 amalloy: hahaha best ever. thanks clojurebot, that was perfect timing

18:30 ghiu: amalloy: got it, thanks (postwalk (fn [x] (if (keyword? x) (name x) x)) m))

18:30 daniel__2: anyway, i have to go to bed https://github.com/danielstockton/evolve/blob/master/src/evolve/core.clj

18:30 thanks for all your help, i will resume tomorrow evening

18:31 gfredericks: goodnight

18:38 bdb_: README.clj is only a pull request away: https://github.com/github/markup

18:38 "The code we use to render README.your_favorite_markup"

19:44 icefox: Is there a list of janitor type tasks for clojurescript anywhere?

19:52 amalloy: icefox: you asked this yesterday, right? maybe i'm the only dumb one in the channel, but i can only guess at what "janitor type tasks" means

19:54 ibdknox: amalloy: dude you're so dumb.

19:54 wait

19:54 so am I

19:54 :(

19:54 icefox: amalloy: simple things like, function foo isn't documented, or function foo is deprecated and any code that uses it should be upgraded. The Linux project started the idea of janitors as a way to help get new developers into the Linux project. In trade for doing janitor type tasks the devs promise to review and help them get familiar with the code base

19:54 amalloy: ibdknox: in fairness, i couldn't answer his question even if i did know, because i don't know much about cljs

19:54 but perhaps some prodding will inspire the rest of the channel

19:55 icefox: really I want to learn ClojureScript and one way that seems to work for me is to help contribute so I wanted to know if there are any boring not too difficult tasks that needed done

19:55 ibdknox: icefox: I'm not sure anyone is keeping a list updated for such things

19:56 icefox: the best thing you could do right now, is just use it

19:56 -,

19:56 icefox: yah, been poking around with it making some apps

19:56 jli: hm. if I want to add a thing to the end of a sequence, is it better to do (conj (vec coll) x) or (concat coll [x])?

19:57 or am I doing something wrong?

19:57 (yes, I know it's slow)

19:57 amalloy: jli: they are both right and both wrong, depending on what you're doing

19:59 * jli winces in preparation for a bamboo rod blow to the back of the head that never comes

19:59 ibdknox: jli: why do you have a seq if you need to add something to the end of it?

19:59 amalloy: though, really, (conj (vec coll) x) is a bit nuts - if you're going to be adding onto the end you should make it a vec to begin with, in which case (conj coll x) is fine

20:01 jli: I start with (range), then I map over it, and then I want to add something to the end

20:02 amalloy: if you're only doing that once, concat is much better

20:02 jli: I tried doing "(vec (range ..))" but after the map, conj adds to the beginning

20:03 amalloy: indeed, because map turns it back into a lazy sequence

20:03 ibdknox: concat will keep it lazy

20:07 jli: right. okay. concat, rock. thx.

20:35 kab3wm: ibdknox: Noir question for you.. is there any way to conditionally insert a partial if a flash message exists? The problem I'm running into is if I check if flash-get exists, it pops it and I can't access it after that.

20:43 ibdknox: kab3wm: you can just us an if-let :)

20:43 kab3wm: (if-let [someval (flash-get)] (partial-with-val someval))

20:44 kab3wm: ibdknox: cool, I'll give that a shot. thank you.

23:13 metajack: Why does (String/valueOf nil) throw an exception, but (#(String/valueOf %) nil) return "null" (Clojure 1.3)?

23:22 zodiak: metajack, I would ~guess~ that clojure deals with looking at what the String java lib expects (a string) and if it's nil, then all that the function can return is nil, whereas, the java function has no idea about how to handle nil's in strings

23:22 that would be my guess after learning clojure for a month ;)

23:32 brehaut: metajack: thats really quite surprising

23:33 symbole: Maybe (String/valueOf nil) is not calling valueOf(Object obj).

23:33 metajack: brehaut: it throws null pointer exception. from what i can tell all the other versions of valueOf take primitives

23:34 brehaut: my java is not super sharp, but i didn't think the primitive types were nullable?

23:34 hi talios

23:34 talios: hola

23:35 symbole: brehaut: They're not. Maybe they're being set to null internally, and that's why it fails? I'm not really sure.

23:37 #() is a Clojure function which takes Object(s) as an argument, so I think nil might be converted to an Object before it makes its way to valueOf.

23:37 brehaut: symbole: its implicitly an Object if nil anyway

23:38 metajack: well in the real code i found this in, ti's a named function defined with defn, but i reproduced it with #()

23:39 brehaut: metajack: #() is expanded by the reader to a (fn […) form

23:39 er fn*

23:39 metajack: So I don't think that particular form matters for this issue.

23:41 brehaut: metajack: indeed; it seems only that its crossing a method boundary that matters

23:42 amalloy: ,(String/valueOf nil)

23:42 clojurebot: #<NullPointerException java.lang.NullPointerException>

23:42 amalloy: ,(#(String/valueOf %) nil)

23:42 clojurebot: "null"

23:42 amalloy: $javadoc String valueOf

23:42 lazybot: http://download.oracle.com/javase/6/docs/api/java/lang/String.html#valueOf(java.lang.Object)

23:44 amalloy: so valueOf(Object) is willing to convert null to "null". the others aren't, of course, because they take primitives

23:45 metajack: So direct invocation basically picks one of the primitive versions incorrectly?

23:46 amalloy: metajack: probably. i'm not intimately familiar with clojure's typehinting algorithms, but i believe the compiler knows that a nil literal is of class null

23:47 whereas in the other case it only knows it will be given an Object. perhaps it chooses to compile that into a no-reflection dispatch to String/valueOf(Object)

23:49 ,(String/valueOf ^Object nil)

23:49 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Metadata can only be applied to IMetas>

23:49 amalloy: ,(#(String/valueOf ^Integer %) nil)

23:49 clojurebot: "null"

23:49 amalloy: ,(#(String/valueOf ^int %) nil)

23:49 clojurebot: #<CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: int, compiling:(NO_SOURCE_PATH:0)>

23:49 amalloy: hmph

23:50 brehaut: ,(let [a nil] (String/valueOf a))

23:50 clojurebot: #<NullPointerException java.lang.NullPointerException>

23:50 brehaut: ,(let [a nil] (String/valueOf ^Object a))

23:50 clojurebot: "null"

23:50 amalloy: sure, that much is given

23:51 symbole: metajack: I think it's worth posting this quesiton to the mailing list. I'm curious what this is all about.

23:51 amalloy: i'm surprised to see that neither of metajack's original versions causes the compiler to emit reflective code

23:51 brehaut: likewise

23:52 what is particularly odd is, it should give a more useful error if its selecting a method incorrectly based on type

23:52 , (let [a nil] (String/valueOf ^int a))

23:52 clojurebot: #<CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: int, compiling:(NO_SOURCE_PATH:0)>

23:52 amalloy: brehaut: no, i don't think it should. the exception should be coming when the compiler tries to unbox the Long it's working with

23:53 and discovers that the Long is nil

23:54 brehaut: but its not choosing to unbox right? theres no reflection warnings

23:56 amalloy: brehaut: it's not dealing with a primitive long, it's compiled against a Long, i think (this is assuming, arbitrarily, that it's chosen the long overload)

23:56 so the un-reflective code says "unbox this Long to a long, then call String/valueOf"

23:57 brehaut: I'm not sure i understand why it would choose to compile against the long overload

23:57 (and incidentally, the same error occurs in 1.2)

23:59 amalloy: brehaut: i don't think it *should* compile against the long overload, but i can imagine it happening, and it would explain the issue

Logging service provided by n01se.net