#clojure logs

2010-06-19

00:52scott_I noticed #() forms use fn* underneath. How does that differ from fn?
00:59hiredmanscott_: in ways that don't matter for #()
01:00scott_What are those ways?
01:29hiredmanscott_: fn* doesn't have destructuring
01:29scott_hiredman: So #() maybe uses it just for the (possibly very small) performance boost
01:30remledufffn is the special form, so technically, you shouldn't be concerned with the fn* implementation detail
01:38Blackfootis there a type for unsigned short? trying to use clj-native the JNA library
01:40scottjI don't think java has unsigned types
01:41Blackfoothmm that makes sense. ok, i'll try just using short
02:42Blackfootwhat the clojure way to define fields? I want to compare int return values. do i just (def FORMAT_MP3 3) over and over?
02:47vIkSiThmm, whats the best way to serialize a clojure data structure?
02:48vIkSiTI've been trying to figure out some methods using print-dup, but I keep getting stuck.
02:50Blackfooti think print-dup is the standard way in 1.1, in 1.2 the core Clojure data structures will all be
02:50BlackfootSerializable
02:50Blackfootbut i don't personally have much experience with it, sorry
02:52vIkSiTBlackfoot, ah thanks for the info.. but do you have any pointers on where to start looking for serialization anyway?
02:54Blackfootthere's been a few conversations on the mailing list, so you might have some luck there.
02:54Blackfooti think the answer so far for simple objects has been to bind *print-dup* to true and just use (str)
02:54Blackfoothttp://richhickey.github.com/clojure/branch-1.1.x/clojure.core-api.html#clojure.core/*print-dup*
03:00hoeckBlackfoot: I'm using maps and my own macro for perf-sensitive code
03:01Blackfoothoeck: hmm ok, yea maps sounds like a reasonable way to go
03:02hoeckand with a simple (zipmap (vals m) (keys m)), you get a reverse lookup too
03:15vIkSiThmm
03:15vIkSiTis there a way to serialize refs?
03:17hoeckvIkSiT: do you really want to serialize the ref or just its content?
03:17vIkSiThoeck, ah yes, just the content :)
03:17vIkSiTI should probably try @ damn
03:18hoeckvIkSiT: :)
03:18vIkSiThoeck, hmm, so I've got some complex data structures though
03:18vIkSiTfor instance, one looks likes this: #:cljsimpledb.catalog.Catalog{:c #<Ref@e28099: {}>, :cnt #<Ref@429bc5f9: 0>}
03:19vIkSiTideally, I'd like to be able to read direclty back into a record of type catalog
03:20hoeckI see no way other than writing your own serializer/deserializer then
03:21hoeckor change your code so that the mutation does not happen in the Catalog record, but somewhere outside
03:22vIkSiThoeck, hmm, not entirely sure what you mean by the mutation bit..
03:22vIkSiTcould you explain a bit more?
03:24hoeckinstead 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
03:26vIkSiTaah. hehe, at this point I've got some more refs inside the Catalog record
03:27vIkSiThoeck, generally, is writing your own serializer etc recommended?
03:27vIkSiT(also, whats a good resource to learn about writing one?)
03:28hoeckfrom what i can see, you have no other choice than to write your own
03:29hoeckdo you want to use java-serialization or clojure and read?
03:32hoeckvIkSiT: http://gist.github.com/444675
03:32hoeckmaybe using print-method this way will temporarily solve your problem
03:32vIkSiThoeck, not sure which one would be better?
03:33hoeckclojure+read is way easier, java-serialization potentially faster and more space efficient (on disk) but also more complicated to use
03:33hoeckjava serialization requires your defrecords to be AOT-compiled
03:35hoeckI guess it depends on wether you load som kilobytes of config data or a Gigabyte of statistical data :)
03:35vIkSiThoeck, ah, I'm building a database - so ideally, the java version would be good. But to start with, the clojure+Read looks good :)
03:35vIkSiThoeck, so what exactly does your function do in this case?
03:36vIkSiTthe print-method, that is
03:36hoeckit defines the way the FooCatalog record should be printed
03:37hoeckthe print representations of all clojure objects are defined this way
03:37vIkSiTah I see
03:37vIkSiTso if I wanted to print that to a file..
03:37vIkSiThow would I do it?
03:37hoeckand you can overwrite that with your own versions
03:37hoeckjust (spit "filename" foo-catalog-instance)
03:38hoeckand load it with (read-string (slurp "filename"))
03:39hoeck,spit
03:39clojurebotjava.lang.Exception: Unable to resolve symbol: spit in this context
03:40hoeckspit is defined in clojure.contrib.io, at least by the clojure-contrib version I am using, slurp is in core
03:42vIkSiTaah
03:42vIkSiTlet me check
03:42hiredmanspit is also in core these days
03:42hiredman:/
03:42hiredmanbut I've never seen the one in core actually work
03:42hiredmanit just seems to break things
03:42vIkSiThiredman, facing that right now!
03:42vIkSiThow does one use it?!
03:43hiredmandon't
03:43vIkSiT(spit (File. "filename") obj) ?
03:43hiredmanuse the one from io or duck-streams
03:43vIkSiTer, how does one import that? my REPL seems to have messed up
03:44hoeckvIkSiT: (require '[clojure.contrib.io :as io])
03:44hiredman(ns-unmap (create-ns 'clojure.core) 'spit)
03:44vIkSiTCould not locate clojure/contrib/io__init.class or clojure/contrib/io.clj ..
03:44hoeckand then io/spit
03:44hiredman(use '[clojure.contrib.io :only [spit]])
03:45hiredmanthen you are missing contrib from your classpath
03:45vIkSiTahm.
03:45hoeckor clean up the repl first as hiredman suggests :)
03:45vIkSiTI did clean up :)
03:45vIkSiTand i've got both contrib and core in project.clj in lein; and running lein swank
03:50hiredmanwhat version of contrib?
03:50hiredmanand what version of core?
03:51hiredmanif you have spit in core and no io in contrib your versions are most likely out of whack
03:52vIkSiThmm
03:52vIkSiTclojure-1.2.0-master-20100607.150309-85.jar ; clojure-contrib-1.2.0-master-SNAPSHOT.jar
03:52vIkSiTfrom lein deps
03:53hiredmanthat contrib is old
03:54hiredmanif I recall it shouldn't even work
03:54vIkSiThehe
03:54hiredmanif you clean out your ./lib/ and ~/.m2/ lein deps will fail because those jars are not even on the server anymore
03:55hiredmancontrib doesn't have "master" in the version anymore
03:55vIkSiTwow I didn't even know there was a ~.m2
03:55vIkSiTSo, the best way to continue is to clean out lib and
03:55vIkSiT~m2*, and then do lein deps again?
03:55clojurebothttp://github.com/technomancy/leiningen
03:56hiredmanno
03:56hiredmanyou should just fix the version specified in the project.clj
03:57vIkSiTso what should those versions be?
03:57vIkSiTIs there a canonical name for the "latest"?
03:59hiredman[org.clojure/clojure-contrib "1.2.0-SNAPSHOT"]
03:59vIkSiThiredman, ah so no "master" in either clojure or contrib.
04:00TakeVHow would I evaluate a string that is clojure code?
04:02hoeck,(eval (read-string "(+ 1 2 3)"))
04:02clojurebotDENIED
04:02hiredmanvIkSiT: clojure still has it
04:03vIkSiTah.
04:04TakeVhoeck: Thanks. :)
04:04hoeckTakeV: np :)
04:10vIkSiThoeck, can the defmethod you created for FooRecord also be used with other functions than spit?
04:24hoeckvIkSiT: this method will be called whenever you call some kind of print on the record
04:25vIkSiThoeck, ah.. looks like I'll need to figure out how to do this with buffered readers/writers.. spit is just too unreliable :)
04:26hoecksorry, you have to actually call it this way: (spit filename (pr-str <that-record>))
04:26hoeckstr on the record only calls a generic .toStirng method
04:28vIkSiTah
04:28hoeckvIkSiT: http://gist.github.com/444708
04:29hoeckc.c.io to the rescue!
04:29vIkSiTaha :) thats much better
04:29vIkSiTjust got it working with io/spit as well
04:30vIkSiTi wonder if I could use it with a binary file too
04:30hoeckbut for a real database, I'm shure you will need your own serialization, writing directly to bytearrays or bytebuffers
04:31vIkSiTyes, I've got a pretty good idea of how to organize pages and heap files
04:31hoeckgood :)
04:31vIkSiTmy only bottleneck right now is - how do i take a clojure structure and convert it to a binary representation
04:32hoeckfor defrecords, one way may be to put them in a plain hashmap, and serialize that hashmap instead
04:32vIkSiThoeck, http://gist.github.com/444710 - this is what i'm trying to do right now with binary files
04:32hoeckor serialize the AOT-compiled defrecord directly
04:32vIkSiThoeck, ah hmm. interesting
04:33vIkSiTI guess my problem is that the records look something like this :
04:33hoeckor traverse your record tree and use java serialization on all unknown types and a special serialization for records and refs
04:35vIkSiThttps://gist.github.com/a96c9f930e808fbd3c7d
04:35vIkSiThoeck, too complex to serialize? :P
04:36vIkSiThrm, is there a way to pretty print a record?
04:38hoeckhave you tried pprint?
04:38hoeck(use '[clojure.pprint :only [pprint]])
04:38hoeck(pprint ......)
04:39vIkSiTwoo. thats pretty
04:39vIkSiT:)
04:40vIkSiThoeck, thats what I'm trying to serialize: https://gist.github.com/a96c9f930e808fbd3c7d
04:40vIkSiTI think I've got lots of refs, but I think I can get by with serializing bits and parts of it
04:41hoeckmmh, all those refs do not make serializing that thing easier :D
04:41vIkSiThehe yeah
04:41vIkSiTthe problem is, not hving ANY mutable semantics in there make things so much harder
04:43hoeckwhat about walking that record tree, derefing all refs, then serialize the result?
04:43hoeckand for deserialization, just load that tree from disk, walk it and insert the required refs, no?
04:45vIkSiTyep exactly
04:45ChousukeI'd say that's way too many refs
04:45vIkSiTchousuke, hmm..
04:45Chousukein general, having nested refs breaks easy snapshotting.
04:47vIkSiThmm. 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
04:47vIkSiTthe others I can try to get rid of
04:47hoeckvIkSiT: 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]) :)
04:47ChousukevIkSiT: remember update-in, it's handy for nested structures
04:47vIkSiTah good point
04:48hoeckor ^:unsynchronized-mutable
04:48Chousukehoeck: deftype though.
04:48hoeckChousuke: right
04:49vIkSiThoeck, btw, whats the advantage of ysing voltaile or unsynch mutable there?
04:49vIkSiTusing*
04:50hoeckyou don't need refs or atoms, less overhead for single threaded or unsynchronized usages
04:50vIkSiTinteresting
04:50ChousukeThey can be used to create data types that do mutation internally.
04:50vIkSiToh that IS useful
04:51Chousukeit's also difficult :)
04:51vIkSiTso if I understand it right, I could have a "table" record that has all the mutation happen inside it, atomically?
04:51vIkSiToh? :)
04:51Chousukeno, :unsynchronized-mutable is not atomic at all as far as I know.
04:51hoeckI'm using currently a ^:volatile-mutable for implementing a JDBC resultset type, the resultset interface is inherently stateful and single threaded
04:52Chousukeyou'd still need locks and other things around it.
04:52vIkSiTah I see
04:52hoeckvIkSiT: when using mutable or volatile, you have to take care of synchronization yourself, e.g. through thread-confinement
04:52vIkSiTso maybe I should go more functional, and put things inside a top level refs only
04:52vIkSiTref*
04:52Chousukeit's like a plain old non-final java field.
04:52vIkSiTgotcha
04:53ChousukevIkSiT: you can start with that, and add more refs if you encounter scalability problems.
04:53vIkSiTright. 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
04:54vIkSiTbut maybe I can just reduce the number of levels my refs go into..
04:57vIkSiTok sleep time, laters. thanks for the insight, chousuke and hoeck
06:45Licenserthere we go back in arms to fight for clojure
06:51Licensergeeez
06:51DarthShrineHmm?
06:52Licenserthe changes in the qual branch are a horror
06:54Licenser,(* 10000000000000 1000000000000)
06:54clojurebotjava.lang.ExceptionInInitializerError
06:54Licenser,(* 100000000000 1000000000000)
06:54clojurebotjava.lang.ExceptionInInitializerError
06:54Licenser$(* 100000000000 1000000000000)
06:54sexpbotjava.lang.ClassNotFoundException: clojure.core$fn__4819$fn__4820
06:54Licenserwow
06:54Licenser$(* 100000000 1000000000)
06:54sexpbot=> 100000000000000000
06:54Licenser$(* 100000000 10000000000)
06:54sexpbotjava.lang.NoClassDefFoundError: clojure/core$fn__4819$fn__4820
06:54Licenser$(* 100000000 1000000000)
06:54sexpbot=> 100000000000000000
06:54Licenserthis is odd
06:55Licenser,(* 100000000 1000000000)
06:55clojurebot100000000000000000
06:58AWizzArdLicenser: it still is beta software and will hopefully be fixed in the coming time.
06:58LicenserAWizzArd: I worry about that it seems to be a design decision
06:59Licenserdecisions are not usually fixed :P
07:01AWizzArdWell, if it is a bug it will be fixed I guess. If this is intended, then the error message could get improved.
07:01AWizzArdBut otherwise, if this is a compile time error then it is fine.
07:01AWizzArdIt will mean that you will be confused during compilation, but then after the initial shock can fix it, and produce working code.
07:02AWizzArdAnd next time you know that either * is not the right fn to call, or that the args you used don't work there
07:02AWizzArd,(+ "Hello " "World")
07:02clojurebotjava.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
07:02AWizzArdThat is an okay error message.
07:02AWizzArdAnd it would be even nicer to catch this at compile time :)
07:03Licenserheh
07:03Licensercan't in a dynamic language
07:03Licenserthat is the problem
07:03Chousukewell you can
07:03Chousukesince the strings are literals
07:03Licenserpartially not entirely I think
07:03Licenseryes for this case but not for every case
07:03Licenserand unless it is for every case you in the end really can't
07:03Chousukebut Clojure does not do much correctness analysis at all :P
07:04Licenserit rather throws Java exceptions
07:04Licenserbut that's ok, what is not OK in my eys is that you've odd behaviour now for numbers :(
07:04Licenserand that you tecnically have statically typed loops
07:05Licenserand that implictly not even explictly (which would be ugly but not as bad)
07:06LicenserI 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
07:07AWizzArdThere can be a (fully) optional type system on top of every programming language.
07:07AWizzArdWith such Clojure can be statically checked, if the developer wishes this.
07:08AWizzArdThis is called “Gradual Typing”, and with it you can make very granular descisions of how much will be type checked or not.
07:08LicenserI agree and I loved that you can have typs if you want and not have them otherwise
07:08Licenserbut that changed
07:09Licensernow 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
07:09AWizzArdCould 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.
07:09AWizzArdLicenser: Rich mentioned yesterday that he plans to throw error messages in such loops.
07:09Licenserit still is bad
07:09AWizzArdwith error messages?
07:10Licenserlook at this:
07:10Licenseruser=> (loop [n 1 r 1] (if (zero? n) r (recur (dec n) (str r r))))
07:10LicenserNO_SOURCE_FILE:1 recur arg for primitive local: r is not matching primitive, had: java.lang.String, needed: long
07:10Licenserjava.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number (NO_SOURCE_FILE:1)
07:10Licenseryes because it IS statically typed
07:11AWizzArdWell, with this error message it is fine.
07:11Licenserthis decision goes beyond you having to worry about integer overflows it introduces static typing
07:11LicenserAWizzArd: but you can't write dynamically typed code there any more
07:11Licenserthis is the problem
07:11AWizzArdwhy not?
07:11Licenserbecause it crashes
07:11Licenserbecause loop is statically typed to [long long]
07:12Licenserand it will never take any other objects w/o crashing
07:12AWizzArdDoes this occur during compilation/loading of a file, or at runtime?
07:12Licenserthe warning during loading the crash during runtime
07:12AWizzArdbut the warning sounds great
07:12Licenserhow you can likely have cases where one of the values of recur does not always have to same type as before
07:13Licenserit is still wrong
07:13Licenseror clojure becomes a statically typed language but then please explictly
07:14AWizzArd(defn foo [] (loop [x (Object.)] (recur "hi")))
07:14Licenserone 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.
07:14Licenseroh yea great :P
07:14AWizzArdin that case recur must return any Object
07:14LicenserAWizzArd: welcome to java
07:15AWizzArdbut this IS currently what *every* object was typed with
07:15AWizzArdIn all programming languages all fns take only Object parameters and return them.
07:15AWizzArdin all dynamically typed ones
07:15LicenserAWizzArd: but you can't initialize x with a useful value instead of Object
07:15AWizzArdThe type signature must always be correct, in them all.
07:15Licenserthe example above won't work
07:16AWizzArdAnyway, why would you want to exchange the type of an object?
07:16clojurebotdatatype is see datatypes
07:16AWizzArdI think this will be wrong in nearly all cases
07:16Licenserfor example when I go in a code from a vector to a list, or to a map?
07:16AWizzArdI don't want to be able to do (+ "Hi" (File. "/my/file"))
07:16AWizzArdLicenser: then it is a collection
07:17Licenseryes but why do they behave differently?
07:17Licenserand I can see cases where you go from 1 to 1.0, many of them
07:17AWizzArdThey are different objects.
07:17Licenserso we do spaceal cases for numbers since they can be nice and confusing then?
07:17AWizzArdBeing an experieced bicycle user does not qualify me to be Formula 1 expert
07:17LicenserAWizzArd: that is a horrible bad example :P
07:18AWizzArdNot so much. Objects and interactinos with them don't work in infinite ways
07:18LicenserI don't mind explic static typing, we have ^static for that. but I do very much mind implect one
07:18AWizzArdNumbers are the real exception in computing because of limits in memory and computational speed.
07:18AWizzArdWith an infinite amount of memory and an infinite fast system there would only be the type "number" ever
07:18Licenserthis limits also apply for ever other kind of object, be it a string, a list a ector
07:19AWizzArdWell, in that sense Clojure was always statically typed.
07:19AWizzArdEvery fn argument had to be of class Object
07:19LicenserAWizzArd: 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
07:20LicenserAWizzArd: that is word mangeling
07:20AWizzArdIt is totally important that the program works correctly.
07:20Licenseryes and this breaks it
07:20Licenserit 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
07:20AWizzArdBut sometimes we know that a program will work correctly and not suddenly overflow from 9 trillions to minus 9 trillions because we added 1
07:20LicenserI mean why the heck is (num 1) different form 1?
07:21LicenserAWizzArd: you're wrong
07:21AWizzArdhow?
07:21clojurebotwith style and grace
07:21Licenserwhen all are numbers this won't happen
07:21Licenserin the new code, yes, this will happen and this is exaclty what I don't want to see happening
07:21AWizzArdTrue, but I gave this example explicitly for code which we want to run fast.
07:22AWizzArdAnd in that case it is important that there are warnings/error messages. And then it is fine.
07:22LicenserAWizzArd: 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
07:22AWizzArdWhen 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.
07:23LicenserMean question: how many useful error messages have you seen in clojure?
07:23AWizzArdIt would be bad if we could not say (num 1.5) anymore
07:23AWizzArdBut we can still use the boxed types. With those error messages are more unlikely.
07:23AWizzArdThey can still run into problems, if your numbers are very very big
07:23Licenseryes run out of memory, or end up never finishing but that are other kinds of problems
07:24AWizzArdBut typically we have enough ram, so there will be no runtime erros.
07:24Licenserwith modern computers speed, performance should take second pace over correctness
07:24Licenserthat is why premature optimisation is so much hated by so many people
07:24AWizzArdBut the warnings tell you that your code is not correct.
07:24Licenserbut now we create a language that forces you to do that
07:25AWizzArdNot when the compiler warns/errors us
07:25LicenserAWizzArd: no the code is correct clojure made it incorrect that is the problem
07:25AWizzArdIt is not correct that you switched the types.
07:25AWizzArdYou don't have a gas pedal on your bicycle
07:25Licenseryes it is since we do have a number stack for that
07:25Licenseron some I do actually yes
07:26AWizzArdhehe :)
07:26AWizzArdWell, can you test your above code with r (num 1) please?
07:26LicenserI can do (* 1 0.5) and it works
07:26Licenserbut I can't do it in a loop
07:26Licenserit will work
07:26AWizzArdso, where is the problem then?
07:27Licenserthat I do have to write (num) and know what it does to get the most intuitive behaviour
07:27Licenserand to work around stupid static typing
07:27AWizzArdThe intuitive behaviour is just a thing we can get used to.
07:27LicenserAWizzArd: it is not a problem for you or me since we have disucssed this and understand the workings
07:27AWizzArdAfter a few rounds we will understand that such things need to get constructed specifically.
07:28AWizzArdI also don't mind having to write (File. "/my/path")
07:28Licenserbut 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?
07:28AWizzArdvs f"/my/path"
07:28Licenserthe problem is the special behavior of loop that it acts differently then other things
07:28AWizzArdBeing dynamically typed means that there is not edit->compile->run cycle anymore, and that you have an administrative system
07:29AWizzArdDynamically typing is not about being able to say x=15 ... x="Hi"
07:29Licenserdynamic typing has to do with typing not with build cycle
07:29Licensera language being dynamic has to be with the build cycle
07:29AWizzArdBeing 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
07:29AWizzArdonly in some cases for let it is useful
07:30AWizzArdto increase readability
07:30AWizzArdA dynamic typed language is more like a OS that you can administer
07:30AWizzArdYou don't need to decide which programs you want to run, in which order, before your start your computer
07:30Licenserdynamically typed functions means that you can write (inc 1) and (inc 1.0) without having to write a gazillion of inc methods
07:30AWizzArdwhile it is running you can change the system, install new programs, create files, and such
07:30AWizzArdno
07:31Licenseryes
07:31AWizzArdNope sorry, this is not an enforced feature.
07:31Licenserhttp://de.wikipedia.org/wiki/Dynamic_typing
07:31AWizzArdDynamically typed is being able to say: (defn foo [] (println "Helo")) and then a minute later (defn foo [] (println "Hello"))
07:32AWizzArdBeing able to say (defn foo...) in the first place is already dynamic typing
07:32Licenserno that is dynamic not dynamic typed
07:32AWizzArdIn a statically typed program I can't because I write the program before I run it.
07:32Licenserand you can do that in C too you know?
07:32AWizzArdIn Clojure I first run my program, then write it.
07:32Licenserthat has nothing to do with dynamic typing
07:32AWizzArdIn C I can do it when I engage a dynamic typing style of programming
07:33LicenserAWizzArd: please look at the link
07:33AWizzArdNo need, i know pretty well what i am talking about.
07:34Licenserno :P
07:34AWizzArdcorrect calculations of numbers is typically a feature in dynamically typed languages. It is not required that I don't need to construct them specifically.
07:34AWizzArdLicenser: I can edit that website to state whatever I want.
07:34AWizzArdIn Clojure I have to construct File objects to work with them correctly.
07:35AWizzArdAnd I have to construct generic numbers explicitly from now on.
07:35AWizzArdNo big deal, it is only a few keystrokes away and only in rare cases needed.
07:36AWizzArdAs long the compiler warns me about this everything is fine.
07:36AWizzArdIf Clojure were statically typed it would mean that I can not change foo at runtime anymore
07:36LicenserAWizzArd: it makes the language more complex and confusing it goes away from the elegant and simple things
07:36AWizzArdThis could be the case.
07:36AWizzArdI don't want to argue against such statement.
07:37AWizzArdWe will have to see how much production code is affected by this.
07:37AWizzArdI will recompile my sources and check how many warnings get generated.
07:37LicenserAWizzArd: but agian to typing C is statically typed but I can very well change the value later in the code
07:38AWizzArdI don't know if most C compilers are really statically type checking the code.
07:38AWizzArdBut right now I don't see how you can typically start the C repl, then write a program (a function) and run it.
07:38AWizzArdThere can be a C repl of course, I just don't know if this is the way how C programs get written in practice
07:39clojurebotclojure euler is http://clojure-euler.wikispaces.com/
07:39Licenserwell in c.c you get 3 warnings
07:39AWizzArdI see.
07:40AWizzArdCan they get fixed?
07:41djpowelli 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
07:41Licenserdjpowell: 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
07:42djpowellI'm not too worried, this is just an experiment, not the downfall of clojure
07:42AWizzArdThat'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.
07:43LicenserAWizzArd: http://gist.github.com/444827
07:43Licenserthis is one of the things
07:43AWizzArdI 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
07:43LicenserAWizzArd: we're all going to die!!!
07:43AWizzArdlet me see
07:44AWizzArdWhat is the problem with that code?
07:44LicenserI love longs and doubles but I'd like to have to tell the compiler when I need this speed improvement
07:44AWizzArdDoes it produce no warnings and at the same times produces incorrect results?
07:44Licensermath.clj:112 recur arg for primitive local: y is not matching primitive, had: java.lang.Number, needed: long
07:44Licenseryou could write y (num 1)
07:44Licenserbut that'd be silly
07:44AWizzArdTwo conditions must be true at the same time for this new feature to suck: it must compile code without warnings *and* run incorrectly
07:45AWizzArdIf one of two conditions is not met it is fine.
07:45AWizzArd(num 1) won't kill us
07:45djpowelli'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.
07:45AWizzArdthis is just one little function
07:45AWizzArdIt is mostly a psychological issue, not a technical one I guess.
07:46LicenserI find +' being for primitives good +' for num's not so good
07:46AWizzArdIn the end I really don't care much if both are available.
07:46LicenserAWizzArd: 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
07:47LicenserI tell you, if that had been the case when I started clojure I'd not be here today
07:47AWizzArdYes, they are important. The reason why I use Clojure is mostly psychological of course.
07:47djpowellLicenser: if what was the case?
07:47AWizzArdIf I were not human and evolved to be a really good programmer, then I can just write assembler code.
07:47Licenserbecause my impression would have been 'what a bunch of whiredos that force you to jump through hoops for simple code'
07:47Licenserthat I'd need to know about +' *' and (num 1) to do the project euler stuff
07:48djpowellLicenser: the inference of the type of the loop variable? Or the more general changes with non-promoting arithmetic
07:48AWizzArdWell, adding (num) at 3 places of a 6k LOC program is not really bad, especially when the compiler tells us the exact line numbers (:
07:48LicenserAWizzArd: no BUT if it is amongst the first things you see about a language it is a very bad thing
07:48AWizzArdThe Euler code is not representative for typical production code.
07:48djpowellit is the sort of incidental complexity that clojure mostly strives to avoid
07:49Licenseradding (long 3) in 10 places where you know speed is ain issue in 6k LOC isn't a problem either
07:49LicenserAWizzArd: but it is what people see first
07:49AWizzArdMay 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.
07:49LicenserFor my projects I really don't care for this I care for clojure in general and a first impression
07:49LicenserAWizzArd: in the long run it is
07:50djpowellI 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
07:50AWizzArdIf Clojure were to remove the GC or the repl, then *that* would piss me off.
07:50Licensersince 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
07:50Licenserdjpowell: yap exactly that would be great
07:51LicenserI love if you could do all the stuff in the equal branch but would not HAVE to
07:51AWizzArddjpowell: it may that way, defaulting to more correct code and specifying that we want it faster
07:51djpowellliterals 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
07:51AWizzArdThat would be okay for me personally, as well as defaulting to fast code *plus* compile-time warnings
07:52LicenserAWizzArd: there isn't nessesarily a hard destinction between compile time and run time
07:52AWizzArdLicenser: does 1n already work in your branch?
07:52Licenser1n yes gibes me a big int
07:52AWizzArdand (num 1)?
07:52Licenserbut again it is added complexity
07:52Licenseryes that too
07:52AWizzArdk
07:52Licensersimple problems should be solved with simple code
07:53AWizzArdI agree that it increases the complexity.
07:53AWizzArdAnd I think we all agree that it increases efficiency too.
07:53Licenseryes it does
07:54Licensernot efficiency but performance actually
07:54Licenserit decreasees efficiency in my eyes
07:55AWizzArdWell, I was implying: efficiency = run time performance
07:56Licenserokay I would see efficiency as how effecticient you can write code
07:56mmarczykah, just sent another reply to the ggroup thread...
07:56AWizzArdThat I call productivity
07:57mmarczykI have to say I'm pretty happy with the equal as it stands, but I'd prefer autobox-or-hint
07:57Licenserthe other is called performance :P but again we're bickering about words, we know what we mean, yes it increases performance but decreases productivity
07:57AWizzArdI don't say it decreases productivity
07:57AWizzArdbecause I don't measure productivity in mere seconds
07:58AWizzArdBut in increases the complexity.
07:58Licenseras I do, and this increases complexity
07:58AWizzArdProductivity comes through more important features, not because I have to type (File. "path") instead of f"path"
07:58AWizzArdThat is no productivity win
07:58AWizzArdBut having a GC is
07:58AWizzArdbeing able to write functional code is
07:58LicenserAWizzArd: it is not about having to call some method bot about intuition
07:58AWizzArdhaving fully persistent datastructures is
07:59LicenserFile. is perfectly explaind and intuitive by the very basic of clojures concept
07:59mmarczykAWizzArd: 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?
07:59Licenserthe behaviour of loo not
07:59mmarczyk^surely.
08:00AWizzArdI 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.
08:00LicenserI don't ;P
08:00AWizzArdWe have some training, and from that perspective plus my years of CL background it is indeed against my personal "intuition"
08:00mmarczyk:-)
08:00AWizzArdWhere "intuition" means "my personal training"
08:01AWizzArdIf I were taught that it is normal to work that way in programming I would be surprised how unintuitive Python programs are
08:01silveenTry writing software in english, if your native language was lojban, perhaps programming would be more natural
08:01LicenserAWizzArd: no it does not, the most intuitive thing is that the simplest possbile code is the correct one
08:01mmarczykin order to expect that 1243590283469103468 + 132478619034851734208671 equals something big you need, what, grade school training?
08:01mmarczykwhereas 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
08:02mmarczykah, actually no danger of wraparound here... but same goes for exceptions
08:02AWizzArdI am now an experienced professional, and this whole issue really does not affect me.
08:02LicenserAWizzArd: again it does in the long run
08:02AWizzArdI see how it affects newbies, and egoistic as I am, I don't care about them ;-)
08:02LicenserAWizzArd: you should because they might be your feature employees or employers
08:02AWizzArdPeople are only the shortest amount of time in the state of being a newbie in their programmieng carrier.
08:03Licenserthe one thing for a language to stand on the market is to have many people using it or we end up as CL :P
08:03mmarczykand that's precisely when they make some of the most important choices
08:03mmarczykmost of which they cannot possibly make in an educated way at that stage
08:03AWizzArdLicenser: as colleagues I would try to hire pros such as you, not newbies.
08:03LicenserAWizzArd: but this might be one of the most important ones
08:03LicenserAWizzArd: 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
08:04Licensermeaning there might not be a next Licenser
08:04AWizzArdwe all were newbies
08:04Licenserof cause there won't be ever another Licenser but that is a different matter :P
08:04AWizzArdWe will have to see and wait.
08:04AWizzArdhehe!
08:04AWizzArdyup
08:04Licenserbut we can either work into this direction or work towards the direction of having many new happy Licenser's
08:04Licenserthat is a decision we can and have to make
08:04AWizzArdEspecially one wit this crazy-professor kind of hairstyle :p
08:05Licenser:P
08:05Licensersadly 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
08:05AWizzArdI care more about having a language that is oriented on programming experts, not newbies
08:06AWizzArdThe featuresets are often mutually exclusive
08:06LicenserAWizzArd: but this isn't the problem we're facing
08:06Licenserkeeping the default case 'newbie friendly' won't change anything for the experts
08:06AWizzArdok, I can agree with that
08:06Licenserwe 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
08:07Licenserand 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
08:07AWizzArdSee, 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.
08:08AWizzArdWell, 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
08:08LicenserI 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
08:09LicenserAWizzArd: yes that'd be my dream
08:09AWizzArdThe 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.
08:09Licenserheh
08:09AWizzArdBut this is still 10-20 years in the future.
08:09Licenserthat'd be annoying kind of trust me I wrote a proram that did kind of that
08:09AWizzArdWell, at that point there will be not many programmers anymore.
08:09Licensernot for compiling code but compiling configurations but it turned out to be very annoying
08:09AWizzArdIt's a dying profession :)
08:09LicenserAWizzArd: nonsense
08:10Licensergenius never die out :P
08:10Licenserno computer will ever have my brilliant ideas :P
08:10OForeroHello
08:10AWizzArdI see
08:10AWizzArdHey OForero
08:10OForeroI am stuck at something
08:10AWizzArdWie geht es dir? ;)
08:10OForerohttp://paste.pocoo.org/show/227239/
08:10Licenser:P
08:10OForerosehr gut danke
08:10OForeround selber?
08:11OForeroobwohl Clojure macht mich gerade fertig ... :-(
08:11AWizzArdI am fine too, thanks
08:11AWizzArdBetter let's switch back to english. But there is also a #Clojure.de
08:12OForeromy written german is not fluent :-(
08:12OForeroI think I hit the limits of the simulation ... or something
08:15AWizzArdOForero: your use of (get x 0) and (get x 1) is confusing
08:15AWizzArdbetter would be to say (key x) and (val x)
08:16AWizzArdor at least (first x) and (second x)
08:16AWizzArdyour prepare fn could also use destructuring
08:16AWizzArd(defn prepare [[name value]] ...)
08:17AWizzArd(defn prepare [[name value]] `(def ~name ~value))
08:17AWizzArdsomething like that would be easier to read
08:18Licenser*nods*
08:22djpowellI 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
08:28rbarraud;
08:29AWizzArdwb Lice
08:29Licenserthanks
08:35mmarczykdjpowell: didn't you mean that the promoting ops should be *non*-primed...?
08:35mmarczyk(that's re: the ggroup post)
08:35djpowelloh yeah that
08:35mmarczykright, agreed in that case
08:35mmarczykthough mostly I think you should need the primes only if you need the hints
08:36mmarczyk(surely if you hint you also know where to prime? ;-))
08:37djpowellwell not necessarily
08:37djpowellprimed ops are polymorphic
08:37djpowellhinted ones aren't
08:37djpoweller, i think...
08:40djpowelli'm not entirely sure anyway to be honest
08:41mmarczyknot sure if you're referring to the current state of affairs or to the desired state of affairs?
08:41mmarczykmy point is that whatever should be the default should not be primed
08:41djpowellwhat do you mean by default?
08:42mmarczyk"use that unless you actually know you need the other one"
08:43OForeroAWizzArd: thanks for the tips
08:44OForeroI will use those
08:44OForerobut the problem is that the record type is lost in the binding when using the function
08:44AWizzArdAnd that I find surprising too.
08:45OForerothe macro work, but I am not able to use it in a map operation
08:45OForeroI think I will mail it to the list
08:46LicenserI'm not sure if you can use macros in maps
08:46AWizzArdOForero: (first (map prepare data)) ==> (def rec #:user.Record{:a 1, :b 2, :c 3})
08:47AWizzArd(nth *1 2) ==> #:user.Record{:a 1, :b 2, :c 3}
08:47AWizzArd(eval *1) ==> {:a 1, :b 2, :c 3}
08:48AWizzArd(eval (Record. 10 20 30)) ==> {:a 10, :b 20, :c 30}
08:48AWizzArdand not #:user.Record{:a 10, :b 20, :c 30}
08:48AWizzArdRecords don't eval to themselves, they eval to maps
08:48AWizzArdThat is the issue here.
08:49OForerook
08:49OForerothat will explain why the macro works
08:49AWizzArdyes
08:49OForerobecause it does not eval the parameters at input
08:50OForeroI kind of think records shouldn't forget their recordness
08:50mmarczykooh, that's a cool bit of knowledge on records
08:50OForeroI will post it to the group and see what reactions are there
08:51AWizzArdk
08:52AWizzArdThere we have this intuition thing again :)
08:55AWizzArdGood morning rhickey.
08:56OForeroI am bias ... because I still like types
08:56Licenserrhickey my favourte victom for code suggestions, how are you today?
08:56OForeroand kind of think that loosing type information is bad
08:56OForero(that is why I do not like erasure)
08:58AWizzArdIt is strange how records eval to maps when evaled 'twice'
08:59mmarczyktwice?
08:59OForeroI have to go and hunt
08:59OForeroI'll check later about this again ...
08:59OForeroAWizzArd: thanks for finding the reason
09:00Licenser(eval #:user.Record{:a 1, :b 2, :c 3})
09:00Licenser,(eval #:user.Record{:a 1, :b 2, :c 3})
09:00clojurebotNo dispatch macro for: :
09:00OForeroone more lesson ....
09:00Licenser,(eval '#:user.Record{:a 1, :b 2, :c 3})
09:00clojurebotNo dispatch macro for: :
09:01mmarczykLicenser: records are not readable...
09:01mmarczykalso, I think clojurebot uses 1.1
09:01hiredman,*clojure-version*
09:01clojurebot{:interim true, :major 1, :minor 2, :incremental 0, :qualifier "master"}
09:01mmarczykoh, forgive me, clojurebot
09:02mmarczykI didn't quite realise how new & shiny your circuits were :-)
09:02Licensermmarczyk: was just trying something out :)
09:03AWizzArdmmarczyk: sorry, forget this twice thing, I was wrong
09:03mmarczykOForero: well actually
09:03mmarczykOForero: the reason your code doesn't work is that prepare-2 sees %
09:04mmarczykOForero: the symbol, I mean...
09:04AWizzArd,'%
09:04clojurebot%
09:05mmarczykso 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
09:05mmarczykbefore breaking
09:05mmarczykmaking it apparent what's going on.
09:07OForerook ... I will try that
09:09AWizzArdyou can also call macroexpand-x on your macro call to test them
09:10mmarczykeffectively you'd like the macro to receive the argument *evaluated* -- which is contrary to the point of macros -- just use a function instead
09:10OForeromacro expand does not work here
09:10AWizzArd,(macroexpand-x '(when 1 2))
09:10clojurebotjava.lang.Exception: Unable to resolve symbol: macroexpand-x in this context
09:10OForerobecause the macro works
09:10OForeroit fails when used in the collection
09:10mmarczykit doesn't fail when used "in the collection"
09:10AWizzArduhm, 1, not x
09:10AWizzArd,(macroexpand-1 '(when 1 2))
09:10clojurebot(if 1 (do 2))
09:10mmarczykit fails because you use it as (prepare-2 %)
09:11mmarczykthe % gets turned into a gensym -- a one-off symbol -- by the #(...) syntax
09:11mmarczykso effectively it gets a symbol
09:11mmarczykbut that symbol names a local, namely the sole parameter to the anonymous function
09:11mmarczykand you can't eval that
09:11OForerommarczyk: I was using a function ... but it has the amnesia problem
09:12mmarczykLicenser: hey, let Rich answer the previous batch of e-mails! :-)
09:12Licensermmarczyk: :P psst I just had a new idea let me toss it in°
09:13mmarczykLicenser: but more importantly, I'm afraid the suggestion was that that's not easy... dunno myself though
09:13Licenserif this is possible it would be a actuall good compromise
09:13Licenserwell I admit I'm not sure how loop is implemented
09:13mmarczykOForero: amnesia?
09:13OForeroif you check the pastie
09:13mmarczykI have
09:14OForerothe first thing I attempted was with a function
09:14mmarczykright
09:14OForerobut because Records evaluate to maps
09:14OForerothen the type is lost
09:14mmarczykI think you might need to do (import example.Record)
09:14OForeroand I need the type because if not I can not call the protocol on it
09:14mmarczykwhich I promise I only thought about now
09:15mmarczykgive it a go maybe? :-)
09:15OForerook ... I will try that
09:15mmarczykyup, works for me
09:15mmarczyksome JVM leaking through the Clojure abstraction, I'm afraid
09:15OForeronop
09:16OForeroreally?
09:16OForerommh
09:16OForeroI reload the file then
09:16mmarczykyeah, try a fresh repl... I will too
09:17mmarczykoh, I see, hm
09:19OForeronope
09:19OForerothe record lost its type ... also after the import
09:19mmarczykand what would you like to happen? for rec to hold your record?
09:19OForeroyes ...
09:20OForeroI am working in a sort of dsl
09:20AWizzArdMaybe you need to AOT it?
09:20OForeroand I pass a map with records and functions
09:20mmarczykuse intern maybe
09:20OForerobut there are some functions that I declared in protocols
09:20OForeroand those require the type to work
09:21AWizzArdWell, I would also expect that class instances evaluate to themselves
09:21OForeroAOT?
09:21clojurebotAOT genclass is http://paste.lisp.org/display/70665 and http://clojure-log.n01se.net/date/2008-11-18.html#14:19
09:21AWizzArdI would be surprised if (eval (File. "")) would not result in .. a file
09:21mmarczyk,(doc intern)
09:21clojurebotDENIED
09:21mmarczykah, well
09:21mmarczykOForero: you can use intern instead of def
09:21AWizzArdOForero: you call (compile-file 'on-your-namespace)
09:21mmarczykit's a function which will create your Var for you
09:21mmarczykthen you don't have to use macros at all
09:21mmarczykbut, on a related note, your multimethod doesn't work for me
09:22OForerointern? ...
09:22OForerowhat is the problem?
09:22mmarczykahh, sorry, it does work, my bad :-P
09:22OForero(prepare-2 (first data)) works
09:22mmarczykwell
09:22mmarczykyou can write binder as
09:23mmarczyk(defn binder [x] (intern *ns* (toSymbol-2 (get x 0)) (get x 1)))
09:23mmarczykthen it's a function and you can map it over a collection
09:23mmarczykand if I understand you correctly, it does what you want
09:23OForerook ... that will replace the prepare
09:23OForeroyes
09:23OForerolet me try that
09:24mmarczyk(binder (first data))
09:25OForeroyep
09:25OForerothat work in the example
09:26OForeroI have to plug it into my code and see if that works ...
09:26mmarczyk(defn binder [xs] (doseq [x xs] (intern *ns* (toSymbol-2 (get x 0)) (get x 1))))
09:26OForerothanks for the training session
09:27mmarczyk:-)
09:27OForeroyou think doseq is more idiomatic because of the side effects?
09:27mmarczykdoseq *works* with side effects :-)
09:27mmarczykmap would have to be forced with dorun, say
09:27OForeroI know ... the question was if the creation of the vars is a side effect
09:28OForerobecause it works with map
09:28mmarczykwell, yes, it is
09:28mmarczykit might work at the repl
09:28OForerofine
09:28mmarczykbut depending on where you put it in your code
09:28OForeroyour are right .... I have to remember that
09:28mmarczykright
09:29OForeroin the absence of a type system ... it is very good to have a helpful community
09:29OForero:-)
09:30mmarczyk:-)
09:31mmarczykeval-on-a-record remains funky
09:32mmarczykrhickey: do records evaluate to maps by design?
09:34rhickeymmarczyk: what does 'evaluate to maps' mean?
09:34mmarczyk(class (eval some-record))
09:35mmarczykgives me clojure.lang.PersistentArrayMap for some record I'm using
09:35AWizzArdrhickey: (defrecord Foo [a b]) ... (eval (Foo. 10 20)) ==> {:a 10, :b 20}
09:37rhickeyah, no, could you please make a ticket for that?
09:38mmarczykAWizzArd: your discovery :-)
09:39AWizzArdk
09:39mmarczykalright, going off for now... bbl
09:40OForerothanks guys
09:41OForeroAWizzArd: can you ping me the ticket number?
09:41OForeroI will put it in my document ... and of course reference you
09:41OForerommarczyk: thanks ... it does works in my main code
09:42OForeroand it is shorter
09:46AWizzArdOForero: http://bit.ly/bAq5DX
10:12AWizzArdWhat is the best way to find out if a given object is an instance of some record?
10:23djpowellAWizzArd: will (instance? MyRecord x) do?
10:24djpowelltho, if you're doing instance tests, then perhaps you should be using some sort of polymorphism instead?
10:24AWizzArddjpowell: I want to write a serializer
10:25AWizzArdbut non-AOT'ed records can not be serialized by using the jvm mechanism
10:25AWizzArdso I need to identify those, them all
10:25AWizzArdnot just a specific one
10:25AWizzArd(record? foo) I need
10:25AWizzArdand/or (deftype? foo)
10:26djpowellI don't think there is a way at the moment
10:27AWizzArdYesterday hoeck suggested something about having a look at the classloader
10:29djpowelldon't do this :) - (.startsWith (pr-str p) "#:")
10:29AWizzArdwould be cool though if all deftypes and records implemented one (possibly empty) interface that allows me to identify them
10:30AWizzArddjpowell: great, this seems to be the best solution :p
10:30djpowellI imagine that records will get a readable representation soon enough
10:32AWizzArdtoo slow
10:32AWizzArdThat does not scale
10:57rustemsunievis 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:02AWizzArdrustemsuniev: that is basically okay, but you could use destructuring (fn [{:keys [x y]}] (and (= x 1) (= y 3)))
11:02Leafwquestion: if clojure.parallel is deprecated, what replaces it?
11:02rustemsunievAWizzArd: Thanks!
11:03dnolen,(some #(when (= (map % [:x :y]) [1 3]) %) [{:x 1 :y 1} {:x 1 :y 2} {:x 1 :y 3}])
11:03clojurebot{:x 1, :y 3}
11:08rustemsunievdnolen: Cheers! :)
11:11Leafwsorry, I'd appreciate help understanding if there is a new clojure.parallel package, since the old one has been marked as deprecated.
11:25OForeroAWizzArd: thanks ... I'll go back to my shores ...
11:29djpowellLeafw: the old clojure.par required the ParallelArray classes from a version of jsr166y which isn't going into Java 7
11:30djpowell(or is that clojure.parallel)
11:31djpowellanyway, 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:31djpowellbut, 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:32djpowellthere is still pmap in core, if you just need a parallel map...
11:32djpowellthe par branch hasn't been updated in a while tho
11:34djpowellI don't think there would be a problem using the deprecated parallel stuff in the meantime
11:55Leafw,(def a 6)
11:55clojurebotDENIED
11:56Leafw,(let [a 6 a2 (with-meta a {:test #(if (< % 10) (throw (Exception. "< 10!")))}] (test a))
11:56clojurebotUnmatched delimiter: ]
11:57Leafw,(let [a 6 a2 (with-meta a {:test #(if (< % 10) (throw (Exception. "< 10!")))})] (test a))
11:57clojurebotjava.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IObj
11:57Leafwhum anybody could explain what is wrong with that with-meta declaration?
11:59Leafwdjpowell: thanks for the par explanations. So it's all in the par branch.
12:05Leafw,(clojure.set/intersection (keys {2 "two" 4 "four"}) #{2 3})
12:05clojurebotjava.lang.ClassCastException: clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentSet
12:05Leafwthat I don't understand either
12:06Leafwhow come KeySeq doesn't implement IPersistentSet ?
12:06ubolontonIn the let form a is not a var
12:07ubolontonIt is literally 6 there
12:07ubolontonSo it's (with-meta 6 ...)
12:07Leafwubolonton: ok, but with (def a 6) and (def a (with-meta ....)) same problem, ubolonton
12:12hoeckLeafw: numbers cannot have metadata
12:14Leafw(def a 6), a is a var, not a number
12:14Leafwit evaluates to a number, but that is different.
12:14hoeckbut a resolves to a number
12:14ubolontonYes it is evaluated before be passed to with-meta
12:14Leafwso how can one give the var a its meta data ?
12:14ubolontonwith-meta is a function not a macro
12:14ubolonton(with-meta 'a ...)
12:14LeafwI see. So one needs (with-meta (var a) {}) ...
12:15Leafwoh. ok.
12:15Leafwunevaluated a ... gets its meta map. thanks
12:16Leafwand 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:16hoeckLeafw: but metadata on vars is not settable
12:17Leafwhoeck: yes I know, its (def a (with-meta ...
12:17hoeckno, with-meta doesn't work on vars
12:18hoeckjust found that out :P
12:18Leafwhoeck: I am not sure I understaht what you mean. with-meta returns a var, doesn't it?
12:19hoeckwith-meta returns a new object with the attached metadata
12:19Leafwsure. That 'object' is a var
12:19hoeckbut only if that object implements the IObj interface, and a var doesn't
12:19Leafwhum, no, it returns a Symbol, sorry
12:19Leafwbuf
12:20Leafwdud, I am confused. What is the proper usage of with-meta and :test and (test ...) ?
12:21hoeckyou specify the :test function in the defn
12:22hoeckand to alter a vars metadata, you use alter-meta
12:22Leafwdefn? I see. One cannot test a var then? What is the use of testing a function?
12:22hoeckor def of course :)
12:22hoeck,(doc def)
12:22clojurebotDENIED
12:23Leafwalter-meta doesn't exist, hoeck
12:23hoecksorry, its alter-meta!
12:24hoeck,(doc alter-meta!)
12:24clojurebot"([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:25LeafwI see, !
12:25hoeckbecause it mutates sth.
12:25Leafwright
12:26hoecknow I understand what you're trying to do, using test to check the contents of a var
12:26Leafwyes :)
12:28hoeck(def #^{:test (fn [] 1)} foo 1)
12:29hoecknote that the new metadata syntax uses ^ instead of #^
12:29hoeckand then invoke the test with (test #'foo)
12:30Leafwbut the test function is now aware of the value of foo
12:30Leafwso of what use is it?
12:30hoeckthat was just an example test function
12:30Leafwyes I understand :)
12:30Leafwbut I tried giving the test fn an arg, and then that fails
12:31Leafw(test #'foo) would return :no-test
12:31Leafwit's (test foo), I think
12:31hoeck(declare a) (def #^{:test fn-using-a} a 1)
12:32LeafwI 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:32hoeckas its a var, you can just use it in the test function like any other vars
12:33hoeckthough you have to declare that var first, because the test-function will be evaled before the def
12:35Leafwhoeck: that actually fails
12:35Leafw(def a 6)
12:35Leafw(def a (with-meta 'a {:test #(if (< a 10) (throw (Exception. "Value under 10!")))}))
12:35Leafw(test a)
12:35Leafwjava.lang.ClassCastException: clojure.lang.Symbol cannot be cast to java.lang.Number
12:35Leafwso "a" is not visible, or is read in a way that I don't udnerstand.
12:37hoeckhttp://gist.github.com/445036
12:38Leafwso declare works but def doesn't :)
12:38Leafwnow that is yet another source of confusion
12:39hoeckno, you're defining the var "a" to be the symbol "a" with the attached :test metadata
12:40kirashi
12:40hoeckand 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:40hoeckLeafw: (test a) basically uses ((:test (meta a)))
12:41kirasi have a question that is turning into a book... how many lines should i post at once?
12:41LeafwI must say this is not as clear as I think it is.
12:41Leafwkiras: post a gist at github
12:41kirasLeafw: ok, ty
12:41Leafwhoeck: but thanks for the explnation. I am reading it like a 12 times
12:41hoeckthe key point is understanding vars
12:42hoeckwhenever you do (def a 1), you define a var
12:42hoeckwhen you evaluate `a' on the repl, you get the contents of that var
12:43Leafwyes, so much I get it
12:43hoeckso (meta a) gets the metadata of the object _inside_ the var
12:44Leafwso the var contains a symbol and a value, is that right
12:44Leafwand the var itself has a meta map.
12:44hoeckno, the var only contains that value
12:44Leafwso what links the symbol and the value?
12:45hoeckthe mapping of names to var-objects is done by the clojure runtime, I guess
12:45Leafwso a symbol has a meta map then? Or is it the var, which contains the symbol, that has the meta map?
12:46Leafwsorry, that second part is clearly wrong: I meant Or is it the var, which contains the symbol, that has the meta map?
12:46LeafwxD
12:46Leafws/symbol/value
12:46hoeckthe var has a meta-map
12:47Leafwok
12:47Leafwand also the value object.
12:47hoeckand the value can have metamap too, if its a symbol
12:47hoeckright
12:47Leafwsure, rabitt hole all the way deep
12:47hoeckbut not if the value object is a number, because numbers do not implement metadata
12:47Leafwmakes sense
12:47Leafwby the way
12:47hoeckor keywords do also not implement metadata
12:48hoeckright, and back to your initial problem
12:49hoeck(def #^{:a 1} foo 1) adds {:a 1} as metadata to the to-be-created var `foo'
12:50Leafwthe (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:50hoeckexactly
12:50LeafwI think I am getting it. Thanks hoeck
12:50hoecknp :)
12:51LeafwI knew about #^{} in def. You mentioned though that now it is being changed to ^ alone, without # ?
12:52Leafwand 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:53hoeckwell, its just a plain pointer in the vap object, and gets out of the way pretty easily
12:53hoeckbut it offers great capabilities, each var object for instance as :line and :file metadata
12:55Leafwindeed most values in clojure end up not in vars but in a let or as members of a collection.
12:55hoeckand with the upcoming ^:static flag, there is enough room to improve performance where needed
13:00Leafwhoeck: what does the ^:static do?
13:00hoeckLeafw: on recent clojure snapshots, ^ is used as a reader-macro for metadata, its less visually disturbing than #^, I beleive #^ will be marked deprecated
13:00LeafwI see, both #^ and ^ work, currently.
13:01hoeckof course, they will work both for a while
13:01Leafw^ used to mean something else thoguh
13:01Leafwbut I forgot what it was.
13:01hoeckit was for accessing metadata?
13:01hoeck^:static indicates, that a function can be compiled as a method
13:02hoeckit will then loose its closure-property, but can take primitive args and will be less dynamic
13:03hoeckcode using ^:static functions has to be reevaluted to call new versions of the static functions
13:03LeafwI see. So it throws one back to the java world.
13:03Leafwboth for the good and the bad :)
13:04LeafwI can see a use for numerical operations with clojure, adding the ^:static once all works fine.
13:04rhickeyLeafw: 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:05Leafwrhickey: true. The "bad" is much less so.
13:05rhickeyLeafw: it's more like the macro experience
13:05Leafwmacros aren't closures either, is that what you mean?
13:06rhickeyLeafw: seeing a change to a macro requires re-evaluation of client code
13:06Leafwevery advice out there suggest not using macros, and I have found it the hardest to teach others.
13:06Leafwrhickey: I understand. The macro got compiled and is aware only of what was declared when it was compiled.
13:07Leafwrhickey: clojure.parallel is marked as deprecated in clojure.org. What will clojure 1.2 come with?
13:07rhickeyno, the caller of a macro embeds its current definition, and won't use a new definition until it (the caller) is recompiled
13:08Leafwre-reading that ... I think I understood. Thanks.
13:09Leafwby the way rhickey , clojure code made it into a J Neuroscience paper. Made my life easier and works great.
13:09rhickeyLeafw: cool! - got a pointer?
13:10serp_(using emacs and swank): how do I compile a buffer the second time without getting errors about stuff already existing?
13:11Leafwhttp://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:12kirassome questions i have: http://gist.github.com/445066
13:13Leafwrhickey: in the materials ad methods I acknowledge clojure as the language used.
13:15Leafwthe other major clojure fiel used is here: http://repo.or.cz/w/trakem2.git/blob/HEAD:/lineage/identify.clj
13:23hoeckkiras: 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:23hoeckkiras: but im no lein expert, not shure how lein handles that
13:23hoeckclojure of course allows dashes or underscores, its just not good style to create a my_name_space
13:23kirashoeck: thanks. i knew that in lisp dashes were used instead, but i am confused by the way lein is doing this.
13:24kirashoeck: 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:24hoeckin clojure, if you declare a dashed-name.space-test , its files must reside in the classpath at dashed_name/space_test.clj
13:25kirasright
13:25kirasi'm just saying, it would be bad to use lein new test-project as it currently works
13:25kirasbecause all the files/directories will be named with dashes
13:25kirasusing lein new test_project will name the files/directories correctly
13:26hoeckkiras: lein is pretty young though, so it may have its rough edges
13:26kirasbut then in the actual code, you get (defproject test_project) and (ns test_project.core)
13:26hoeckthen simply use the lein test_project and replace the underscores in the generated files
13:26kirashoeck: ok, i was trying to figure out if that was the right way to do things or not
13:27hoeckno, lein should definitively care about that
13:27kirashoeck: i worked through the programming clojure book, but i haven't done any real clojure projects yet, just playing around at the repl
13:27hoeckbut I'm not an active lein user anyways, have you used the latest version?
13:27kirashoeck: so i was a little bit unsure of whether i was right or not
13:28kirashoeck: i believe this is the latest, i can check
13:28kirasheh
13:30kirashoeck: 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:32hoeckkiras: of course, I guess its best to post sth on the mailinglist
13:32kirashoeck: the clojure mailing list?
13:33hoeckkiras: http://github.com/technomancy/leiningen
13:33hoeckin the readme under "hacking" are some links to the mailing list and the issues section
13:34hoeckbut I haven't found a dash/underscore issue there
13:34kirasah, thanks
13:34kiraswell, it seems that i'm using 1.1.0 and there is a 1.2.0-RC1 available
13:35kirasmaybe i should try that
13:35hoeckof course! :)
13:35kirasheh
13:36kirasthanks for the help. i'm going to see if that works better.
13:44dnolenrhickey: with the latest changes should I be seeing a per regression around amap/areduce?
13:44dnolens/per/perf
13:45rhickeydnolen: no, got a gist?
13:49dnolenrhickey: 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:49rhickeydnolen: if you are on the latest, you shouldn't be using +'
13:49dnolenrhickey: heh, things are moving quickly, missed that.
13:50rhickeydnolen: do a (doc +)
13:51rhickeydnolen: also refresh: https://www.assembla.com/wiki/show/b4-TTcvBSr3RAZeJe5aVNr/Enhanced_Primitive_Support
13:52rhickeydnolen: did you miss: http://groups.google.com/group/clojure/msg/9d13452a01048646
13:54dnolenrhickey: thx
13:56dnolenrhickey: wow, am i correct in seeing that gives map like an order of magnitude speedup?
13:56dnolenrhickey: sorry i mean reduce I think, or is that because internal reduce got re-enabled?
13:58rhickeydnolen: dunno what you are comparing
14:08mmarczykah, cl-format in contrib breaks down with current equal :-(
14:09mmarczyk"had: Object, needed: long"
14:09mmarczyk(grep for last_pos)
14:10dnolenrhickey: 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:11Blackfootif 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:13rhickeymmarczyk: get latest contrib
14:13mmarczykrhickey: oh... ok, pulling now, thanks
14:23ChousukeBlackfoot: (str form) :P
14:23ChousukeBlackfoot: or pr-str
14:24Blackfoothttp://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:26edbondspend 30min looking how to write 1.2.0 version in leiningen, help please
14:26Blackfootoh i think i see why that's not working, the forms are being run in the binding
14:27edbondorg.clojure/clojure "1.2.0-SNAPSHOT" ?
14:27serp_org.clojure/clojure "1.2.0-master-SNAPSHOT"]
14:28edbondserp_: thanks
14:30rustemsunievIs there any way to clean a *board* after test is executed? (defn boards-fixture [f] (binding [board (load-board 2 2)] (f)))
14:34mmarczykBlackfoot: why not just ~forms instead of (list ~@forms) ?
14:35mmarczykactually ~(map (fn [f] `'~f) forms), I guess
14:35Blackfootmmarczyk: that had an error in an earlier iteration iteration. ok, trying that now
14:36mmarczykBlackfoot: (defmacro pf [& fs] `(doseq [f# '~(map (fn [f] `'~f) fs)] (println f#)))
14:37mmarczyknote the extra quote before ~(map ... too
14:38mmarczykBlackfoot: actually (defmacro pf [& fs] `(doseq [f# '~fs] (println f#))) matches your spec
14:38mmarczykthe other one prints (quote (inc 1)), this one prints (inc 1)
14:39mmarczykmixed things up in the first approach, my bad :-)
14:40Blackfootno problem, less mixed up than me :) yea, sounds like i should not have spliced them
14:42mmarczykI'm off for now, bbl
14:45Blackfootthanks mmarczyk. next step is to actually show the result of running the form
15:29qbgrhickey: 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:50qbgdnolen: Now as in the equal branch or now as in the master branch?
15:50dnolenqdg: loop/recur hasn't changed, it's a special form
15:52qbgBut assuming 1 is a primitive causes strange behaviour to those who are used to the master branch
15:52dnolenthe only issue is initializing with a literal. if you want a boxed accumulator ask for it.
15:52dnolenthey want loop/recur to participate as fns
15:52dnolenI think this is a bad idea, it isn't an fn
15:55qbg(loop [i 1] (recur (foo i))) won't compile if foo is a regular function currently; some don't like that
15:57qbgOTOH, one could argue that if you are using loop/recur in normal code, you are doing it wrong.
16:01dnolenqbg: exactly, loop/recur converts directly to a low-level iteration. I see no reason to embed smarts into it.
16:02dnoleni 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:04qbgMy previously presented idea would work at compile time, so there shouldn't be a performance difference
16:10KjellskiHi 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:10dnolenqbg: of course that hides the mistake of someone who wants primitives
16:11raekKjellski: have you done "lein deps"?
16:11Kjellskiyes, the jar is already present in lib/
16:11qbgdnolen: The compiler could emit a note if something like *warn-on-reflection* is set.
16:11raekah, now I see it
16:11raek(use 'clojure-csv)
16:12raekotherwise you get the empty prefix list
16:12Kjellskitells me the same: java.io.FileNotFoundException: Could not locate clojure_csv__init.class or clojure_csv.clj on classpath: (NO_SOURCE_FILE:0)
16:12raekshouldn't it be clojure-csv.core?
16:13raekthat was what I found on http://github.com/davidsantiago/clojure-csv
16:13raekmaybe that have been changed recently
16:13Kjellskiraek: damned, thanks man! that did the job!
16:15dnolenqbg: 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:20tomojso either (loop [x (num 1)] ..) or (loop [x 1] ... (+' x ...)) is what to do when you want auto-promotion?
16:20tomojusing unprime in the first loop
16:22qbgRight now you need to use +' to get auto-promotion
16:22qbgAnd the second loop won't compile because +' won't return a primitive
16:26tomojso you're saying you need (loop [x (num 1)] ... (+' x ...)) ?
16:26qbgYes
16:27tomojok, I see
16:27tomoj(loop [x (num 1)] ... (+ x ...)) will use boxed longs but will throw an error on overflow?
16:28qbgLooks like it
16:29qbg(I'm assuming you are recuring with the result of math)
16:59TakeVUse ^ instead of #^ for type hints, right?
16:59qbgYes
16:59TakeVCool.
17:13silveenhuh? ^ instead of #^? since when? and why?
17:14raeksince 1.2 (#^ still works). no idea.
17:14qbgIt has been like that for a while on the master branch.
17:15silveenwierd, but ok
17:21KjellskiI'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:22qbgWhat do you have for :main in your project.clj?
17:23Kjellskiqbg: Yes, and it points to the right file... *stupidasiseeit* do I need the (:gen-class) option for the target namespace?
17:24qbgThat would help...
17:25Kjellskiqbg: It's in and not helping after "lein clean" "lein compile" "lein jar" "java -jar test.jar"
17:26qbgfor :main you have namespace and not its file, correct?
17:28Kjellskiqbg: it's ":main test.core" and in that file it's "(ns test.core ..." something wrong with that?
17:28qbgIf you replace :main with clojure.main, can you launch test.jar and get the clojure REPL?
17:30Kjellskiqbg: 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:30qbgDoes it work when you create an uberjar?
17:30MrHusKjellski: do you have a -main function?
17:32Kjellskiqbg: yeah, then it works when i try to java -jar test-standalone.jar
17:32KjellskiMrHus: Yap, I have...
17:32qbgYou are going to need to have clojure on the classpath when you launch test.jar
17:34Kjellskiqbg: okay, thanks! Could I just use the one in lib/ from that project?
17:34qbgYes
17:59arohneris there a function like repeatedly, where the seq ends when f returns nil?
18:00arohnerI guess I can (take-while identity (repeatedly f))
18:00qbg(take-while #(not (nil? %)) (repeatedly f))
18:22Kjellskiis there any way to make "lein repl" load the :main and it's namespace?
18:57rbarraud\
20:33defnlancepantz: ever get your code up for the rails + clojure?
21:09defnanyone know what the docstring was for lazy-cons?
21:09defnim trying to turn some lazy-cons laden code into lazy-seq code
21:34trptcolindefn: for some definition of "was" (pulled out of the "20081217" branch of the git repo), here it is: http://gist.github.com/445462