#clojure log - Jun 19 2010

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

0:52 scott_: I noticed #() forms use fn* underneath. How does that differ from fn?

0:59 hiredman: scott_: in ways that don't matter for #()

1:00 scott_: What are those ways?

1:29 hiredman: scott_: fn* doesn't have destructuring

1:29 scott_: hiredman: So #() maybe uses it just for the (possibly very small) performance boost

1:30 remleduff: fn is the special form, so technically, you shouldn't be concerned with the fn* implementation detail

1:38 Blackfoot: is there a type for unsigned short? trying to use clj-native the JNA library

1:40 scottj: I don't think java has unsigned types

1:41 Blackfoot: hmm that makes sense. ok, i'll try just using short

2:42 what the clojure way to define fields? I want to compare int return values. do i just (def FORMAT_MP3 3) over and over?

2:47 vIkSiT: hmm, whats the best way to serialize a clojure data structure?

2:48 I've been trying to figure out some methods using print-dup, but I keep getting stuck.

2:50 Blackfoot: i think print-dup is the standard way in 1.1, in 1.2 the core Clojure data structures will all be

2:50 Serializable

2:50 but i don't personally have much experience with it, sorry

2:52 vIkSiT: Blackfoot, ah thanks for the info.. but do you have any pointers on where to start looking for serialization anyway?

2:54 Blackfoot: there's been a few conversations on the mailing list, so you might have some luck there.

2:54 i think the answer so far for simple objects has been to bind *print-dup* to true and just use (str)

2:54 http://richhickey.github.com/clojure/branch-1.1.x/clojure.core-api.html#clojure.core/*print-dup*

3:00 hoeck: Blackfoot: I'm using maps and my own macro for perf-sensitive code

3:01 Blackfoot: hoeck: hmm ok, yea maps sounds like a reasonable way to go

3:02 hoeck: and with a simple (zipmap (vals m) (keys m)), you get a reverse lookup too

3:15 vIkSiT: hmm

3:15 is there a way to serialize refs?

3:17 hoeck: vIkSiT: do you really want to serialize the ref or just its content?

3:17 vIkSiT: hoeck, ah yes, just the content :)

3:17 I should probably try @ damn

3:18 hoeck: vIkSiT: :)

3:18 vIkSiT: hoeck, hmm, so I've got some complex data structures though

3:18 for instance, one looks likes this: #:cljsimpledb.catalog.Catalog{:c #<Ref@e28099: {}>, :cnt #<Ref@429bc5f9: 0>}

3:19 ideally, I'd like to be able to read direclty back into a record of type catalog

3:20 hoeck: I see no way other than writing your own serializer/deserializer then

3:21 or change your code so that the mutation does not happen in the Catalog record, but somewhere outside

3:22 vIkSiT: hoeck, hmm, not entirely sure what you mean by the mutation bit..

3:22 could you explain a bit more?

3:24 hoeck: instead of putting the ref inside the Catalog record, put the Catalog itself into a ref and make the :c field immutable, this way, you wont hav to serialize a ref when you serialize the Catalog record

3:26 vIkSiT: aah. hehe, at this point I've got some more refs inside the Catalog record

3:27 hoeck, generally, is writing your own serializer etc recommended?

3:27 (also, whats a good resource to learn about writing one?)

3:28 hoeck: from what i can see, you have no other choice than to write your own

3:29 do you want to use java-serialization or clojure and read?

3:32 vIkSiT: http://gist.github.com/444675

3:32 maybe using print-method this way will temporarily solve your problem

3:32 vIkSiT: hoeck, not sure which one would be better?

3:33 hoeck: clojure+read is way easier, java-serialization potentially faster and more space efficient (on disk) but also more complicated to use

3:33 java serialization requires your defrecords to be AOT-compiled

3:35 I guess it depends on wether you load som kilobytes of config data or a Gigabyte of statistical data :)

3:35 vIkSiT: hoeck, ah, I'm building a database - so ideally, the java version would be good. But to start with, the clojure+Read looks good :)

3:35 hoeck, so what exactly does your function do in this case?

3:36 the print-method, that is

3:36 hoeck: it defines the way the FooCatalog record should be printed

3:37 the print representations of all clojure objects are defined this way

3:37 vIkSiT: ah I see

3:37 so if I wanted to print that to a file..

3:37 how would I do it?

3:37 hoeck: and you can overwrite that with your own versions

3:37 just (spit "filename" foo-catalog-instance)

3:38 and load it with (read-string (slurp "filename"))

3:39 ,spit

3:39 clojurebot: java.lang.Exception: Unable to resolve symbol: spit in this context

3:40 hoeck: spit is defined in clojure.contrib.io, at least by the clojure-contrib version I am using, slurp is in core

3:42 vIkSiT: aah

3:42 let me check

3:42 hiredman: spit is also in core these days

3:42 :/

3:42 but I've never seen the one in core actually work

3:42 it just seems to break things

3:42 vIkSiT: hiredman, facing that right now!

3:42 how does one use it?!

3:43 hiredman: don't

3:43 vIkSiT: (spit (File. "filename") obj) ?

3:43 hiredman: use the one from io or duck-streams

3:43 vIkSiT: er, how does one import that? my REPL seems to have messed up

3:44 hoeck: vIkSiT: (require '[clojure.contrib.io :as io])

3:44 hiredman: (ns-unmap (create-ns 'clojure.core) 'spit)

3:44 vIkSiT: Could not locate clojure/contrib/io__init.class or clojure/contrib/io.clj ..

3:44 hoeck: and then io/spit

3:44 hiredman: (use '[clojure.contrib.io :only [spit]])

3:45 then you are missing contrib from your classpath

3:45 vIkSiT: ahm.

3:45 hoeck: or clean up the repl first as hiredman suggests :)

3:45 vIkSiT: I did clean up :)

3:45 and i've got both contrib and core in project.clj in lein; and running lein swank

3:50 hiredman: what version of contrib?

3:50 and what version of core?

3:51 if you have spit in core and no io in contrib your versions are most likely out of whack

3:52 vIkSiT: hmm

3:52 clojure-1.2.0-master-20100607.150309-85.jar ; clojure-contrib-1.2.0-master-SNAPSHOT.jar

3:52 from lein deps

3:53 hiredman: that contrib is old

3:54 if I recall it shouldn't even work

3:54 vIkSiT: hehe

3:54 hiredman: if you clean out your ./lib/ and ~/.m2/ lein deps will fail because those jars are not even on the server anymore

3:55 contrib doesn't have "master" in the version anymore

3:55 vIkSiT: wow I didn't even know there was a ~.m2

3:55 So, the best way to continue is to clean out lib and

3:55 ~m2*, and then do lein deps again?

3:55 clojurebot: http://github.com/technomancy/leiningen

3:56 hiredman: no

3:56 you should just fix the version specified in the project.clj

3:57 vIkSiT: so what should those versions be?

3:57 Is there a canonical name for the "latest"?

3:59 hiredman: [org.clojure/clojure-contrib "1.2.0-SNAPSHOT"]

3:59 vIkSiT: hiredman, ah so no "master" in either clojure or contrib.

4:00 TakeV: How would I evaluate a string that is clojure code?

4:02 hoeck: ,(eval (read-string "(+ 1 2 3)"))

4:02 clojurebot: DENIED

4:02 hiredman: vIkSiT: clojure still has it

4:03 vIkSiT: ah.

4:04 TakeV: hoeck: Thanks. :)

4:04 hoeck: TakeV: np :)

4:10 vIkSiT: hoeck, can the defmethod you created for FooRecord also be used with other functions than spit?

4:24 hoeck: vIkSiT: this method will be called whenever you call some kind of print on the record

4:25 vIkSiT: hoeck, ah.. looks like I'll need to figure out how to do this with buffered readers/writers.. spit is just too unreliable :)

4:26 hoeck: sorry, you have to actually call it this way: (spit filename (pr-str <that-record>))

4:26 str on the record only calls a generic .toStirng method

4:28 vIkSiT: ah

4:28 hoeck: vIkSiT: http://gist.github.com/444708

4:29 c.c.io to the rescue!

4:29 vIkSiT: aha :) thats much better

4:29 just got it working with io/spit as well

4:30 i wonder if I could use it with a binary file too

4:30 hoeck: but for a real database, I'm shure you will need your own serialization, writing directly to bytearrays or bytebuffers

4:31 vIkSiT: yes, I've got a pretty good idea of how to organize pages and heap files

4:31 hoeck: good :)

4:31 vIkSiT: my only bottleneck right now is - how do i take a clojure structure and convert it to a binary representation

4:32 hoeck: for defrecords, one way may be to put them in a plain hashmap, and serialize that hashmap instead

4:32 vIkSiT: hoeck, http://gist.github.com/444710 - this is what i'm trying to do right now with binary files

4:32 hoeck: or serialize the AOT-compiled defrecord directly

4:32 vIkSiT: hoeck, ah hmm. interesting

4:33 I guess my problem is that the records look something like this :

4:33 hoeck: or traverse your record tree and use java serialization on all unknown types and a special serialization for records and refs

4:35 vIkSiT: https://gist.github.com/a96c9f930e808fbd3c7d

4:35 hoeck, too complex to serialize? :P

4:36 hrm, is there a way to pretty print a record?

4:38 hoeck: have you tried pprint?

4:38 (use '[clojure.pprint :only [pprint]])

4:38 (pprint ......)

4:39 vIkSiT: woo. thats pretty

4:39 :)

4:40 hoeck, thats what I'm trying to serialize: https://gist.github.com/a96c9f930e808fbd3c7d

4:40 I think I've got lots of refs, but I think I can get by with serializing bits and parts of it

4:41 hoeck: mmh, all those refs do not make serializing that thing easier :D

4:41 vIkSiT: hehe yeah

4:41 the problem is, not hving ANY mutable semantics in there make things so much harder

4:43 hoeck: what about walking that record tree, derefing all refs, then serialize the result?

4:43 and for deserialization, just load that tree from disk, walk it and insert the required refs, no?

4:45 vIkSiT: yep exactly

4:45 Chousuke: I'd say that's way too many refs

4:45 vIkSiT: chousuke, hmm..

4:45 Chousuke: in general, having nested refs breaks easy snapshotting.

4:47 vIkSiT: hmm. I guess I need atleast 2 levels of refs there though - given that the list of tuples in a table needs to be mutable; and so does the schema

4:47 the others I can try to get rid of

4:47 hoeck: vIkSiT: if you *really* need a mutable structure, and have the balls to deal with all the synchronization consequences, you may also use (defrecord Foo [^:volatile-mutable c]) :)

4:47 Chousuke: vIkSiT: remember update-in, it's handy for nested structures

4:47 vIkSiT: ah good point

4:48 hoeck: or ^:unsynchronized-mutable

4:48 Chousuke: hoeck: deftype though.

4:48 hoeck: Chousuke: right

4:49 vIkSiT: hoeck, btw, whats the advantage of ysing voltaile or unsynch mutable there?

4:49 using*

4:50 hoeck: you don't need refs or atoms, less overhead for single threaded or unsynchronized usages

4:50 vIkSiT: interesting

4:50 Chousuke: They can be used to create data types that do mutation internally.

4:50 vIkSiT: oh that IS useful

4:51 Chousuke: it's also difficult :)

4:51 vIkSiT: so if I understand it right, I could have a "table" record that has all the mutation happen inside it, atomically?

4:51 oh? :)

4:51 Chousuke: no, :unsynchronized-mutable is not atomic at all as far as I know.

4:51 hoeck: I'm using currently a ^:volatile-mutable for implementing a JDBC resultset type, the resultset interface is inherently stateful and single threaded

4:52 Chousuke: you'd still need locks and other things around it.

4:52 vIkSiT: ah I see

4:52 hoeck: vIkSiT: when using mutable or volatile, you have to take care of synchronization yourself, e.g. through thread-confinement

4:52 vIkSiT: so maybe I should go more functional, and put things inside a top level refs only

4:52 ref*

4:52 Chousuke: it's like a plain old non-final java field.

4:52 vIkSiT: gotcha

4:53 Chousuke: vIkSiT: you can start with that, and add more refs if you encounter scalability problems.

4:53 vIkSiT: right. I was thinking, that if I were to implement the heap or a b-tree with purely functional attributes, its going to be really bad in terms of space complexity

4:54 but maybe I can just reduce the number of levels my refs go into..

4:57 ok sleep time, laters. thanks for the insight, chousuke and hoeck

6:45 Licenser: there we go back in arms to fight for clojure

6:51 geeez

6:51 DarthShrine: Hmm?

6:52 Licenser: the changes in the qual branch are a horror

6:54 ,(* 10000000000000 1000000000000)

6:54 clojurebot: java.lang.ExceptionInInitializerError

6:54 Licenser: ,(* 100000000000 1000000000000)

6:54 clojurebot: java.lang.ExceptionInInitializerError

6:54 Licenser: $(* 100000000000 1000000000000)

6:54 sexpbot: java.lang.ClassNotFoundException: clojure.core$fn__4819$fn__4820

6:54 Licenser: wow

6:54 $(* 100000000 1000000000)

6:54 sexpbot: => 100000000000000000

6:54 Licenser: $(* 100000000 10000000000)

6:54 sexpbot: java.lang.NoClassDefFoundError: clojure/core$fn__4819$fn__4820

6:54 Licenser: $(* 100000000 1000000000)

6:54 sexpbot: => 100000000000000000

6:54 Licenser: this is odd

6:55 ,(* 100000000 1000000000)

6:55 clojurebot: 100000000000000000

6:58 AWizzArd: Licenser: it still is beta software and will hopefully be fixed in the coming time.

6:58 Licenser: AWizzArd: I worry about that it seems to be a design decision

6:59 decisions are not usually fixed :P

7:01 AWizzArd: Well, if it is a bug it will be fixed I guess. If this is intended, then the error message could get improved.

7:01 But otherwise, if this is a compile time error then it is fine.

7:01 It will mean that you will be confused during compilation, but then after the initial shock can fix it, and produce working code.

7:02 And next time you know that either * is not the right fn to call, or that the args you used don't work there

7:02 ,(+ "Hello " "World")

7:02 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number

7:02 AWizzArd: That is an okay error message.

7:02 And it would be even nicer to catch this at compile time :)

7:03 Licenser: heh

7:03 can't in a dynamic language

7:03 that is the problem

7:03 Chousuke: well you can

7:03 since the strings are literals

7:03 Licenser: partially not entirely I think

7:03 yes for this case but not for every case

7:03 and unless it is for every case you in the end really can't

7:03 Chousuke: but Clojure does not do much correctness analysis at all :P

7:04 Licenser: it rather throws Java exceptions

7:04 but that's ok, what is not OK in my eys is that you've odd behaviour now for numbers :(

7:04 and that you tecnically have statically typed loops

7:05 and that implictly not even explictly (which would be ugly but not as bad)

7:06 I like type hints since they let you decide when you enforce a type but having the code decide for you 'You want to use a long here!' without you saying it, is wrong

7:07 AWizzArd: There can be a (fully) optional type system on top of every programming language.

7:07 With such Clojure can be statically checked, if the developer wishes this.

7:08 This is called “Gradual Typing”, and with it you can make very granular descisions of how much will be type checked or not.

7:08 Licenser: I agree and I loved that you can have typs if you want and not have them otherwise

7:08 but that changed

7:09 now it is like that in most places but when you use loop clojure takes this decision away from you and you will have if you want or not statical typing

7:09 AWizzArd: Could be from nothing at all over just one fn of your whole code base up to really everything, so that you end up with a totally type checked program, that does not allow dynamic changes of fns at runtime.

7:09 Licenser: Rich mentioned yesterday that he plans to throw error messages in such loops.

7:09 Licenser: it still is bad

7:09 AWizzArd: with error messages?

7:10 Licenser: look at this:

7:10 user=> (loop [n 1 r 1] (if (zero? n) r (recur (dec n) (str r r))))

7:10 NO_SOURCE_FILE:1 recur arg for primitive local: r is not matching primitive, had: java.lang.String, needed: long

7:10 java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number (NO_SOURCE_FILE:1)

7:10 yes because it IS statically typed

7:11 AWizzArd: Well, with this error message it is fine.

7:11 Licenser: this decision goes beyond you having to worry about integer overflows it introduces static typing

7:11 AWizzArd: but you can't write dynamically typed code there any more

7:11 this is the problem

7:11 AWizzArd: why not?

7:11 Licenser: because it crashes

7:11 because loop is statically typed to [long long]

7:12 and it will never take any other objects w/o crashing

7:12 AWizzArd: Does this occur during compilation/loading of a file, or at runtime?

7:12 Licenser: the warning during loading the crash during runtime

7:12 AWizzArd: but the warning sounds great

7:12 Licenser: how you can likely have cases where one of the values of recur does not always have to same type as before

7:13 it is still wrong

7:13 or clojure becomes a statically typed language but then please explictly

7:14 AWizzArd: (defn foo [] (loop [x (Object.)] (recur "hi")))

7:14 Licenser: one good thing about clojure is that it is a dynamical language that I can toss stuff around as much as I want and don#t have to worry about types since I don't tell the code what typs they are. This is gone, history, we are now in scala/java world where you have to watch out, typecast and do all this orrible things. And even worst we don't even KNOW what typs we use since clojure dictates what we want to use.

7:14 oh yea great :P

7:14 AWizzArd: in that case recur must return any Object

7:14 Licenser: AWizzArd: welcome to java

7:15 AWizzArd: but this IS currently what *every* object was typed with

7:15 In all programming languages all fns take only Object parameters and return them.

7:15 in all dynamically typed ones

7:15 Licenser: AWizzArd: but you can't initialize x with a useful value instead of Object

7:15 AWizzArd: The type signature must always be correct, in them all.

7:15 Licenser: the example above won't work

7:16 AWizzArd: Anyway, why would you want to exchange the type of an object?

7:16 clojurebot: datatype is see datatypes

7:16 AWizzArd: I think this will be wrong in nearly all cases

7:16 Licenser: for example when I go in a code from a vector to a list, or to a map?

7:16 AWizzArd: I don't want to be able to do (+ "Hi" (File. "/my/file"))

7:16 Licenser: then it is a collection

7:17 Licenser: yes but why do they behave differently?

7:17 and I can see cases where you go from 1 to 1.0, many of them

7:17 AWizzArd: They are different objects.

7:17 Licenser: so we do spaceal cases for numbers since they can be nice and confusing then?

7:17 AWizzArd: Being an experieced bicycle user does not qualify me to be Formula 1 expert

7:17 Licenser: AWizzArd: that is a horrible bad example :P

7:18 AWizzArd: Not so much. Objects and interactinos with them don't work in infinite ways

7:18 Licenser: I don't mind explic static typing, we have ^static for that. but I do very much mind implect one

7:18 AWizzArd: Numbers are the real exception in computing because of limits in memory and computational speed.

7:18 With an infinite amount of memory and an infinite fast system there would only be the type "number" ever

7:18 Licenser: this limits also apply for ever other kind of object, be it a string, a list a ector

7:19 AWizzArd: Well, in that sense Clojure was always statically typed.

7:19 Every fn argument had to be of class Object

7:19 Licenser: AWizzArd: but isn't it more important that the program works then it is fast? For our every day program we don't care at all of + is 0.1 ms faster

7:20 AWizzArd: that is word mangeling

7:20 AWizzArd: It is totally important that the program works correctly.

7:20 Licenser: yes and this breaks it

7:20 it requires in deepth understanding of the special cases for numbers to be sure your program works and you can get bitten in the ass with very confusing stuff

7:20 AWizzArd: But sometimes we know that a program will work correctly and not suddenly overflow from 9 trillions to minus 9 trillions because we added 1

7:20 Licenser: I mean why the heck is (num 1) different form 1?

7:21 AWizzArd: you're wrong

7:21 AWizzArd: how?

7:21 clojurebot: with style and grace

7:21 Licenser: when all are numbers this won't happen

7:21 in the new code, yes, this will happen and this is exaclty what I don't want to see happening

7:21 AWizzArd: True, but I gave this example explicitly for code which we want to run fast.

7:22 And in that case it is important that there are warnings/error messages. And then it is fine.

7:22 Licenser: AWizzArd: but then we are aware of the risks, if we are forced to optimize explictly we are also forced to know where the problems will arise if there are any

7:22 AWizzArd: When the compiler tells me: man, you are using the fast stuff here, but there are type mismatches - then it is perfectly fine. I just don't want it to go unnoticed.

7:23 Licenser: Mean question: how many useful error messages have you seen in clojure?

7:23 AWizzArd: It would be bad if we could not say (num 1.5) anymore

7:23 But we can still use the boxed types. With those error messages are more unlikely.

7:23 They can still run into problems, if your numbers are very very big

7:23 Licenser: yes run out of memory, or end up never finishing but that are other kinds of problems

7:24 AWizzArd: But typically we have enough ram, so there will be no runtime erros.

7:24 Licenser: with modern computers speed, performance should take second pace over correctness

7:24 that is why premature optimisation is so much hated by so many people

7:24 AWizzArd: But the warnings tell you that your code is not correct.

7:24 Licenser: but now we create a language that forces you to do that

7:25 AWizzArd: Not when the compiler warns/errors us

7:25 Licenser: AWizzArd: no the code is correct clojure made it incorrect that is the problem

7:25 AWizzArd: It is not correct that you switched the types.

7:25 You don't have a gas pedal on your bicycle

7:25 Licenser: yes it is since we do have a number stack for that

7:25 on some I do actually yes

7:26 AWizzArd: hehe :)

7:26 Well, can you test your above code with r (num 1) please?

7:26 Licenser: I can do (* 1 0.5) and it works

7:26 but I can't do it in a loop

7:26 it will work

7:26 AWizzArd: so, where is the problem then?

7:27 Licenser: that I do have to write (num) and know what it does to get the most intuitive behaviour

7:27 and to work around stupid static typing

7:27 AWizzArd: The intuitive behaviour is just a thing we can get used to.

7:27 Licenser: AWizzArd: it is not a problem for you or me since we have disucssed this and understand the workings

7:27 AWizzArd: After a few rounds we will understand that such things need to get constructed specifically.

7:28 I also don't mind having to write (File. "/my/path")

7:28 Licenser: but seriousely how will you sell this to your collegues: Oh clojure is dynamically typed, but if you use a loop you've to be very careful to use the right types, nono you can't give them explictly the compiler tells you what you want to do isn't that great?

7:28 AWizzArd: vs f"/my/path"

7:28 Licenser: the problem is the special behavior of loop that it acts differently then other things

7:28 AWizzArd: Being dynamically typed means that there is not edit->compile->run cycle anymore, and that you have an administrative system

7:29 Dynamically typing is not about being able to say x=15 ... x="Hi"

7:29 Licenser: dynamic typing has to do with typing not with build cycle

7:29 a language being dynamic has to be with the build cycle

7:29 AWizzArd: Being able to change the type of the object a variable refers to is *possible* in dynamic typing, but this is a bad side effect and should never occur in production code

7:29 only in some cases for let it is useful

7:30 to increase readability

7:30 A dynamic typed language is more like a OS that you can administer

7:30 You don't need to decide which programs you want to run, in which order, before your start your computer

7:30 Licenser: dynamically typed functions means that you can write (inc 1) and (inc 1.0) without having to write a gazillion of inc methods

7:30 AWizzArd: while it is running you can change the system, install new programs, create files, and such

7:30 no

7:31 Licenser: yes

7:31 AWizzArd: Nope sorry, this is not an enforced feature.

7:31 Licenser: http://de.wikipedia.org/wiki/Dynamic_typing

7:31 AWizzArd: Dynamically typed is being able to say: (defn foo [] (println "Helo")) and then a minute later (defn foo [] (println "Hello"))

7:32 Being able to say (defn foo...) in the first place is already dynamic typing

7:32 Licenser: no that is dynamic not dynamic typed

7:32 AWizzArd: In a statically typed program I can't because I write the program before I run it.

7:32 Licenser: and you can do that in C too you know?

7:32 AWizzArd: In Clojure I first run my program, then write it.

7:32 Licenser: that has nothing to do with dynamic typing

7:32 AWizzArd: In C I can do it when I engage a dynamic typing style of programming

7:33 Licenser: AWizzArd: please look at the link

7:33 AWizzArd: No need, i know pretty well what i am talking about.

7:34 Licenser: no :P

7:34 AWizzArd: correct calculations of numbers is typically a feature in dynamically typed languages. It is not required that I don't need to construct them specifically.

7:34 Licenser: I can edit that website to state whatever I want.

7:34 In Clojure I have to construct File objects to work with them correctly.

7:35 And I have to construct generic numbers explicitly from now on.

7:35 No big deal, it is only a few keystrokes away and only in rare cases needed.

7:36 As long the compiler warns me about this everything is fine.

7:36 If Clojure were statically typed it would mean that I can not change foo at runtime anymore

7:36 Licenser: AWizzArd: it makes the language more complex and confusing it goes away from the elegant and simple things

7:36 AWizzArd: This could be the case.

7:36 I don't want to argue against such statement.

7:37 We will have to see how much production code is affected by this.

7:37 I will recompile my sources and check how many warnings get generated.

7:37 Licenser: AWizzArd: but agian to typing C is statically typed but I can very well change the value later in the code

7:38 AWizzArd: I don't know if most C compilers are really statically type checking the code.

7:38 But right now I don't see how you can typically start the C repl, then write a program (a function) and run it.

7:38 There can be a C repl of course, I just don't know if this is the way how C programs get written in practice

7:39 clojurebot: clojure euler is http://clojure-euler.wikispaces.com/

7:39 Licenser: well in c.c you get 3 warnings

7:39 AWizzArd: I see.

7:40 Can they get fixed?

7:41 djpowell: i have no real interest in bigints, but I agree with Licenser that this is static typing of the loop var, and I don't like it

7:41 Licenser: djpowell: neither do I have a real interest in bigints, but I think the default should be Number since we have it and it is nice as it just works

7:42 djpowell: I'm not too worried, this is just an experiment, not the downfall of clojure

7:42 AWizzArd: That's a whole different issue. Personal preferrence over having to type in 5 more chars in rare cases or not is different from the compiler helping you to write correct code.

7:43 Licenser: AWizzArd: http://gist.github.com/444827

7:43 this is one of the things

7:43 AWizzArd: I guess Rich just sees how much faster code is that uses longs or doubles instead of Numbers, and that typically calculations don't go out of the limits of -9 trillion to 9 trillion

7:43 Licenser: AWizzArd: we're all going to die!!!

7:43 AWizzArd: let me see

7:44 What is the problem with that code?

7:44 Licenser: I love longs and doubles but I'd like to have to tell the compiler when I need this speed improvement

7:44 AWizzArd: Does it produce no warnings and at the same times produces incorrect results?

7:44 Licenser: math.clj:112 recur arg for primitive local: y is not matching primitive, had: java.lang.Number, needed: long

7:44 you could write y (num 1)

7:44 but that'd be silly

7:44 AWizzArd: Two conditions must be true at the same time for this new feature to suck: it must compile code without warnings *and* run incorrectly

7:45 If one of two conditions is not met it is fine.

7:45 (num 1) won't kill us

7:45 djpowell: i'm not sure how I feel about +' and friends, they don't look too bad. the issue is though, that the loop variable cannot be promoted by them, because the compiler has already *incorrectly* inferred that it should be an int, just because the init value hapenned to fit in an int.

7:45 AWizzArd: this is just one little function

7:45 It is mostly a psychological issue, not a technical one I guess.

7:46 Licenser: I find +' being for primitives good +' for num's not so good

7:46 AWizzArd: In the end I really don't care much if both are available.

7:46 Licenser: AWizzArd: of cause it is but psychological issues are very important. The first impression is most impotant and telling someone who does the euler procject for example oh you need to use +' and *' and (num 1) will be a instant turn off

7:47 I tell you, if that had been the case when I started clojure I'd not be here today

7:47 AWizzArd: Yes, they are important. The reason why I use Clojure is mostly psychological of course.

7:47 djpowell: Licenser: if what was the case?

7:47 AWizzArd: If I were not human and evolved to be a really good programmer, then I can just write assembler code.

7:47 Licenser: because my impression would have been 'what a bunch of whiredos that force you to jump through hoops for simple code'

7:47 that I'd need to know about +' *' and (num 1) to do the project euler stuff

7:48 djpowell: Licenser: the inference of the type of the loop variable? Or the more general changes with non-promoting arithmetic

7:48 AWizzArd: Well, adding (num) at 3 places of a 6k LOC program is not really bad, especially when the compiler tells us the exact line numbers (:

7:48 Licenser: AWizzArd: no BUT if it is amongst the first things you see about a language it is a very bad thing

7:48 AWizzArd: The Euler code is not representative for typical production code.

7:48 djpowell: it is the sort of incidental complexity that clojure mostly strives to avoid

7:49 Licenser: adding (long 3) in 10 places where you know speed is ain issue in 6k LOC isn't a problem either

7:49 AWizzArd: but it is what people see first

7:49 AWizzArd: May be true. I can only see that I personally don't care about this. I care about productivity, and this is not an issue here.

7:49 Licenser: For my projects I really don't care for this I care for clojure in general and a first impression

7:49 AWizzArd: in the long run it is

7:50 djpowell: I think though, if we had something like loop variables defaulting to holding nums, and a ^int type hint to declare them to hold primitives, then that would be better

7:50 AWizzArd: If Clojure were to remove the GC or the repl, then *that* would piss me off.

7:50 Licenser: since the only way to find clojure programmers is to get them interested, and it might be nice that you can do your production code but if you don't find other codes to work with you, you'll have to drop clojure and start writing java

7:50 djpowell: yap exactly that would be great

7:51 I love if you could do all the stuff in the equal branch but would not HAVE to

7:51 AWizzArd: djpowell: it may that way, defaulting to more correct code and specifying that we want it faster

7:51 djpowell: literals could still squeeze into primitives if they wanted to, but they would be automatically wrapped in loop initialisers unless you asked for them to not be

7:51 AWizzArd: That would be okay for me personally, as well as defaulting to fast code *plus* compile-time warnings

7:52 Licenser: AWizzArd: there isn't nessesarily a hard destinction between compile time and run time

7:52 AWizzArd: Licenser: does 1n already work in your branch?

7:52 Licenser: 1n yes gibes me a big int

7:52 AWizzArd: and (num 1)?

7:52 Licenser: but again it is added complexity

7:52 yes that too

7:52 AWizzArd: k

7:52 Licenser: simple problems should be solved with simple code

7:53 AWizzArd: I agree that it increases the complexity.

7:53 And I think we all agree that it increases efficiency too.

7:53 Licenser: yes it does

7:54 not efficiency but performance actually

7:54 it decreasees efficiency in my eyes

7:55 AWizzArd: Well, I was implying: efficiency = run time performance

7:56 Licenser: okay I would see efficiency as how effecticient you can write code

7:56 mmarczyk: ah, just sent another reply to the ggroup thread...

7:56 AWizzArd: That I call productivity

7:57 mmarczyk: I have to say I'm pretty happy with the equal as it stands, but I'd prefer autobox-or-hint

7:57 Licenser: the other is called performance :P but again we're bickering about words, we know what we mean, yes it increases performance but decreases productivity

7:57 AWizzArd: I don't say it decreases productivity

7:57 because I don't measure productivity in mere seconds

7:58 But in increases the complexity.

7:58 Licenser: as I do, and this increases complexity

7:58 AWizzArd: Productivity comes through more important features, not because I have to type (File. "path") instead of f"path"

7:58 That is no productivity win

7:58 But having a GC is

7:58 being able to write functional code is

7:58 Licenser: AWizzArd: it is not about having to call some method bot about intuition

7:58 AWizzArd: having fully persistent datastructures is

7:59 Licenser: File. is perfectly explaind and intuitive by the very basic of clojures concept

7:59 mmarczyk: AWizzArd: sure you're not going to claim that (File. "path") vs. f"path" is comparable to being required or not required to know the representations of your numbers?

7:59 Licenser: the behaviour of loo not

7:59 mmarczyk: ^surely.

8:00 AWizzArd: I don't know if humans have intuition in respect to programming. I don't see how we evolved being programmers. In fact, humans totally suck at programming.

8:00 Licenser: I don't ;P

8:00 AWizzArd: We have some training, and from that perspective plus my years of CL background it is indeed against my personal "intuition"

8:00 mmarczyk: :-)

8:00 AWizzArd: Where "intuition" means "my personal training"

8:01 If I were taught that it is normal to work that way in programming I would be surprised how unintuitive Python programs are

8:01 silveen: Try writing software in english, if your native language was lojban, perhaps programming would be more natural

8:01 Licenser: AWizzArd: no it does not, the most intuitive thing is that the simplest possbile code is the correct one

8:01 mmarczyk: in order to expect that 1243590283469103468 + 132478619034851734208671 equals something big you need, what, grade school training?

8:01 whereas to expect wraparound you need something rather more involved which is likely never going to win over your initial intuitions, as it well should not

8:02 ah, actually no danger of wraparound here... but same goes for exceptions

8:02 AWizzArd: I am now an experienced professional, and this whole issue really does not affect me.

8:02 Licenser: AWizzArd: again it does in the long run

8:02 AWizzArd: I see how it affects newbies, and egoistic as I am, I don't care about them ;-)

8:02 Licenser: AWizzArd: you should because they might be your feature employees or employers

8:02 AWizzArd: People are only the shortest amount of time in the state of being a newbie in their programmieng carrier.

8:03 Licenser: the one thing for a language to stand on the market is to have many people using it or we end up as CL :P

8:03 mmarczyk: and that's precisely when they make some of the most important choices

8:03 most of which they cannot possibly make in an educated way at that stage

8:03 AWizzArd: Licenser: as colleagues I would try to hire pros such as you, not newbies.

8:03 Licenser: AWizzArd: but this might be one of the most important ones

8:03 AWizzArd: but I was a newbe too, and I'd not have started clojure if I had to know about the inner workings of number to write some of the euler projects

8:04 meaning there might not be a next Licenser

8:04 AWizzArd: we all were newbies

8:04 Licenser: of cause there won't be ever another Licenser but that is a different matter :P

8:04 AWizzArd: We will have to see and wait.

8:04 hehe!

8:04 yup

8:04 Licenser: but we can either work into this direction or work towards the direction of having many new happy Licenser's

8:04 that is a decision we can and have to make

8:04 AWizzArd: Especially one wit this crazy-professor kind of hairstyle :p

8:05 Licenser: :P

8:05 sadly current changes indicate that we work towards having not many new happy Licensers but poor unhappy Licenser that are 'stuck' with Ruby since they actually do what you expect most of the time

8:05 AWizzArd: I care more about having a language that is oriented on programming experts, not newbies

8:06 The featuresets are often mutually exclusive

8:06 Licenser: AWizzArd: but this isn't the problem we're facing

8:06 keeping the default case 'newbie friendly' won't change anything for the experts

8:06 AWizzArd: ok, I can agree with that

8:06 Licenser: we still can have our speed, and performance if we need it and since we ARE experts we know when we need it and when not

8:07 and we understand how the Number stack and primitives work, and how to apply ugly tricks to squeeze the last few mili secionds out of a loop

8:07 AWizzArd: See, for me it is fine having the behaviour that is still the official one, namely correctness first. But having efficiency first plus compile warnings is as well as okay for me.

8:08 Well, the nicest thing would be: have the correct code first but also an intelligent compiler which will rewrite our code to the fast one if that would be still correct

8:08 Licenser: I actually don't see the downside of having correctness first since when you want (or need) efficiency just writing code without thinking aobut is won't be enough anyway

8:09 AWizzArd: yes that'd be my dream

8:09 AWizzArd: The compiler could interview us and ask questions about how this code is being used, it could read the design specs and talk to the customers.

8:09 Licenser: heh

8:09 AWizzArd: But this is still 10-20 years in the future.

8:09 Licenser: that'd be annoying kind of trust me I wrote a proram that did kind of that

8:09 AWizzArd: Well, at that point there will be not many programmers anymore.

8:09 Licenser: not for compiling code but compiling configurations but it turned out to be very annoying

8:09 AWizzArd: It's a dying profession :)

8:09 Licenser: AWizzArd: nonsense

8:10 genius never die out :P

8:10 no computer will ever have my brilliant ideas :P

8:10 OForero: Hello

8:10 AWizzArd: I see

8:10 Hey OForero

8:10 OForero: I am stuck at something

8:10 AWizzArd: Wie geht es dir? ;)

8:10 OForero: http://paste.pocoo.org/show/227239/

8:10 Licenser: :P

8:10 OForero: sehr gut danke

8:10 und selber?

8:11 obwohl Clojure macht mich gerade fertig ... :-(

8:11 AWizzArd: I am fine too, thanks

8:11 Better let's switch back to english. But there is also a #Clojure.de

8:12 OForero: my written german is not fluent :-(

8:12 I think I hit the limits of the simulation ... or something

8:15 AWizzArd: OForero: your use of (get x 0) and (get x 1) is confusing

8:15 better would be to say (key x) and (val x)

8:16 or at least (first x) and (second x)

8:16 your prepare fn could also use destructuring

8:16 (defn prepare [[name value]] ...)

8:17 (defn prepare [[name value]] `(def ~name ~value))

8:17 something like that would be easier to read

8:18 Licenser: *nods*

8:22 djpowell: I think I'd be ok with the branch, except: + would be promoting; +' would be non-promoting; loop initialisers would auto-box unless they were given primitive type hints

8:28 rbarraud: ;

8:29 * Licenser gnaws at his network

8:29 AWizzArd: wb Lice

8:29 Licenser: thanks

8:35 mmarczyk: djpowell: didn't you mean that the promoting ops should be *non*-primed...?

8:35 (that's re: the ggroup post)

8:35 djpowell: oh yeah that

8:35 mmarczyk: right, agreed in that case

8:35 though mostly I think you should need the primes only if you need the hints

8:36 (surely if you hint you also know where to prime? ;-))

8:37 djpowell: well not necessarily

8:37 primed ops are polymorphic

8:37 hinted ones aren't

8:37 er, i think...

8:40 i'm not entirely sure anyway to be honest

8:41 mmarczyk: not sure if you're referring to the current state of affairs or to the desired state of affairs?

8:41 my point is that whatever should be the default should not be primed

8:41 djpowell: what do you mean by default?

8:42 mmarczyk: "use that unless you actually know you need the other one"

8:43 OForero: AWizzArd: thanks for the tips

8:44 I will use those

8:44 but the problem is that the record type is lost in the binding when using the function

8:44 AWizzArd: And that I find surprising too.

8:45 OForero: the macro work, but I am not able to use it in a map operation

8:45 I think I will mail it to the list

8:46 Licenser: I'm not sure if you can use macros in maps

8:46 AWizzArd: OForero: (first (map prepare data)) ==> (def rec #:user.Record{:a 1, :b 2, :c 3})

8:47 (nth *1 2) ==> #:user.Record{:a 1, :b 2, :c 3}

8:47 (eval *1) ==> {:a 1, :b 2, :c 3}

8:48 (eval (Record. 10 20 30)) ==> {:a 10, :b 20, :c 30}

8:48 and not #:user.Record{:a 10, :b 20, :c 30}

8:48 Records don't eval to themselves, they eval to maps

8:48 That is the issue here.

8:49 OForero: ok

8:49 that will explain why the macro works

8:49 AWizzArd: yes

8:49 OForero: because it does not eval the parameters at input

8:50 I kind of think records shouldn't forget their recordness

8:50 mmarczyk: ooh, that's a cool bit of knowledge on records

8:50 OForero: I will post it to the group and see what reactions are there

8:51 AWizzArd: k

8:52 * AWizzArd admits that he is a bit surprised about this.

8:52 AWizzArd: There we have this intuition thing again :)

8:55 Good morning rhickey.

8:56 OForero: I am bias ... because I still like types

8:56 Licenser: rhickey my favourte victom for code suggestions, how are you today?

8:56 OForero: and kind of think that loosing type information is bad

8:56 (that is why I do not like erasure)

8:58 AWizzArd: It is strange how records eval to maps when evaled 'twice'

8:59 mmarczyk: twice?

8:59 OForero: I have to go and hunt

8:59 I'll check later about this again ...

8:59 AWizzArd: thanks for finding the reason

9:00 Licenser: (eval #:user.Record{:a 1, :b 2, :c 3})

9:00 ,(eval #:user.Record{:a 1, :b 2, :c 3})

9:00 clojurebot: No dispatch macro for: :

9:00 OForero: one more lesson ....

9:00 Licenser: ,(eval '#:user.Record{:a 1, :b 2, :c 3})

9:00 clojurebot: No dispatch macro for: :

9:01 mmarczyk: Licenser: records are not readable...

9:01 also, I think clojurebot uses 1.1

9:01 hiredman: ,*clojure-version*

9:01 clojurebot: {:interim true, :major 1, :minor 2, :incremental 0, :qualifier "master"}

9:01 mmarczyk: oh, forgive me, clojurebot

9:02 I didn't quite realise how new & shiny your circuits were :-)

9:02 Licenser: mmarczyk: was just trying something out :)

9:03 AWizzArd: mmarczyk: sorry, forget this twice thing, I was wrong

9:03 mmarczyk: OForero: well actually

9:03 OForero: the reason your code doesn't work is that prepare-2 sees %

9:04 OForero: the symbol, I mean...

9:04 AWizzArd: ,'%

9:04 clojurebot: %

9:05 mmarczyk: so if you put a (print x) before the syntax-quoted form in the definition of prepare-2, it will print out the gensym for you when you try to use it like that

9:05 before breaking

9:05 making it apparent what's going on.

9:07 OForero: ok ... I will try that

9:09 AWizzArd: you can also call macroexpand-x on your macro call to test them

9:10 mmarczyk: effectively you'd like the macro to receive the argument *evaluated* -- which is contrary to the point of macros -- just use a function instead

9:10 OForero: macro expand does not work here

9:10 AWizzArd: ,(macroexpand-x '(when 1 2))

9:10 clojurebot: java.lang.Exception: Unable to resolve symbol: macroexpand-x in this context

9:10 OForero: because the macro works

9:10 it fails when used in the collection

9:10 mmarczyk: it doesn't fail when used "in the collection"

9:10 AWizzArd: uhm, 1, not x

9:10 ,(macroexpand-1 '(when 1 2))

9:10 clojurebot: (if 1 (do 2))

9:10 mmarczyk: it fails because you use it as (prepare-2 %)

9:11 the % gets turned into a gensym -- a one-off symbol -- by the #(...) syntax

9:11 so effectively it gets a symbol

9:11 but that symbol names a local, namely the sole parameter to the anonymous function

9:11 and you can't eval that

9:11 OForero: mmarczyk: I was using a function ... but it has the amnesia problem

9:12 mmarczyk: Licenser: hey, let Rich answer the previous batch of e-mails! :-)

9:12 Licenser: mmarczyk: :P psst I just had a new idea let me toss it in°

9:13 mmarczyk: Licenser: but more importantly, I'm afraid the suggestion was that that's not easy... dunno myself though

9:13 Licenser: if this is possible it would be a actuall good compromise

9:13 well I admit I'm not sure how loop is implemented

9:13 mmarczyk: OForero: amnesia?

9:13 OForero: if you check the pastie

9:13 mmarczyk: I have

9:14 OForero: the first thing I attempted was with a function

9:14 mmarczyk: right

9:14 OForero: but because Records evaluate to maps

9:14 then the type is lost

9:14 mmarczyk: I think you might need to do (import example.Record)

9:14 OForero: and I need the type because if not I can not call the protocol on it

9:14 mmarczyk: which I promise I only thought about now

9:15 give it a go maybe? :-)

9:15 OForero: ok ... I will try that

9:15 mmarczyk: yup, works for me

9:15 some JVM leaking through the Clojure abstraction, I'm afraid

9:15 OForero: nop

9:16 really?

9:16 mmh

9:16 I reload the file then

9:16 mmarczyk: yeah, try a fresh repl... I will too

9:17 oh, I see, hm

9:19 OForero: nope

9:19 the record lost its type ... also after the import

9:19 mmarczyk: and what would you like to happen? for rec to hold your record?

9:19 OForero: yes ...

9:20 I am working in a sort of dsl

9:20 AWizzArd: Maybe you need to AOT it?

9:20 OForero: and I pass a map with records and functions

9:20 mmarczyk: use intern maybe

9:20 OForero: but there are some functions that I declared in protocols

9:20 and those require the type to work

9:21 AWizzArd: Well, I would also expect that class instances evaluate to themselves

9:21 OForero: AOT?

9:21 clojurebot: AOT genclass is http://paste.lisp.org/display/70665 and http://clojure-log.n01se.net/date/2008-11-18.html#14:19

9:21 AWizzArd: I would be surprised if (eval (File. "")) would not result in .. a file

9:21 mmarczyk: ,(doc intern)

9:21 clojurebot: DENIED

9:21 mmarczyk: ah, well

9:21 OForero: you can use intern instead of def

9:21 AWizzArd: OForero: you call (compile-file 'on-your-namespace)

9:21 mmarczyk: it's a function which will create your Var for you

9:21 then you don't have to use macros at all

9:21 but, on a related note, your multimethod doesn't work for me

9:22 OForero: intern? ...

9:22 what is the problem?

9:22 mmarczyk: ahh, sorry, it does work, my bad :-P

9:22 OForero: (prepare-2 (first data)) works

9:22 mmarczyk: well

9:22 you can write binder as

9:23 (defn binder [x] (intern *ns* (toSymbol-2 (get x 0)) (get x 1)))

9:23 then it's a function and you can map it over a collection

9:23 and if I understand you correctly, it does what you want

9:23 OForero: ok ... that will replace the prepare

9:23 yes

9:23 let me try that

9:24 mmarczyk: (binder (first data))

9:25 OForero: yep

9:25 that work in the example

9:26 I have to plug it into my code and see if that works ...

9:26 mmarczyk: (defn binder [xs] (doseq [x xs] (intern *ns* (toSymbol-2 (get x 0)) (get x 1))))

9:26 OForero: thanks for the training session

9:27 mmarczyk: :-)

9:27 OForero: you think doseq is more idiomatic because of the side effects?

9:27 mmarczyk: doseq *works* with side effects :-)

9:27 map would have to be forced with dorun, say

9:27 OForero: I know ... the question was if the creation of the vars is a side effect

9:28 because it works with map

9:28 mmarczyk: well, yes, it is

9:28 it might work at the repl

9:28 OForero: fine

9:28 mmarczyk: but depending on where you put it in your code

9:28 OForero: your are right .... I have to remember that

9:28 mmarczyk: right

9:29 OForero: in the absence of a type system ... it is very good to have a helpful community

9:29 :-)

9:30 mmarczyk: :-)

9:31 eval-on-a-record remains funky

9:32 rhickey: do records evaluate to maps by design?

9:34 rhickey: mmarczyk: what does 'evaluate to maps' mean?

9:34 mmarczyk: (class (eval some-record))

9:35 gives me clojure.lang.PersistentArrayMap for some record I'm using

9:35 AWizzArd: rhickey: (defrecord Foo [a b]) ... (eval (Foo. 10 20)) ==> {:a 10, :b 20}

9:37 rhickey: ah, no, could you please make a ticket for that?

9:38 mmarczyk: AWizzArd: your discovery :-)

9:39 AWizzArd: k

9:39 mmarczyk: alright, going off for now... bbl

9:40 OForero: thanks guys

9:41 AWizzArd: can you ping me the ticket number?

9:41 I will put it in my document ... and of course reference you

9:41 mmarczyk: thanks ... it does works in my main code

9:42 and it is shorter

9:46 AWizzArd: OForero: http://bit.ly/bAq5DX

10:12 What is the best way to find out if a given object is an instance of some record?

10:23 djpowell: AWizzArd: will (instance? MyRecord x) do?

10:24 tho, if you're doing instance tests, then perhaps you should be using some sort of polymorphism instead?

10:24 AWizzArd: djpowell: I want to write a serializer

10:25 but non-AOT'ed records can not be serialized by using the jvm mechanism

10:25 so I need to identify those, them all

10:25 not just a specific one

10:25 (record? foo) I need

10:25 and/or (deftype? foo)

10:26 djpowell: I don't think there is a way at the moment

10:27 AWizzArd: Yesterday hoeck suggested something about having a look at the classloader

10:29 djpowell: don't do this :) - (.startsWith (pr-str p) "#:")

10:29 AWizzArd: would be cool though if all deftypes and records implemented one (possibly empty) interface that allows me to identify them

10:30 djpowell: great, this seems to be the best solution :p

10:30 djpowell: I imagine that records will get a readable representation soon enough

10:32 AWizzArd: too slow

10:32 That does not scale

10:57 rustemsuniev: is there any better way to find an element in map? (filter #(and (= (get % :x) 1) (= (get % :y) 3) ) [{:x 1 :y 1} {:x 1 :y 2} {:x 1 :y 3}])

11:02 AWizzArd: rustemsuniev: that is basically okay, but you could use destructuring (fn [{:keys [x y]}] (and (= x 1) (= y 3)))

11:02 Leafw: question: if clojure.parallel is deprecated, what replaces it?

11:02 rustemsuniev: AWizzArd: Thanks!

11:03 dnolen: ,(some #(when (= (map % [:x :y]) [1 3]) %) [{:x 1 :y 1} {:x 1 :y 2} {:x 1 :y 3}])

11:03 clojurebot: {:x 1, :y 3}

11:08 rustemsuniev: dnolen: Cheers! :)

11:11 Leafw: sorry, I'd appreciate help understanding if there is a new clojure.parallel package, since the old one has been marked as deprecated.

11:25 OForero: AWizzArd: thanks ... I'll go back to my shores ...

11:29 djpowell: Leafw: the old clojure.par required the ParallelArray classes from a version of jsr166y which isn't going into Java 7

11:30 (or is that clojure.parallel)

11:31 anyway, there is a 'par' branch which relies only on the lower level jsr166y classes, which will go into Java 7, and rather than having to convert your code to work with par classes, in that branch Clojure's vectors implement the necessary stuff, so it is all very easy and faster

11:31 but, that requires at least Java 6, whereas clojure currently only requires Java 5, so I think that branch has been shelved for a bit until a decision is made to make clojure require Java 6

11:32 there is still pmap in core, if you just need a parallel map...

11:32 the par branch hasn't been updated in a while tho

11:34 I don't think there would be a problem using the deprecated parallel stuff in the meantime

11:55 Leafw: ,(def a 6)

11:55 clojurebot: DENIED

11:56 Leafw: ,(let [a 6 a2 (with-meta a {:test #(if (< % 10) (throw (Exception. "< 10!")))}] (test a))

11:56 clojurebot: Unmatched delimiter: ]

11:57 Leafw: ,(let [a 6 a2 (with-meta a {:test #(if (< % 10) (throw (Exception. "< 10!")))})] (test a))

11:57 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IObj

11:57 Leafw: hum anybody could explain what is wrong with that with-meta declaration?

11:59 djpowell: thanks for the par explanations. So it's all in the par branch.

12:05 ,(clojure.set/intersection (keys {2 "two" 4 "four"}) #{2 3})

12:05 clojurebot: java.lang.ClassCastException: clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentSet

12:05 Leafw: that I don't understand either

12:06 how come KeySeq doesn't implement IPersistentSet ?

12:06 ubolonton: In the let form a is not a var

12:07 It is literally 6 there

12:07 So it's (with-meta 6 ...)

12:07 Leafw: ubolonton: ok, but with (def a 6) and (def a (with-meta ....)) same problem, ubolonton

12:12 hoeck: Leafw: numbers cannot have metadata

12:14 Leafw: (def a 6), a is a var, not a number

12:14 it evaluates to a number, but that is different.

12:14 hoeck: but a resolves to a number

12:14 ubolonton: Yes it is evaluated before be passed to with-meta

12:14 Leafw: so how can one give the var a its meta data ?

12:14 ubolonton: with-meta is a function not a macro

12:14 (with-meta 'a ...)

12:14 Leafw: I see. So one needs (with-meta (var a) {}) ...

12:15 oh. ok.

12:15 unevaluated a ... gets its meta map. thanks

12:16 and then, how can the var a be read from within the test function? The test function is given no arguments, and direct use of 'a' in it fails with Symbol can't be cast to number. How can the test function get the value of the variable it tests for?

12:16 hoeck: Leafw: but metadata on vars is not settable

12:17 Leafw: hoeck: yes I know, its (def a (with-meta ...

12:17 hoeck: no, with-meta doesn't work on vars

12:18 just found that out :P

12:18 Leafw: hoeck: I am not sure I understaht what you mean. with-meta returns a var, doesn't it?

12:19 hoeck: with-meta returns a new object with the attached metadata

12:19 Leafw: sure. That 'object' is a var

12:19 hoeck: but only if that object implements the IObj interface, and a var doesn't

12:19 Leafw: hum, no, it returns a Symbol, sorry

12:19 buf

12:20 dud, I am confused. What is the proper usage of with-meta and :test and (test ...) ?

12:21 hoeck: you specify the :test function in the defn

12:22 and to alter a vars metadata, you use alter-meta

12:22 Leafw: defn? I see. One cannot test a var then? What is the use of testing a function?

12:22 hoeck: or def of course :)

12:22 ,(doc def)

12:22 clojurebot: DENIED

12:23 Leafw: alter-meta doesn't exist, hoeck

12:23 hoeck: sorry, its alter-meta!

12:24 ,(doc alter-meta!)

12:24 clojurebot: "([iref f & args]); Atomically sets the metadata for a namespace/var/ref/agent/atom to be: (apply f its-current-meta args) f must be free of side-effects"

12:25 Leafw: I see, !

12:25 hoeck: because it mutates sth.

12:25 Leafw: right

12:26 hoeck: now I understand what you're trying to do, using test to check the contents of a var

12:26 Leafw: yes :)

12:28 hoeck: (def #^{:test (fn [] 1)} foo 1)

12:29 note that the new metadata syntax uses ^ instead of #^

12:29 and then invoke the test with (test #'foo)

12:30 Leafw: but the test function is now aware of the value of foo

12:30 so of what use is it?

12:30 hoeck: that was just an example test function

12:30 Leafw: yes I understand :)

12:30 but I tried giving the test fn an arg, and then that fails

12:31 (test #'foo) would return :no-test

12:31 it's (test foo), I think

12:31 hoeck: (declare a) (def #^{:test fn-using-a} a 1)

12:32 Leafw: I can get that o work, but I don't see the point of a test function for a var that is not aware of the value of the var.

12:32 hoeck: as its a var, you can just use it in the test function like any other vars

12:33 though you have to declare that var first, because the test-function will be evaled before the def

12:35 Leafw: hoeck: that actually fails

12:35 (def a 6)

12:35 (def a (with-meta 'a {:test #(if (< a 10) (throw (Exception. "Value under 10!")))}))

12:35 (test a)

12:35 java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to java.lang.Number

12:35 so "a" is not visible, or is read in a way that I don't udnerstand.

12:37 hoeck: http://gist.github.com/445036

12:38 Leafw: so declare works but def doesn't :)

12:38 now that is yet another source of confusion

12:39 hoeck: no, you're defining the var "a" to be the symbol "a" with the attached :test metadata

12:40 kiras: hi

12:40 hoeck: and then you are calling (test a), which uses the metadata on the symbol a to test the value of the variable a, which is the symbol a, which is not a number ! :P

12:40 Leafw: (test a) basically uses ((:test (meta a)))

12:41 kiras: i have a question that is turning into a book... how many lines should i post at once?

12:41 Leafw: I must say this is not as clear as I think it is.

12:41 kiras: post a gist at github

12:41 kiras: Leafw: ok, ty

12:41 Leafw: hoeck: but thanks for the explnation. I am reading it like a 12 times

12:41 hoeck: the key point is understanding vars

12:42 whenever you do (def a 1), you define a var

12:42 when you evaluate `a' on the repl, you get the contents of that var

12:43 Leafw: yes, so much I get it

12:43 hoeck: so (meta a) gets the metadata of the object _inside_ the var

12:44 Leafw: so the var contains a symbol and a value, is that right

12:44 and the var itself has a meta map.

12:44 hoeck: no, the var only contains that value

12:44 Leafw: so what links the symbol and the value?

12:45 hoeck: the mapping of names to var-objects is done by the clojure runtime, I guess

12:45 Leafw: so a symbol has a meta map then? Or is it the var, which contains the symbol, that has the meta map?

12:46 sorry, that second part is clearly wrong: I meant Or is it the var, which contains the symbol, that has the meta map?

12:46 xD

12:46 s/symbol/value

12:46 hoeck: the var has a meta-map

12:47 Leafw: ok

12:47 and also the value object.

12:47 hoeck: and the value can have metamap too, if its a symbol

12:47 right

12:47 Leafw: sure, rabitt hole all the way deep

12:47 hoeck: but not if the value object is a number, because numbers do not implement metadata

12:47 Leafw: makes sense

12:47 by the way

12:47 hoeck: or keywords do also not implement metadata

12:48 right, and back to your initial problem

12:49 (def #^{:a 1} foo 1) adds {:a 1} as metadata to the to-be-created var `foo'

12:50 Leafw: the (test #'a) then gets the meta map for the 'a itself. Otherwise, (test a) would test for the meta map of the value of a, which is 6, which doesn't have any.

12:50 hoeck: exactly

12:50 Leafw: I think I am getting it. Thanks hoeck

12:50 hoeck: np :)

12:51 Leafw: I knew about #^{} in def. You mentioned though that now it is being changed to ^ alone, without # ?

12:52 and by the way, isn;'t it a huge overhead that all vars have a meta map? Or is that map nil except when explicitly defined?

12:53 hoeck: well, its just a plain pointer in the vap object, and gets out of the way pretty easily

12:53 but it offers great capabilities, each var object for instance as :line and :file metadata

12:55 Leafw: indeed most values in clojure end up not in vars but in a let or as members of a collection.

12:55 hoeck: and with the upcoming ^:static flag, there is enough room to improve performance where needed

13:00 Leafw: hoeck: what does the ^:static do?

13:00 hoeck: Leafw: on recent clojure snapshots, ^ is used as a reader-macro for metadata, its less visually disturbing than #^, I beleive #^ will be marked deprecated

13:00 Leafw: I see, both #^ and ^ work, currently.

13:01 hoeck: of course, they will work both for a while

13:01 Leafw: ^ used to mean something else thoguh

13:01 but I forgot what it was.

13:01 hoeck: it was for accessing metadata?

13:01 ^:static indicates, that a function can be compiled as a method

13:02 it will then loose its closure-property, but can take primitive args and will be less dynamic

13:03 code using ^:static functions has to be reevaluted to call new versions of the static functions

13:03 Leafw: I see. So it throws one back to the java world.

13:03 both for the good and the bad :)

13:04 I can see a use for numerical operations with clojure, adding the ^:static once all works fine.

13:04 rhickey: Leafw: not really, you can do this while in the repl, with all your other code and data loaded, vs, quit, recompile, restart of Java

13:05 Leafw: rhickey: true. The "bad" is much less so.

13:05 rhickey: Leafw: it's more like the macro experience

13:05 Leafw: macros aren't closures either, is that what you mean?

13:06 rhickey: Leafw: seeing a change to a macro requires re-evaluation of client code

13:06 Leafw: every advice out there suggest not using macros, and I have found it the hardest to teach others.

13:06 rhickey: I understand. The macro got compiled and is aware only of what was declared when it was compiled.

13:07 rhickey: clojure.parallel is marked as deprecated in clojure.org. What will clojure 1.2 come with?

13:07 rhickey: no, the caller of a macro embeds its current definition, and won't use a new definition until it (the caller) is recompiled

13:08 Leafw: re-reading that ... I think I understood. Thanks.

13:09 by the way rhickey , clojure code made it into a J Neuroscience paper. Made my life easier and works great.

13:09 rhickey: Leafw: cool! - got a pointer?

13:10 serp_: (using emacs and swank): how do I compile a buffer the second time without getting errors about stuff already existing?

13:11 Leafw: http://www.jneurosci.org/cgi/content/full/30/22/7538 (see pdf here: http://www.ini.uzh.ch/~acardona/papers/Cardona_2010_lineage_identification.pdf ) and some of the clojure code, mostly as a data storage in a map of maps, here: http://www.ini.uzh.ch/~acardona/nit/

13:12 kiras: some questions i have: http://gist.github.com/445066

13:13 Leafw: rhickey: in the materials ad methods I acknowledge clojure as the language used.

13:15 the other major clojure fiel used is here: http://repo.or.cz/w/trakem2.git/blob/HEAD:/lineage/identify.clj

13:23 hoeck: kiras: the dash-underscore is because in idiomatic lisp, one uses dashes instead of underscores or camelcase, but java doesn't allow dashes in classnames

13:23 kiras: but im no lein expert, not shure how lein handles that

13:23 clojure of course allows dashes or underscores, its just not good style to create a my_name_space

13:23 kiras: hoeck: thanks. i knew that in lisp dashes were used instead, but i am confused by the way lein is doing this.

13:24 hoeck: it almost seems like if you do lein new test_project or lein new test-project, it should create the files with underscores, but use hyphens in (defproject) and (ns), doesn't it? i may be totally missing something though.

13:24 hoeck: in clojure, if you declare a dashed-name.space-test , its files must reside in the classpath at dashed_name/space_test.clj

13:25 kiras: right

13:25 i'm just saying, it would be bad to use lein new test-project as it currently works

13:25 because all the files/directories will be named with dashes

13:25 using lein new test_project will name the files/directories correctly

13:26 hoeck: kiras: lein is pretty young though, so it may have its rough edges

13:26 kiras: but then in the actual code, you get (defproject test_project) and (ns test_project.core)

13:26 hoeck: then simply use the lein test_project and replace the underscores in the generated files

13:26 kiras: hoeck: ok, i was trying to figure out if that was the right way to do things or not

13:27 hoeck: no, lein should definitively care about that

13:27 kiras: hoeck: i worked through the programming clojure book, but i haven't done any real clojure projects yet, just playing around at the repl

13:27 hoeck: but I'm not an active lein user anyways, have you used the latest version?

13:27 kiras: hoeck: so i was a little bit unsure of whether i was right or not

13:28 hoeck: i believe this is the latest, i can check

13:28 * hoeck is still using ant

13:28 kiras: heh

13:30 hoeck: if this is the latest version and it's behaving this way, then it's wrong, right? it should work like i was saying, where whether lein new test-project or lein new test_project is used, it should name files with underscores and use hyphens in the code? if this is the latest version, should i submit a bug report to someone?

13:32 hoeck: kiras: of course, I guess its best to post sth on the mailinglist

13:32 kiras: hoeck: the clojure mailing list?

13:33 hoeck: kiras: http://github.com/technomancy/leiningen

13:33 in the readme under "hacking" are some links to the mailing list and the issues section

13:34 but I haven't found a dash/underscore issue there

13:34 kiras: ah, thanks

13:34 well, it seems that i'm using 1.1.0 and there is a 1.2.0-RC1 available

13:35 maybe i should try that

13:35 hoeck: of course! :)

13:35 kiras: heh

13:36 thanks for the help. i'm going to see if that works better.

13:44 dnolen: rhickey: with the latest changes should I be seeing a per regression around amap/areduce?

13:44 s/per/perf

13:45 rhickey: dnolen: no, got a gist?

13:49 dnolen: rhickey: not yet, was testing a bigger program, I was seeing 22ms per iteration with the intro of +', now I'm back to 100ms, I'll need to come up something smaller/specific

13:49 rhickey: dnolen: if you are on the latest, you shouldn't be using +'

13:49 dnolen: rhickey: heh, things are moving quickly, missed that.

13:50 rhickey: dnolen: do a (doc +)

13:51 dnolen: also refresh: https://www.assembla.com/wiki/show/b4-TTcvBSr3RAZeJe5aVNr/Enhanced_Primitive_Support

13:52 dnolen: did you miss: http://groups.google.com/group/clojure/msg/9d13452a01048646

13:54 dnolen: rhickey: thx

13:56 rhickey: wow, am i correct in seeing that gives map like an order of magnitude speedup?

13:56 rhickey: sorry i mean reduce I think, or is that because internal reduce got re-enabled?

13:58 rhickey: dnolen: dunno what you are comparing

14:08 mmarczyk: ah, cl-format in contrib breaks down with current equal :-(

14:09 "had: Object, needed: long"

14:09 (grep for last_pos)

14:10 dnolen: rhickey: alternate universe is interesting. Thought it seems like the auto-promoting BigInt group in the Clojure community is either bigger or more vocal :) I'm still ok +', etc for fast-math.

14:11 Blackfoot: if i am writing a macro that takes multiple forms, assigning each form to generated symbol, how can i get the string representation of that form?

14:13 rhickey: mmarczyk: get latest contrib

14:13 mmarczyk: rhickey: oh... ok, pulling now, thanks

14:23 Chousuke: Blackfoot: (str form) :P

14:23 Blackfoot: or pr-str

14:24 Blackfoot: http://gist.github.com/445120 here's a simplified version, and i'ld like (printforms (inc 1) (inc 2)) to print (inc 1) (inc 2)

14:26 edbond: spend 30min looking how to write 1.2.0 version in leiningen, help please

14:26 Blackfoot: oh i think i see why that's not working, the forms are being run in the binding

14:27 edbond: org.clojure/clojure "1.2.0-SNAPSHOT" ?

14:27 serp_: org.clojure/clojure "1.2.0-master-SNAPSHOT"]

14:28 edbond: serp_: thanks

14:30 rustemsuniev: Is there any way to clean a *board* after test is executed? (defn boards-fixture [f] (binding [board (load-board 2 2)] (f)))

14:34 mmarczyk: Blackfoot: why not just ~forms instead of (list ~@forms) ?

14:35 actually ~(map (fn [f] `'~f) forms), I guess

14:35 Blackfoot: mmarczyk: that had an error in an earlier iteration iteration. ok, trying that now

14:36 mmarczyk: Blackfoot: (defmacro pf [& fs] `(doseq [f# '~(map (fn [f] `'~f) fs)] (println f#)))

14:37 note the extra quote before ~(map ... too

14:38 Blackfoot: actually (defmacro pf [& fs] `(doseq [f# '~fs] (println f#))) matches your spec

14:38 the other one prints (quote (inc 1)), this one prints (inc 1)

14:39 mixed things up in the first approach, my bad :-)

14:40 Blackfoot: no problem, less mixed up than me :) yea, sounds like i should not have spliced them

14:42 mmarczyk: I'm off for now, bbl

14:45 Blackfoot: thanks mmarczyk. next step is to actually show the result of running the form

15:29 qbg: rhickey: With respect to loop/recur, would it be possible to have the the compiler upgrade primitive bindings to boxed binding (and emit a note, perhaps) when one tries to recur with a non-matching type?

15:48 * dnolen doesn't see the problem with the way loop/recur works now

15:50 qbg: dnolen: Now as in the equal branch or now as in the master branch?

15:50 dnolen: qdg: loop/recur hasn't changed, it's a special form

15:52 qbg: But assuming 1 is a primitive causes strange behaviour to those who are used to the master branch

15:52 dnolen: the only issue is initializing with a literal. if you want a boxed accumulator ask for it.

15:52 they want loop/recur to participate as fns

15:52 I think this is a bad idea, it isn't an fn

15:55 qbg: (loop [i 1] (recur (foo i))) won't compile if foo is a regular function currently; some don't like that

15:57 OTOH, one could argue that if you are using loop/recur in normal code, you are doing it wrong.

16:01 dnolen: qbg: exactly, loop/recur converts directly to a low-level iteration. I see no reason to embed smarts into it.

16:02 i also image putting any checks in loop/recur for autopromotion will diminish perf, the whole point of using loop/recur in the first place

16:04 qbg: My previously presented idea would work at compile time, so there shouldn't be a performance difference

16:10 Kjellski: Hi there, could someone give me a hint on how to tell the leining repl that i want to (use '[clojure-csv]) or something? Thought the classpath would be set automatically?

16:10 dnolen: qbg: of course that hides the mistake of someone who wants primitives

16:11 raek: Kjellski: have you done "lein deps"?

16:11 Kjellski: yes, the jar is already present in lib/

16:11 qbg: dnolen: The compiler could emit a note if something like *warn-on-reflection* is set.

16:11 raek: ah, now I see it

16:11 (use 'clojure-csv)

16:12 otherwise you get the empty prefix list

16:12 Kjellski: tells me the same: java.io.FileNotFoundException: Could not locate clojure_csv__init.class or clojure_csv.clj on classpath: (NO_SOURCE_FILE:0)

16:12 raek: shouldn't it be clojure-csv.core?

16:13 that was what I found on http://github.com/davidsantiago/clojure-csv

16:13 maybe that have been changed recently

16:13 Kjellski: raek: damned, thanks man! that did the job!

16:15 dnolen: qbg: except that as rhickey points out anyone using loop/recur now will probably emit warning. loop/recur is primitive get over it, is my feeling.

16:20 tomoj: so either (loop [x (num 1)] ..) or (loop [x 1] ... (+' x ...)) is what to do when you want auto-promotion?

16:20 using unprime in the first loop

16:22 qbg: Right now you need to use +' to get auto-promotion

16:22 And the second loop won't compile because +' won't return a primitive

16:26 tomoj: so you're saying you need (loop [x (num 1)] ... (+' x ...)) ?

16:26 qbg: Yes

16:27 tomoj: ok, I see

16:27 (loop [x (num 1)] ... (+ x ...)) will use boxed longs but will throw an error on overflow?

16:28 qbg: Looks like it

16:29 (I'm assuming you are recuring with the result of math)

16:59 TakeV: Use ^ instead of #^ for type hints, right?

16:59 qbg: Yes

16:59 TakeV: Cool.

17:13 silveen: huh? ^ instead of #^? since when? and why?

17:14 raek: since 1.2 (#^ still works). no idea.

17:14 qbg: It has been like that for a while on the master branch.

17:15 silveen: wierd, but ok

17:21 Kjellski: I've got a question about lein. I've tried lein jar and lein uberjar, but the main class is not found when I try java -jar test.jar or java -jar test-standalone.jar ...

17:22 qbg: What do you have for :main in your project.clj?

17:23 Kjellski: qbg: Yes, and it points to the right file... *stupidasiseeit* do I need the (:gen-class) option for the target namespace?

17:24 qbg: That would help...

17:25 Kjellski: qbg: It's in and not helping after "lein clean" "lein compile" "lein jar" "java -jar test.jar"

17:26 qbg: for :main you have namespace and not its file, correct?

17:28 Kjellski: qbg: it's ":main test.core" and in that file it's "(ns test.core ..." something wrong with that?

17:28 qbg: If you replace :main with clojure.main, can you launch test.jar and get the clojure REPL?

17:30 Kjellski: qbg: the file is unter "src/test/core.clj" and I tried the clojure.main with clean compile jar and it leads to a no main class exception too...

17:30 qbg: Does it work when you create an uberjar?

17:30 MrHus: Kjellski: do you have a -main function?

17:32 Kjellski: qbg: yeah, then it works when i try to java -jar test-standalone.jar

17:32 MrHus: Yap, I have...

17:32 qbg: You are going to need to have clojure on the classpath when you launch test.jar

17:34 Kjellski: qbg: okay, thanks! Could I just use the one in lib/ from that project?

17:34 qbg: Yes

17:59 arohner: is there a function like repeatedly, where the seq ends when f returns nil?

18:00 I guess I can (take-while identity (repeatedly f))

18:00 qbg: (take-while #(not (nil? %)) (repeatedly f))

18:22 Kjellski: is there any way to make "lein repl" load the :main and it's namespace?

18:57 rbarraud: \

20:33 defn: lancepantz: ever get your code up for the rails + clojure?

21:09 anyone know what the docstring was for lazy-cons?

21:09 im trying to turn some lazy-cons laden code into lazy-seq code

21:34 trptcolin: defn: for some definition of "was" (pulled out of the "20081217" branch of the git repo), here it is: http://gist.github.com/445462

Logging service provided by n01se.net