2011-03-01
| 02:21 | kilo__ | (re-matches #"[a-zA-Z]* " "test") |
| 03:46 | bartj | if I have a list of vectors of size 2, eg: [1 2] [3 4] |
| 03:47 | bartj | to convert it into a hash-map I do: (zipmap (map first above_list) (map second above_list)) |
| 03:47 | bartj | is there a better way ? |
| 03:47 | bartj | I think the map entries are vectors themselves, so I think there should be a function for this, to get back the original map? |
| 03:49 | bartj | grr, (into {} above_list) |
| 04:07 | TobiasRaeder | morning |
| 04:07 | TobiasRaeder | is there a way to have methods with the same name and varying number of args or varargs in protocols? |
| 04:08 | pyr | hi |
| 04:08 | TobiasRaeder | hi :) |
| 04:10 | Chousuke | TobiasRaeder: I don't think protocols support varargs but you can do (defprotocol Foo (method [arg] [arg arg2])) for example. |
| 04:12 | TobiasRaeder | @Chousuke alright, sadly i kinda need something like (method-a [arg1]) and (method-a [arg1 arg2]) for convinience guess ill just have to name the 2. method-a method-b |
| 04:15 | pyr | ok, probably stupid question |
| 04:15 | pyr | but I can't get to go from a symbol to evaluating a function that has the same name |
| 04:15 | pyr | i.e, given :foo, calling (foo) |
| 04:17 | pyr | i meant keyword |
| 04:17 | pyr | not symbol, obviously |
| 04:18 | Chousuke | TobiasRaeder: convenience? what do you mean? |
| 04:18 | TobiasRaeder | I am kinda unhappy with the current wrappers around java.io.File (ie. i haven't found a function that wraps the File(String, String) constructor |
| 04:18 | Chousuke | TobiasRaeder: that syntax is only used when you define the protocol, when you implement it you write a (method [...] ...) block for each arg count |
| 04:19 | TobiasRaeder | my goal was something along the lines of (as-file "web") and (as-file "web" "WEB-INF") for example |
| 04:19 | TobiasRaeder | oh, maybe i missunderstood you initially |
| 04:19 | TobiasRaeder | think i did :) |
| 04:19 | Chousuke | probably |
| 04:21 | Chousuke | so what you want is (defprotocol FileOps (as-file [this] [this whatever]) and then implement those two for String |
| 04:21 | Chousuke | +) |
| 04:22 | Chousuke | a multimethod might be more flexible though. Protocols are faster but only polymorphic on the first argument. |
| 04:22 | Chousuke | protocol methods* |
| 04:22 | TobiasRaeder | yeah which is enough for me |
| 04:22 | TobiasRaeder | but thanks that was exactly what i was looking for |
| 04:27 | TobiasRaeder | @Chousuke mind looking at https://gist.github.com/848878 ? the first one doesnt work (throws Wrong number of args (1) passed to: user$eval2530$fn) for (as-file "filename") |
| 04:27 | TobiasRaeder | @Chousuk the one i just wrote down (Foo and FooRecord work flawlessly) |
| 04:33 | Chousuke | TobiasRaeder: your extend-type syntax is wrong. |
| 04:33 | Chousuke | at least according to my docs :P |
| 04:33 | TobiasRaeder | http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/extend-type |
| 04:34 | TobiasRaeder | extend uses a map but extend-type seems fine |
| 04:34 | TobiasRaeder | and it works for (as-file "web" "WEB-INF") |
| 04:34 | TobiasRaeder | but the one param one throws the exception |
| 04:34 | Chousuke | huh |
| 04:34 | Chousuke | but it says there (baz ([x] ...) ([x y & zs] ...)) |
| 04:35 | TobiasRaeder | oh wow missed that |
| 04:35 | TobiasRaeder | obviously - its the important part in this case |
| 04:35 | Chousuke | what probably happened is your latter two-argument definition overrode the one-argument definition |
| 04:36 | Chousuke | they're both valid fn tails for a single arity so there would be no error I suppose. |
| 04:36 | TobiasRaeder | whats weird is that the foo example worked but now it's working |
| 04:37 | TobiasRaeder | thanks for pointing that out :) |
| 04:37 | Chousuke | TobiasRaeder: defrecord uses a different syntax for some reason :/ |
| 04:37 | TobiasRaeder | @Chousuke yeah mixing two different thing and not thining about them enough ... thanks :D |
| 04:38 | Chousuke | you've got extra apostrophes in your doc strings btw :P |
| 04:39 | TobiasRaeder | thx :p |
| 05:02 | khaliG | is there a nicer/easier way to persist some settings than slurping to file? |
| 05:04 | Fossi | java properties maybe |
| 05:04 | khaliG | hm, but doesn't still require reading writing files yourself? |
| 05:05 | Fossi | there's some to file or such |
| 05:06 | khaliG | i just want to avoid file io if i want to say some user setting |
| 05:06 | khaliG | but i guess there isn't any convenience feature like that :( |
| 05:07 | khaliG | *save |
| 05:12 | AWizzArd_ | khaliG: you can store the user settings in a map and simply spit it on disk |
| 05:12 | AWizzArd_ | When you want that data back then slurp it and read-string it. |
| 05:13 | khaliG | AWizzArd_, yup doing that for other stuff atm, that's cool at least its a clojure form and all. i just want to avoid dealing with files directly, if possible |
| 05:17 | Fossi | khaliG: the good thing about the property stuff is that it will go to $HOME$/.java-properties or such so you don't need any pathhandling |
| 05:17 | Fossi | bad thing is it's not a nice format |
| 05:18 | khaliG | fair enough. I think i'm just going to sit down and write a Registry thing and use that throughout |
| 05:29 | Cozey | how to access resources in classpath from clojure? |
| 05:33 | khaliG | Cozey, same way as java |
| 05:33 | Cozey | so i need to just go through RT/baseLoader? |
| 05:35 | khaliG | Cozey, yep |
| 05:36 | clgv | seems thread local binding via "binding" is extremely expensive. is that true in general? is there anyway elegant way around it? |
| 05:37 | clgv | example: ##(time |
| 05:37 | clgv | (binding [*value* 1] |
| 05:37 | clgv | (doall |
| 05:37 | clgv | (map #(+ % *value*) (range N))))) |
| 05:37 | clgv | &(time |
| 05:37 | clgv | (binding [*value* 1] |
| 05:37 | clgv | (doall |
| 05:37 | clgv | (map #(+ % *value*) (range N))))) |
| 05:40 | khaliG | Cozey, hm check out clojure.lang.RT/baseLoader |
| 05:41 | Cozey | khaliG: there's no contrib package to support (. baseLoader getResources)? it returns some CompoundEnumeration, which is not easy to access (not sure how except completely using java interop) |
| 05:43 | Cozey | hmm. is there a standard way to iterate over something with hasMoreElements/nextElement? |
| 05:45 | Chousuke | Cozey: you can use let to bind the value to a local if you want to close over it. |
| 05:46 | Cozey | mhm |
| 05:46 | Chousuke | Cozey: is that a java interface? |
| 05:46 | Cozey | none :-( http://download.oracle.com/javase/1.5.0/docs/api/javax/naming/CompoundName.html |
| 05:46 | Cozey | what if i wanted to list directory in classpath? |
| 05:47 | Chousuke | file-seq? |
| 05:47 | Cozey | do i have to go through baseLoader/getResources, and forget about all clojure.contrib.io goodness ? |
| 05:47 | Chousuke | core has a couple iterator/enumerator/whatever seq constructors |
| 05:48 | Cozey | ok, got it! (file-seq (file (baseLoader/getResource ... )) |
| 06:01 | khaliG | if you overwrite some function in clojure.core is there a way to undo that? |
| 06:02 | raek | khaliG: overwrite as in (def conj ...) in your namespace, or (alter-var-root #'clojure.core/conj ...)? |
| 06:03 | khaliG | raek, i used defprotocol with methods called set and get |
| 06:03 | Chousuke | that shouldn't overwrite anything :/ |
| 06:04 | khaliG | it did :/ |
| 06:04 | raek | ok. then clojure.core/get is still intact, but your namespace contains a get -> your-ns/get mapping, instead of get -> clojure.core/get |
| 06:04 | khaliG | raek, correct |
| 06:04 | Chousuke | shouldn't Clojure throw an error in a case like that? |
| 06:04 | khaliG | it gave warnings |
| 06:04 | raek | khaliG: you can remove the var with (ns-unmap 'your-ns 'the-var) and then (refer-clojure) to put back the old one |
| 06:05 | Chousuke | hmm |
| 06:05 | raek | I think it gives a warning nowadays instead of an error to not break old programs |
| 06:05 | Chousuke | I dunno if you should unmap the thing from your namespace |
| 06:06 | Chousuke | wouldn't that render it inaccessible? |
| 06:06 | raek | Chousuke: for protocol functions or in general? |
| 06:06 | Chousuke | the functions |
| 06:06 | Chousuke | or hm, I guess in general |
| 06:06 | khaliG | raek, that did the trick, thank you |
| 06:07 | raek | ah, my interpretation of the question was that he wanted to call it something else but undo the mistake |
| 06:07 | khaliG | yep, i'll change the name to something else now |
| 06:07 | xkb | is it possible to stop one specific agent? |
| 06:07 | xkb | besides adding a control bool |
| 06:08 | raek | xkb: no |
| 06:08 | xkb | ok |
| 06:08 | xkb | I created a small tank simulation, where each moving element is an agent, including bullets |
| 06:08 | xkb | and that creates quite alot of threads sometimes :P |
| 06:08 | raek | if you use a thread pool manually (very similar to sending to an agent) you can call future-cancel on the future |
| 06:09 | Chousuke | xkb: so you didn't go the all-bullets-in-one-structure route? :) |
| 06:09 | xkb | Chousuke: tried that at first, eventually decided to try this anyway. |
| 06:09 | raek | but thread interruption only works directly for certain blocking calls. in general, you have to poll the current thread's interrupted status in your code |
| 06:10 | xkb | Chousuke: maybe I will convert it back.. as this solution slows the system downquite often |
| 06:10 | Chousuke | shouldn't the number of agent threads be limited anyway? :/ |
| 06:10 | raek | which is in the end very similar to check a bool value |
| 06:10 | xkb | I now cary the state of :hit or :shot in each tank and bullet |
| 06:10 | xkb | and those flags act as control bools |
| 06:11 | xkb | it's not really elegant |
| 06:11 | khaliG | how does the all-bullets-in-one structure work? :s |
| 06:11 | raek | khaliG: note that it is possible to have a var called 'get' in your ns and still access the clojure one |
| 06:11 | Chousuke | khaliG: easily. just update the state of all bullets in one go. |
| 06:11 | khaliG | oh, i see |
| 06:11 | xkb | keep one ref with all bullets |
| 06:11 | khaliG | raek, understood |
| 06:11 | xkb | or at least that's what I did |
| 06:12 | Chousuke | you could even have all tanks AND bullets in one structure, really. |
| 06:12 | xkb | and I fixed the number of bullets |
| 06:12 | khaliG | so you update everything in ticks? |
| 06:12 | xkb | yes, actually 2 ticks |
| 06:12 | Chousuke | it should be easier to keep synchronised too |
| 06:12 | xkb | something I have to work on |
| 06:12 | Chousuke | if you have a bunch of agents it'll be hell to figure out what is going on at any single moment |
| 06:13 | xkb | I now have 2 freq. one for bullets, and one for tanks |
| 06:13 | Chousuke | so how are you going to draw the UI? :D |
| 06:13 | xkb | Chousuke: in a separate agent |
| 06:13 | xkb | acting on the grid of the world |
| 06:13 | xkb | and the world cells contain stuff |
| 06:13 | Chousuke | xkb: so do the other agents send it drawing commands? |
| 06:13 | xkb | like the ants demo |
| 06:13 | xkb | Chousuke: nope, the other agents now update "the world" |
| 06:14 | Chousuke | ah. |
| 06:14 | xkb | exactly like the ants demo |
| 06:14 | xkb | with the food etc. |
| 06:14 | xkb | it's kind of a strange mental model though |
| 06:15 | xkb | as the state of a tank is partially in the agent (position) and in "the world" (grid content) |
| 06:15 | Chousuke | I've been thinking that if you need efficient drawing in a functional program you'd probably have to construct a sequence of "drawing commands" from whatever happens when the world is updated. |
| 06:15 | Chousuke | because if you update the world data structure and then draw it, you'll have to redraw everything :/ |
| 06:16 | xkb | hmm kinde lik FRP |
| 06:16 | xkb | like* |
| 06:16 | xkb | Functional Reactive Programming |
| 06:17 | Chousuke | I suppose. You could even construct a seq of update commands and then just send it to two receivers, the one that updates the world data structure, and the renderer. :) |
| 06:17 | xkb | Hmm might be fun to try |
| 06:17 | xkb | this needs to be finished before comming weekend :P |
| 06:17 | Chousuke | yeah, so maybe not :P |
| 06:17 | Chousuke | but it would let you keep the rendering logic neatly separate from the game logic |
| 06:18 | xkb | I'm going to do a presentation on Clojure parallelism/concurrency and use this as a case |
| 06:18 | Chousuke | designing "clean" functional programs seems to get tricky whenever UIs are involved :P |
| 06:19 | xkb | I must say, It was quite hard to escape from a more OOish design |
| 06:19 | Chousuke | I mean, haskell folks go arrows arrows and everyone else is just "er, hm, just write some imperative code" |
| 06:19 | Chousuke | :P |
| 06:19 | xkb | hehe indeed |
| 06:19 | xkb | or they put it in a Monad anyway |
| 06:20 | Chousuke | arrows are a generalisation of monads I think |
| 06:20 | xkb | even though I very much like Haskell :) |
| 06:20 | xkb | ye |
| 06:20 | Chousuke | or a related concept anyway |
| 06:20 | AWizzArd_ | Chousuke: I did not follow the discussion. Was it explained above what you mean by "arrows arrows"? If not, could you please tell more about it? |
| 06:21 | xkb | AWizzArd_: it's a haskell concept: http://www.haskell.org/arrows/ |
| 06:21 | Chousuke | AWizzArd_: I didn't mean much about it; all I know that haskell people have taken some pretty interesting approaches to UI programming and they use arrows :P |
| 06:21 | xkb | or actually it's more of an abstraction over computation |
| 06:21 | Chousuke | there was a really neat demonstration in some paper |
| 06:22 | Chousuke | they wrote a pong UI and then a mirror UI transformer |
| 06:22 | xkb | cool :) |
| 06:22 | Chousuke | then they combined the pong UI with the mirror UI thingy and got a mirrored pong UI |
| 06:22 | xkb | Still I always feel I have to dig up my cat. math. book to really understand it |
| 06:22 | Chousuke | and it was synchronised with the non-mirrored UI |
| 06:22 | Chousuke | both getting the same inputs |
| 06:22 | Chousuke | just rendering differently |
| 06:22 | Chousuke | really cool stuff |
| 06:23 | xkb | hmm think I'll google for the paper |
| 06:23 | xkb | sounds interesting indeed |
| 06:24 | Chousuke | I unfortunately don't remember the name of the library they used /: |
| 06:25 | Chousuke | the arrows page probably links to it |
| 06:30 | xkb | ah found it |
| 06:30 | xkb | http://conal.net/papers/genuinely-functional-guis.pdf |
| 06:31 | Chousuke | hmm, looks like my memory is not very reliable. |
| 06:31 | Chousuke | oh well, still cool stuff. |
| 06:34 | AWizzArd_ | I see, thanks. |
| 07:10 | shafire | hi |
| 07:11 | G0SUB | shafire |
| 07:11 | shafire | why do I write the keys like :key value and not key: value? which reason behind this? |
| 07:12 | shafire | and why def? |
| 07:14 | companion_cube | because :key is a special kind of datatype |
| 07:14 | companion_cube | ,:hello |
| 07:14 | clojurebot | :hello |
| 07:15 | kilo_ | ,'(does the comma invoke the bot ?) |
| 07:15 | clojurebot | (does the comma invoke the bot ?) |
| 07:15 | kilo_ | yep it does ! |
| 07:15 | xkb | ,(class :key) |
| 07:15 | clojurebot | clojure.lang.Keyword |
| 07:16 | xkb | ,(class something) |
| 07:16 | clojurebot | java.lang.Exception: Unable to resolve symbol: something in this context |
| 07:16 | companion_cube | ,(= :hello :hello) |
| 07:16 | kilo_ | ,( + 1 2) |
| 07:16 | clojurebot | true |
| 07:16 | clojurebot | 3 |
| 07:16 | Chousuke | shafire: Clojure has pretty minimal syntax. Map syntax for example is nothing but {} and key value pairs |
| 07:16 | thorwil | where a value can be a key |
| 07:17 | Chousuke | shafire: so the following are valid maps: {:key 'val} {'key :val} {1 2} {"key" {:another 'map}} and even {{:a :map} 'val} |
| 07:17 | shafire | so, why not key: value - looks better? |
| 07:18 | Chousuke | shafire: what would key: be? |
| 07:18 | companion_cube | for the sake of uniformity |
| 07:18 | xkb | as far as I know a key can be anything implementing hascode/equals right? |
| 07:18 | Chousuke | shafire: and IMO it doesn't really look any better. :P |
| 07:18 | Chousuke | the : is just superfluous. why should it be there? |
| 07:19 | thorwil | shachaf: because the : has nothing to do with the following item, but only marks a key symbol as such |
| 07:19 | shafire | okay, and why def and not function or so? |
| 07:20 | Chousuke | def is for defining bindings to anything, not just functions |
| 07:20 | Chousuke | and since "fn" is the clojure term for a function, the define-function macro is called defn :P |
| 07:21 | shafire | :-) |
| 07:21 | shafire | today, it's my first day with clojure |
| 07:21 | Chousuke | defn is just a shortcut for (def foo (fn foo ...)) plus some other stuff :) |
| 07:24 | xkb | shafire: so do you like it? :) |
| 07:24 | Chousuke | if Clojure syntax seems weird to you, keep in mind that most of it is not actually defined in terms of text, but in terms of data structures |
| 07:24 | shafire | yeah, i like it, but it's complicated |
| 07:25 | shafire | but i have the feeling, the code is shorter |
| 07:25 | Chousuke | the data structures have a literal textual representation, but the syntax of things like defn or defmacro or defprotocol is defined by the data structures, not the text. |
| 07:25 | xkb | :) |
| 07:26 | shafire | (* 99999999999999999999999999999999999999 99999999999999999999999999999) |
| 07:26 | clojurebot | #<RuntimeException java.lang.RuntimeException: java.lang.NumberFormatException: For input string: "99999999999999999999999999999999999999"> |
| 07:27 | xkb | :P |
| 07:27 | clgv | performance question: does an algorithm written with iterate have significant duration overhead compared to a loop-recur one? |
| 07:27 | shafire | (* 99999999999999999999999 999999999999999999999999) |
| 07:27 | clojurebot | #<RuntimeException java.lang.RuntimeException: java.lang.NumberFormatException: For input string: "99999999999999999999999"> |
| 07:27 | shafire | mhm |
| 07:27 | shafire | how long? |
| 07:27 | Chousuke | for example, in (defn foo [params] body) there's no "paren, defn, string, bracket..." but "list:defn-symbol, name-symbol, vector of symbols, body" |
| 07:29 | Chousuke | though I guess this is not so important in the beginning. I just think it's good to keep in mind if you think clojure has weird syntax. |
| 07:29 | shafire | do you use intellij? good enough? |
| 07:30 | shafire | i like weird syntax :D |
| 07:30 | xkb | I use vim, but that's an exception in clojure-land |
| 07:30 | xkb | most use emacs I think |
| 07:30 | clgv | I use eclipse which seem to be rare too ;) |
| 07:30 | Chousuke | emacs with paredit and slime is just too good with lisp :) |
| 07:31 | xkb | vim has something similar nowadays |
| 07:31 | Chousuke | though I suppose some of the IDEs have comparable features already. |
| 07:31 | xkb | though the emacs version is far superior |
| 07:31 | xkb | however, my mind is wired in vim |
| 07:31 | Chousuke | vim is not very suited to working with external programs :/ |
| 07:31 | clgv | <joke>I already had an operating system installed - so why should I install emacs too? </joke> ;) |
| 07:32 | Chousuke | it's got a nice editing model IMO but the implementation is bad. |
| 07:33 | Chousuke | it's great as a simple editor but when you need to extend and integrate it with other tools it shows its weakness :/ |
| 07:34 | kilo_ | hi, newbie here, how do i invoke the clojurebot |
| 07:34 | companion_cube | ,(+ 1 1) |
| 07:34 | xkb | use , as prefix |
| 07:34 | clojurebot | 2 |
| 07:34 | kilo_ | ,(* 99999999999999999999999 999999999999999999999999) |
| 07:34 | clojurebot | java.lang.ExceptionInInitializerError |
| 07:34 | Chousuke | numbers too large :P |
| 07:34 | kilo_ | interesting. this works on my clojure box |
| 07:34 | Fossi | kilo_: if you just want a quick repl you can also message it in private |
| 07:34 | xkb | what's up with the bignums |
| 07:35 | Chousuke | ,(* 99999999999999999999M 99999999999999999999999M) |
| 07:35 | clojurebot | 9999999999999999999899900000000000000000001M |
| 07:35 | kilo_ | M !! |
| 07:35 | Chousuke | ,*clojure-version* |
| 07:35 | clojurebot | {:major 1, :minor 2, :incremental 0, :qualifier ""} |
| 07:35 | khaliG | ugh protocols are confusing, shall i persevere or just use interfaces for now :/ |
| 07:35 | clgv | whats up with sexpbot today? |
| 07:35 | xkb | persevere I'd say |
| 07:35 | kilo_ | Fossi, tx, already have clojure version, was showing off to a (C++) friend |
| 07:36 | kilo_ | i meant clojurebox |
| 07:36 | Fossi | kilo_: well, i meant people tend to use it in here after asking that question and we all get spammed to death ;) |
| 07:36 | shafire | why do you like clojure? |
| 07:36 | kilo_ | I understand. |
| 07:36 | Fossi | shafire: why wouldn't you? |
| 07:36 | xkb | elegant, terse syntax. no bloat |
| 07:37 | khaliG | xkb, ok i shall! |
| 07:37 | Fossi | lisp + jvm + nice datastructures = win |
| 07:37 | xkb | khaliG: good luck :) |
| 07:37 | xkb | hehe nice one |
| 07:37 | clgv | &(+ 1 2) |
| 07:42 | shafire | Fossi: win win:) |
| 07:43 | shafire | just one i don't like |
| 07:43 | shafire | nobody is commeting his code.... |
| 07:43 | shafire | nobody has commented his code |
| 07:43 | shafire | https://github.com/richhickey/clojure-contrib/blob/master/clojurescript/src/clojure/contrib/clojurescript.clj |
| 07:45 | clgv | shafire: you are right. I hate the lack of commets, too. it makes a lot of things hard to understand |
| 07:46 | xkb | quite often in functional programming, functions are very short and therefore easy to understand without comments |
| 07:47 | xkb | but I agree, in contrib it's very hard to understand sometimes |
| 07:47 | clgv | then have a look in clojure core xkb - I pick a random definition and you explain it adhoc ;) |
| 07:47 | xkb | hehe hence the second sentence :) |
| 07:48 | xkb | core and contrib are very hard to read sometimes indeed |
| 07:48 | xkb | esp. with nested let bindings and stuff |
| 07:49 | clgv | it took me a while to get the details of the "defn" definition in there ;) |
| 07:50 | kilo_ | hey, what does ..... |
| 07:50 | kilo_ | ,(doc defn) |
| 07:50 | clojurebot | "([name doc-string? attr-map? [params*] body] [name doc-string? attr-map? ([params*] body) + attr-map?]); Same as (def name (fn [params* ] exprs*)) or (def name (fn ([params* ] exprs*)+)) with any do... |
| 07:50 | kilo_ | not too readable.... hmm |
| 07:51 | clgv | kilo_: I didn't mean the doc. I meant the implementation of "defn" ;) |
| 07:52 | xkb | for documentation you can also check http://clojuredocs.org/clojure_core/clojure.core/defn- |
| 07:52 | shafire | why are all clojure def so short? that is really amazing... |
| 07:53 | khaliG | shafire, compared to? |
| 07:53 | kilo_ | clgv, true |
| 07:53 | kilo_ | that was easier to understand |
| 07:54 | shafire | khaliG: java |
| 07:54 | Dranik | java is designed to be understendable for brain-damaged people |
| 07:55 | kilo_ | sorry clgv, i misunderstand . when you said 'in there' ..... |
| 07:55 | clgv | kilo_: np |
| 07:55 | shafire | Dranik: you are so funny :D |
| 07:56 | shafire | and the clojure community is more active than the scala community |
| 07:56 | khaliG | shafire, i'm not sure.. i've got an almost complete program in about 500 lines of clojure and when i mocked it up in netbeans/matisse the generated code itself was about 1000 lines just for an older version |
| 07:57 | shafire | mh |
| 07:57 | Fossi | actually i like the code of core quite a bit |
| 07:57 | Fossi | sometimes it's easier to just read the code than the random doc |
| 07:57 | Fossi | esp for things like defn |
| 07:59 | clgv | I think e.g. the defn code would be easier to understand if there were some comments explaining the sub steps ;) |
| 08:07 | shafire | commenting clojure is a major step worth |
| 08:10 | shafire | see you later |
| 08:10 | shafire | bye |
| 08:14 | _fogus | amalloy_: Ping |
| 08:24 | semperos | _fogus: pretty sure he's a west coaster |
| 08:24 | _fogus | It was worth a shot. |
| 08:24 | semperos | :) |
| 08:27 | cemerick | _fogus: BTW, Ruby? :-O |
| 08:27 | cemerick | ;-) |
| 08:28 | _fogus | OOP is the wave of the future! |
| 08:29 | cemerick | So I've heard. |
| 08:29 | cemerick | Bizarrely, I've been tinkering with perl lately. |
| 08:29 | _fogus | Orgiastic mutation FTW |
| 08:29 | cemerick | I guess that's more deserving of a :-O |
| 08:29 | clgv | _fogus: whats that supposed to mean? |
| 08:30 | _fogus | Perl6? |
| 08:30 | _fogus | clgv: What is what supposed to mean? |
| 08:30 | clgv | (14:19:54) _fogus: OOP is the wave of the future! |
| 08:30 | cemerick | Honestly, I'm not over the WTF stage enough to make any reasonable distinction between perl 5 or 6 yet. |
| 08:32 | _fogus | clgv: Haven't you heard the news? Object-oriented programming is the "way that the world works" |
| 08:32 | cemerick | clgv: I think writing a Clojure book makes one dread functional programming. |
| 08:33 | clgv | ah ok. :P |
| 08:33 | clgv | is that book finished now? |
| 08:33 | _fogus | clgv: I'm just playing... but I'm also not hardlined against OOP |
| 08:34 | cemerick | clgv: the above has a huge ;-) of course |
| 08:34 | clgv | cemerick: yeah read it like that ;) |
| 08:35 | fliebel | cemerick: http://rubini.us/2011/02/25/why-use-rubinius/#wur-academic |
| 08:35 | fliebel | "Despite vast odds, somehow programs are written that actually run." |
| 08:36 | _fogus | fliebel: Nice quote |
| 08:36 | cemerick | Everything is always despite vast odds. |
| 08:36 | cemerick | s/somehow.*/somehow we moved out of the caves |
| 08:36 | cemerick | etc |
| 08:37 | _fogus | Getting out of bed this morning was pretty tough too |
| 08:38 | cemerick | "Oh shit, I need to screw with dates today. GD ISO 8601" |
| 08:39 | _fogus | cemerick: I liked your tweet about the Scala levels. |
| 08:39 | fliebel | _fogus: Link? |
| 08:39 | _fogus | fliebel: To the original? |
| 08:40 | fliebel | _fogus: Noh, just curious what cemerick said. |
| 08:40 | cemerick | _fogus: It's bat-nuts crazy IMO. I have cynical theories as to why such a concept was surfaced. |
| 08:40 | cemerick | Thankfully, I do keep my trap shut sometimes. |
| 08:41 | _fogus | http://twitter.com/#!/cemerick/status/40416922378051584 |
| 08:41 | clgv | if I have a transient vector can I still change position "i" or is the "only" effect that conj!-ing is much faster? |
| 08:42 | _fogus | cemerick: That post is a perfect microcosm of the Scala community in general. |
| 08:42 | cemerick | clgv: nah, there's assoc! and dissoc! too |
| 08:42 | clgv | cemerick: thanks. thats what I wanted to hear ;) |
| 08:42 | cemerick | and pop! and disj! |
| 08:43 | cemerick | disj! only for sets, of course |
| 08:43 | fliebel | And some more with some copy-pasting fom clojure.core :) |
| 08:43 | fliebel | e.g. update-in! |
| 08:44 | cemerick | _fogus: I figured. Doesn't seem out of line with the crazy I was seeing before I left. |
| 08:44 | cemerick | Eh, that's ungenerous of me. |
| 08:45 | cemerick | I suppose it works for some. Just not my cup of tea. |
| 08:45 | _fogus | Scala's type system is so powerful that it also types the programmers themselves. |
| 08:46 | fliebel | _fogus: Nice one :) |
| 08:46 | _fogus | object Fogus extends A3 with L1 |
| 08:46 | cemerick | hah |
| 08:47 | cemerick | The haskell and F# folk don't seem to have such artifice though. Perhaps it's the "java.next" sword that hangs over the scala community's head that prompts such things. |
| 08:47 | _fogus | Scala's levels are too coarse... I can't properly mix them into myself! |
| 08:48 | fliebel | cemerick: Han, in Haskell, you'd just say Pepijn -> Pepijn and be done with it. |
| 08:56 | _fogus | dnolen: Can the same be said about any language? |
| 08:57 | clgv | if clojure had levels, the good thing would be that we could level up ;) |
| 09:00 | lucian | clgv: imagine: "you're typing away, you just wrote a highly-concurrent web-server using the STM and your text editor goes: "DING! LEVEL 4!"" |
| 09:01 | jkdufair | I think I need a guide like that for life itself. i.e. A1: respiration, defecation, A2... Z999: zen master |
| 09:01 | cemerick | lucian: now we just need unlockable achievements… |
| 09:02 | cemerick | …and that's when I become a carpenter. |
| 09:02 | clgv | lucian: hilarious thought :D |
| 09:02 | fliebel | dnolen: I gave up the number stuff for a while. I tried to reason about it for a while, change a few things, but no luck. |
| 09:02 | octe | hehe, speaking of achievements and programming |
| 09:02 | octe | http://blog.whiletrue.com/2011/01/what-if-visual-studio-had-achievements/ |
| 09:03 | jkdufair | M-x swank-level-up |
| 09:03 | fliebel | octe, lik the new ms word, I read? |
| 09:03 | octe | octe, huh? |
| 09:03 | lucian | octe: that list's somewhat funny |
| 09:03 | octe | fliebel, huh?* |
| 09:04 | jkdufair | octe: literally LOL |
| 09:04 | _fogus | "You must go to El Dorado and talk with Chouser before you can reach the next level" |
| 09:04 | fliebel | octe: I read ms is planning to add achievements to word as a sort of 'game' to learn Word. |
| 09:04 | octe | oh |
| 09:04 | octe | haha |
| 09:04 | octe | that'd be funny |
| 09:06 | jkdufair | I tried to use PLT Scheme for a project. Amongst other things, the levels made me a bit nuts. |
| 09:07 | lucian | fliebel: reading that rubinius thing, it confirms my suspicion that Ruby programmers don't really know other languages |
| 09:08 | fliebel | lucian: How so? |
| 09:08 | lucian | the article treats bad and good languages just as badly, likely just because they're not ruby |
| 09:08 | lucian | fliebel: there's a dig at python, even comparing it to PHP to some extent. that's just nasty |
| 09:09 | lucian | also an "eww" directed at Groovy, which isn't really that bad |
| 09:09 | cemerick | No one can ever claim that Groovy is elegant, but it sure can get a job done. |
| 09:09 | cemerick | reading that rubinius thing talking about "making ruby fast" reminds me of those hordes of really smart people working on making javascript fast, all due to one unfortunate historical accident |
| 09:11 | _fogus | cemerick: Which event? It's release? |
| 09:11 | lucian | cemerick: meh, ruby isn't nowhere near as crappy as js |
| 09:11 | lucian | i see ruby as almost as nice as python |
| 09:11 | hoeck | cemerick: which event, the inclusion in every browser? |
| 09:11 | fliebel | cemerick: As they put it in this book I have here, Ruby is made for fast writing, not fast execution. |
| 09:13 | cemerick | The accident being: the original 10-day spike, followed by its updake, distribution, and then shoehorning into a standard. Everything is predicated on that one break. |
| 09:14 | TimMc | lucian: My first encounter with Groovy was Grails, where I stared at the scaffolding code for about 20 minutes before I understood that they were trying to make a DSL using catchall methods. Then I burned my computer and ran away screaming. |
| 09:14 | cemerick | lucian: It's the "let's work on making language X fast" objective that made me think of the js connection, not anything related to the languages themselves. |
| 09:15 | _fogus | fliebel: I think that is perfectly valid in the abstract. I can't say that I find Ruby particularly speedy at composing, but that's probably just me |
| 09:15 | cemerick | It seems like once you're contemplating writing yet another VM, something's gone haywire. |
| 09:15 | lucian | cemerick: i see. well, i see it as a nice goal. languages shouldn't be designed first and foremost to be easy to write a fast implementation for |
| 09:16 | octe | The Joy Of Clojure is interesting enough that i'd actually want a dead tree variant |
| 09:16 | cemerick | lucian: oh, it's a fine goal. See, this is what happens when I expose my stream-of-consciousness. :-P |
| 09:16 | octe | i've never actually wanted to read a programming book before |
| 09:16 | lucian | cemerick: well, which vm to use? for many purposes the jvm isn unacceptable |
| 09:17 | lucian | and parrot isn't yet mature enough |
| 09:17 | fliebel | lucian: Rubinus, PyPy, Parrot, etc... |
| 09:17 | dnolen | _fogus: Clojure has far more levels than JavaScript, IMO |
| 09:17 | sacho | I don't see why javascript is "horrible" and makes programs written in it "slow" |
| 09:17 | cemerick | lucian: LLVM, parrot, mono |
| 09:17 | lucian | cemerick: well, they're using llvm |
| 09:17 | companion_cube | what do you call "levels" ? |
| 09:18 | TimMc | sacho: JS is great, IMO. |
| 09:18 | lucian | mono has dubious licensing issues |
| 09:18 | dnolen | fliebel: where you unable to implement the number stuff from TRS at all? |
| 09:18 | locks | rubinius |
| 09:18 | lucian | fliebel: and PyPy is awesome, but it's still writing a new VM |
| 09:18 | sacho | TimMc: sure, minus a few backward-compatibility inherited bumps. |
| 09:18 | lucian | fliebel: and you're forgetting that Ruby people hate Python (even though Python people rather like Ruby) |
| 09:18 | cemerick | lucian: all I know about it, I read on wikipedia :-P |
| 09:18 | locks | lucian: psh, those pesky whitespaces ;P |
| 09:18 | sacho | are people who use both python and ruby rythonists or pybyists? |
| 09:19 | fliebel | dnolen: I got the addition exactly as in the book and the minikanren source, but it has duplicated results. |
| 09:19 | lucian | sacho: that's a dreadful name |
| 09:19 | locks | is there a red snake? |
| 09:19 | sacho | why not. Rython, Python that compiles to ruby code! |
| 09:19 | _fogus | dnolen: I would agree with that. But there's more to js than meets the eye. I'm not sure many people understand that |
| 09:19 | lucian | cemerick: i see. they don't use llvm that much because llvm sucks for anything but compiling static code |
| 09:19 | dnolen | fliebel: hmm, is your all your work pushed to your fork? |
| 09:19 | lucian | sacho: there's unholy, which does the reverse |
| 09:20 | cemerick | pypy and parrot get a pass, since they were through the gate first. Seriously, if someone said they were starting a new VM project, they should get a lot of strange looks. |
| 09:20 | fliebel | sacho: There is a Python implementaion for Rubynus. |
| 09:20 | locks | I'm reading 'js the good parts' and falling in love with it :P |
| 09:20 | lucian | cemerick: i mostly agree, but i think that in this case it's partly justified |
| 09:21 | lucian | locks: try CoffeeScript and you'll love it even more :) |
| 09:21 | fliebel | dnolen: Yes, except that I flattened one all into the parent exist, which should not matter. |
| 09:21 | locks | lucian: it's because of CS that I wanted to learn JS properly ;) |
| 09:21 | locks | the C-syntax really tricks you into thinking of js wrong |
| 09:21 | lucian | cemerick: for the record, i'm a pypy user and i plan to implement python on parrot |
| 09:21 | _fogus | dnolen: Although I might say that Clojure's required knowledge is less transferrable from other languages. In order to get experience in the types of things that Clojure advocates you need to have exposed yourself to many different languages. |
| 09:21 | dnolen | fliebel: I'll check it out later today. |
| 09:21 | _fogus | lucian: Until you need to debug i5t |
| 09:22 | cemerick | lucian: yeah, the perceived value is directly corollated with one's interest in ruby :-) |
| 09:22 | fliebel | dnolen: Only thing I did not do yet is computing the result by hand. |
| 09:22 | companion_cube | just, what do you call "levels" in the context of a language ? |
| 09:22 | lucian | _fogus: ? |
| 09:23 | dnolen | companion_cube: reference to this, http://www.scala-lang.org/node/8610 |
| 09:23 | lucian | cemerick: they considered PyPy to be too python-y (stupid) and parrot immature (mostly correct) |
| 09:23 | companion_cube | uh, ok |
| 09:23 | companion_cube | and clojure has more levels? |
| 09:24 | pyr | clojure just made my day |
| 09:24 | pyr | https://gist.github.com/849172 |
| 09:24 | cemerick | lucian: I have irrational faith in the parrot folks. |
| 09:24 | dnolen | companion_cube: ehhh, no, just that Clojure has many levels as well. Even more so for those unfamiliar with FP or Lisp. |
| 09:24 | lucian | cemerick: they do have awesome goals, don't they? join i.p.o#parrot |
| 09:24 | cemerick | companion_cube: I don't think anyone is going to be so daft as to attempt to codify "levels" for Clojure. |
| 09:25 | companion_cube | oh, yeah, i suppose it takes time to begin playing with some features like meta |
| 09:25 | lucian | the levels thing is stupid |
| 09:25 | octe | has anyone noticed that require'ing swank.swank increases compilation time a lot? |
| 09:25 | _fogus | I think Tony Morris's response to the Scala levels was apt. Vintage Morris. |
| 09:25 | locks | lol @ levels |
| 09:26 | locks | makes me think of maturity levels *shivers* |
| 09:26 | cemerick | locks: I don't think the vernacular was accidental. |
| 09:26 | locks | _fogus: link? |
| 09:26 | Adamant | complexity is hard, let's go shopping |
| 09:26 | locks | complex is better than complicated |
| 09:27 | _fogus | locks: http://blog.tmorris.net/critique-of-oderskys-scala-levels/ |
| 09:27 | locks | thanks |
| 09:27 | fliebel | Hm, dos Clojure have a PEP 20? |
| 09:28 | cemerick | fliebel: style guide, you mean? |
| 09:28 | fliebel | cemerick: 8 is style guide, 20 is zen. |
| 09:28 | lucian | cemerick: that's PEP 8 |
| 09:28 | fliebel | (locks quoted it) |
| 09:29 | lucian | cemerick: try python -m "this" |
| 09:30 | locks | what's the rpoblem with it? |
| 09:30 | _fogus | We had a "style guide" in JoC up until the final editing phase, but threw it out |
| 09:31 | locks | haha |
| 09:31 | fliebel | _fogus: Why? |
| 09:31 | _fogus | fliebel: page count mostly, but also because it's really something that should be a living document rather than in a book |
| 09:31 | lucian | locks: it boasts a lot of features that rubinius doesn't actually have (yet, anyway) |
| 09:31 | _fogus | we will probably put it up on the site one day |
| 09:32 | fliebel | _fogus: (is it done nearly? I've only got 1.7 programming books left) |
| 09:32 | locks | lucian: it's blogpost-driven development :) |
| 09:33 | Fossi | yeah, that's quite a great comment to the level thing |
| 09:33 | fliebel | Man, #clojure is full of good quotes today :) |
| 09:33 | lucian | locks: not only that, but CRuby (or is it called MRI?) has those exact features |
| 09:33 | _fogus | fliebel: The delay of JoC is a very sore point for me... but yes, it's 1-2 days away from being sent to the printer. |
| 09:34 | fliebel | yay! |
| 09:34 | TimMc | _fogus: Congratulations! |
| 09:35 | eckroth` | _fogus: what delayed JoC? I too have been waiting a while but it didn't seem to me like it has been "delayed" |
| 09:35 | _fogus | If I ever consider writing another book again someone PLEASE shoot me |
| 09:35 | TimMc | aw |
| 09:35 | zoldar | _fogus, will this release have some substantial differences in comparison to the "final" MEAP release? |
| 09:35 | lucian | dnolen: heh |
| 09:35 | Fossi | i guess you have to be an author to get why every author says that |
| 09:36 | _fogus | zoldar: The final MEAP has yet to be released. But it will be mostly the same structure as the last MEAP update with less grammar errors and misspellings. :-O |
| 09:36 | eckroth` | Fossi: probably; maybe the authors always have personal deadlines that are not met; it's best we (not the authors of JoC) can just pleasently bide our time :) |
| 09:37 | pjstadig | JoC is stalled? |
| 09:37 | pjstadig | :-p |
| 09:37 | locks | lucian: I think it's MRI now, who cares as long as we understand each other :P |
| 09:37 | _fogus | eckroth`: I'll tell you over a drink one day... not in a public forum. Sorry |
| 09:38 | octe | interesting |
| 09:38 | eckroth` | _fogus: oh ok; thought it was just a silly thing like buggy copyediting software or whatever; no problem; glad it's soon on its way! |
| 09:38 | octe | the long compile times when requiring swank seems related to leiningen |
| 09:38 | octe | takes 1m6s to compile a hello world which requires swank with leiningen |
| 09:38 | octe | and 16s with cake, with no jvm running |
| 09:39 | fliebel | Okay, anyone in for spewing Clojure commandments? |
| 09:39 | fliebel | "Namespaces are one honking great idea -- Clojure does more of those" ;) |
| 09:39 | _fogus | pjstadig: zing! |
| 09:40 | pjstadig | sorry... |
| 09:40 | pjstadig | i was totally joking |
| 09:40 | fliebel | "When faced with repetition, refuse the temptation to write a macro" |
| 09:40 | Fossi | yeah, c&p instead |
| 09:40 | fliebel | -.- |
| 09:41 | Dranik | fliebel, where did you read that? |
| 09:41 | fliebel | Dranik: I'm making it up right now. |
| 09:42 | fliebel | "Functions are better than macroes" "Although macroes are better than mutability" |
| 09:43 | fliebel | "fliebel may not be obvious at first unless you're Dutch." |
| 09:43 | Dranik | fliebel, that one about macro was really confusing |
| 09:43 | tscheibl | ,(let [x [:test]] (contains? x :test) |
| 09:43 | clojurebot | EOF while reading |
| 09:43 | tscheibl | ,(let [x [:test]] (contains? x :test)) |
| 09:43 | clojurebot | false |
| 09:43 | tscheibl | shoud that worry me? |
| 09:43 | tscheibl | l |
| 09:43 | clgv | ,(doc contains?) |
| 09:43 | clojurebot | "([coll key]); Returns true if key is present in the given collection, otherwise returns false. Note that for numerically indexed collections like vectors and Java arrays, this tests if the numeric k... |
| 09:44 | fliebel | Dranik: It was. you have better suggestions? |
| 09:44 | tscheibl | ,(let [x '(:test)] (contains? x :test)) |
| 09:44 | clojurebot | false |
| 09:44 | tscheibl | same |
| 09:45 | Fossi | it's fun to read |
| 09:45 | TimMc | Is there ever a case in Clojure where (identical? l (next (cons :foo l))) is false? |
| 09:45 | _fogus | tscheibl: contains? looks for keys only. It's not a function to look up values in a sequence |
| 09:45 | tscheibl | _fogus: ahh ok.. |
| 09:45 | fliebel | tscheibl: I think some does that. |
| 09:45 | TimMc | That is, do the persistent data structures ever get swapped out for size-based optimization? |
| 09:46 | clgv | ,(let [x [:test]] (contains? 0 :test)) |
| 09:46 | clojurebot | false |
| 09:46 | _fogus | ,(some #{:test} '(foo bar :test)) |
| 09:46 | clojurebot | :test |
| 09:46 | clgv | ups lol mixed it |
| 09:46 | _fogus | ,(let [x [:test]] (contains? 0 x)) |
| 09:46 | clojurebot | false |
| 09:46 | clgv | ,(let [x [:test]] (contains? x 0)) |
| 09:46 | clojurebot | true |
| 09:46 | _fogus | (let [x [:test]] (contains? x 0)) |
| 09:47 | _fogus | I'm too slow! |
| 09:47 | clgv | and doing the same mistakes ;) |
| 09:47 | _fogus | :-( |
| 09:52 | clgv | hmm I have a bad feeling with this: I have an algorithm that is creating vectors with double and then calculating partial sums. Now I got the idea that the it could be a significant overhead to create all these vectors all the time in comparison to simply create one double array at the begin of the algorithm and reuse it every time. is that worth a shot or simply a bad idea? |
| 09:53 | raek | ,(let [x #{:test}] (contains? x :test)) |
| 09:53 | clojurebot | true |
| 09:53 | clgv | these vectors with doubles are really one main part of the algorithm - approx. half of the time is spent there |
| 09:54 | dnolen | clgv: yeah doesn't sound like you should be using vectors here. |
| 09:55 | clgv | dnolen: so the reused double-array would be the way to go? |
| 09:55 | raek | clgv: do you need to pour the data into vectors, or could you manage with using lazy sequences directly? |
| 09:55 | dnolen | clgv: if performance is the most important thing yes. |
| 09:57 | clgv | raek: I need could exchange the vectors with a sequence but I guess the question woul remain the same |
| 09:57 | raek | for example, in (reductions f (vec (map g some-coll))), the vec is superflous |
| 09:57 | raek | ...but this might not be the issue here |
| 09:57 | clgv | raek: it's a probability distribution that is calculated and then I draw a single element from it |
| 09:58 | dnolen | even so w/ vector or sequences you face the overhead of boxing, unboxing numbers. |
| 09:58 | raek | so you need to do look-up with an index? |
| 10:01 | clgv | raek: its concept is: (1) calculate probability for each element (2) calculate commulative distribution function (partial sums) (3) draw random value (4) get element related to random value |
| 10:06 | TimMc | Ah, so you don't know which element you'll be using ahead of time. |
| 10:07 | TimMc | Unless... could you pick the random value ahead of time and only do the calculations necessary for that value? |
| 10:07 | TobiasRaeder | anyone knows an easy way to launch something (ie shellscript) and then pipe all output to stdout? |
| 10:07 | clgv | TimMc: yes, I don't know which element it'll be. I want to pick it at random with a certain probability distribution |
| 10:08 | TimMc | clgv: Is "draw random value" a random index into the vector or a random value *from* the vector? |
| 10:09 | octe | any opinions on berkeley db? (for java) |
| 10:09 | TimMc | _fogus: Like iterate? |
| 10:09 | clgv | TimMc: when I calculate the partial-sums the last one is total-sum. then I do (rand total-sum) |
| 10:10 | _fogus | TimMc: kinda yes |
| 10:10 | TimMc | With take? |
| 10:11 | TimMc | clgv: I'm not sure I understnd the partial-sums stuff, unfortunately. |
| 10:12 | _fogus | TimMc: But I need the last n results to calculate the next value |
| 10:12 | TimMc | _fogus: Oh! Interesting. |
| 10:13 | _fogus | I'm sure someone has written it before. |
| 10:14 | TimMc | What's the use case? |
| 10:14 | clgv | TimMc: concept: (let [probs (map calc-probability element-list), partial-sums (reductions + 0.0 probs), rnd (rand (last partial-sums))] (select-element-index partial-sums rnd) |
| 10:14 | clgv | thats the idea |
| 10:15 | _fogus | TimMc: Curve fitting |
| 10:15 | TimMc | _fogus: hmmok |
| 10:16 | _fogus | ,(doc hmmok) |
| 10:16 | clojurebot | Gabh mo leithscéal? |
| 10:16 | _fogus | :p |
| 10:18 | TimMc | clgv: select-element-index grabs an element from the partial sums of the probabilities based on rnd? |
| 10:18 | TimMc | Or does it give you the index? |
| 10:18 | TimMc | It reminds of wrand. |
| 10:19 | clgv | only an index |
| 10:19 | clgv | whats wrand? |
| 10:19 | clgv | ,(doc wrand) |
| 10:19 | clojurebot | Excuse me? |
| 10:19 | TimMc | where did I see this... |
| 10:20 | TimMc | pffft, never mind |
| 10:20 | TimMc | It's something defined in ants.clj. |
| 10:20 | clgv | yeah thats what google said too ;) |
| 10:21 | TimMc | Is that basically what you are doing with the probs, though? |
| 10:22 | clgv | seems so at first glance. it looks similar to my first approach |
| 10:23 | clgv | I am trying the double array approach now. |
| 10:26 | clgv | it's just getting pretty ugly in comparison to the first elegant version |
| 10:27 | TimMc | clgv: Benchmark the two. Is the ugliness worth the gains? |
| 10:27 | clgv | I'll do |
| 10:28 | clgv | I am encapsulating it in a deftype |
| 10:28 | clgv | so it's hidden from the main algorithm |
| 10:30 | dnolen | clgv: are you using amap/areduce? |
| 10:32 | clgv | dnolen: no. loop-recur right now |
| 10:40 | clgv | with the new handling of java primitives in 1.3 will a transient vector of doubles be almost equivalent to a double array in terms of performance? |
| 10:45 | dnolen | clgv: no |
| 10:45 | dnolen | clgv: from what I understand transient gvecs are going to happen until after Pods. |
| 10:46 | dnolen | s/are/aren't |
| 10:46 | jcromartie | does it make sense to have a "lazy set" |
| 10:46 | jcromartie | ? |
| 10:46 | jcromartie | I guess not |
| 10:47 | clgv | dnolen: what is "Pods"? sexpbot seems to be on holidays... |
| 10:48 | dnolen | clgv: rhickey's new reference type for dealing POJOs as well as unsafe mutable code w/o having to manually deal with locks. |
| 10:49 | jcromartie | Pods ~ Beans? |
| 10:49 | dnolen | clgv: ultimately, map + gvec of prims should be as fast amap/areduce. transients will become implementation detail. |
| 10:49 | clgv | dnolen: ok. I hope there is going to be a lot of docu on new features when 1.3 is released |
| 10:51 | clgv | ah gvec = generic vector |
| 10:51 | dnolen | clgv: none of what I described is slated for 1.3 as far I know. |
| 10:52 | clgv | dnolen: oh ok. so it's "planned" for later? |
| 10:53 | dnolen | clgv: something like that. |
| 10:55 | ttmrichter | What's the current best package for "install and have a REPL" to introduce a new Clojure user to the technology? |
| 10:56 | TimMc | ttmrichter: leiningen is a build tool, but I think it's a pretty fast way to get a REPL |
| 10:57 | ttmrichter | I'm targetting a Windows user here: someone who's going to want an installer and a clicky-icon. |
| 10:57 | TimMc | heh |
| 10:58 | TimMc | Are you sure you want someone writing programs who can't handle running a self-install script? :-P |
| 11:00 | zoldar | ttmrichter, http://www.try-clojure.org/ could be of some use to some extent |
| 11:00 | zoldar | for the basics at least |
| 11:02 | ttmrichter | Is "Clojure Box" any good? |
| 11:02 | ttmrichter | It seems to fit the bill here. |
| 11:03 | ttmrichter | Hmmm... The Emacs thing might be a tough sell. |
| 11:10 | clgv | ttmrichter: you might try eclipse counterclockwise |
| 11:11 | ttmrichter | I was just about to ask about Counterclockwise and Enclojure. |
| 11:11 | clgv | ttmrichter: if you have eclipse setup you just need to add the update site and install CCW and then create a clojure project |
| 11:11 | ttmrichter | I'm not sure if my target uses Eclipse or Netbeans (probably Eclipse). |
| 11:12 | ttmrichter | Are these plugins any good? |
| 11:12 | ttmrichter | As in do they provide a REPL, build suites, etc.? |
| 11:13 | jkdufair | I have to say, Clojure Box is very very nice |
| 11:13 | jkdufair | works out of the... well, box |
| 11:13 | clgv | CCW has a repl. but the one in the stable version feels a bit odd when using ;) |
| 11:13 | jkdufair | Emacs is not hard to learn |
| 11:14 | jkdufair | And Emacs can be pretty clicky and guified these days if that's what they prefer |
| 11:14 | ttmrichter | jkdufair: Given that I can't stand emacs myself, I rather doubt I'm in a position to tell someone else to use it. |
| 11:15 | jkdufair | Alas |
| 11:17 | jkdufair | That's exactly how I work in Emacs |
| 11:17 | ttmrichter | When I say "window" I mean "a window with a shell". |
| 11:17 | ttmrichter | Not a window plied to the gills with bucky-bits and wrist-torture. ;) |
| 11:18 | jkdufair | M-x shell |
| 11:18 | jkdufair | there's a window with a shell :-) |
| 11:18 | ttmrichter | And the window with the ABE editor? |
| 11:18 | ttmrichter | (ABE stands for "Anything But EMACS".:) |
| 11:18 | jkdufair | Oh. I don't have that. |
| 11:19 | ttmrichter | I do. It's called xterm (or something equivalent like gnome_terminal or the like). :D |
| 11:19 | jkdufair | paredit mode is the real juice. it lets the developer THINK in s-expressions and not in text |
| 11:21 | jkdufair | my brain is too small to think at a character level |
| 11:22 | Chousuke | I don't think I think in either characters or s-exprs, but since you're manipulating s-expressions anyway there's no reason not to use something like paredit |
| 11:23 | jkdufair | Yeah, I don't suppose I think in s-exprs, per se, but I think about manipulating them |
| 11:35 | TimMc | ttmrichter: I finally went over to the dark side and learned Emacs: http://www.brainonfire.net/blog/emacs-n00b-start/ |
| 11:35 | zoldar | I'm a vim user who recently switched to emacs - with viper-mode it's really fine experience |
| 11:36 | zoldar | the only pain I have recently, is working with mixed html/js content - this one really sucks :( |
| 11:37 | zoldar | there's nxhtml for emacs but it doesn't play too well with newer versions |
| 11:38 | TimMc | zoldar: I try to avoid embedding CSS and JS in HTML beyond trivialities; remembering to escape < and > as SGML hurts my brain. |
| 11:39 | zoldar | TimMc, I also try to reduce it to the minimum, but even then, it's a bit of a bumpy ride |
| 11:40 | ttmrichter | TimMc: I've learnt emacs. I just don't like it. :) |
| 11:40 | TimMc | heh |
| 11:40 | TimMc | It took me three tries over the course of 2 years. |
| 11:41 | TimMc | Paredit mode is fantastic, and that's the only reason I use the thing. |
| 11:41 | TimMc | Nothing else compares in that regard. |
| 11:42 | clgv | so well I have the changed version running now and it's actually a bit slower... :( |
| 11:42 | clgv | no reflection-warnings though |
| 11:42 | TimMc | clgv: >_< |
| 11:43 | clgv | yeah well, the question is only: can I improve it or do I just delete that branch and go on somewhere else ;) |
| 11:46 | clgv | the strange thing is that most of the time is spent in calculating the single probabilities which was done almost the same before. |
| 11:53 | hv | ,(let [c Integer] (class c "10")) |
| 11:53 | clojurebot | java.lang.IllegalArgumentException: Wrong number of args (2) passed to: core$class |
| 11:53 | hv | oops |
| 11:53 | hv | ,(let [c Integer] (new c "10")) |
| 11:53 | clojurebot | java.lang.IllegalArgumentException: Unable to resolve classname: c |
| 11:55 | TimMc | Yeah, classes aren't exactly first-class. :-/ |
| 11:55 | zoldar | ,(let [c Integer] (clojure.lang.Reflector/invokeConstructor c (object-array [4]))) |
| 11:55 | clojurebot | 4 |
| 11:56 | raek | there are class objects (as c above), but new is a special form and does not evaluate its first argument |
| 11:56 | TimMc | Why would it not? |
| 11:57 | raek | the compiler wants to decide which constructor to use at compile time |
| 11:58 | raek | the byte code for instantiating a class is just an instruction or two |
| 11:59 | hv | raek: in my situation I need to decide at runtime, so is there another fn or macro that helps here? |
| 12:00 | zoldar | hv: you can use reflection, but bear in mind that it can be a significant performance hit |
| 12:00 | raek | hv: if you need it at run time, reflection is a good option (and the Reflector class presents a fairly simple API to do it) |
| 12:01 | raek | hv: in some cases, you can solve the problem with macros |
| 12:02 | raek | (assuming that you can make the decision at macro expand time) |
| 12:03 | hv | zoldar, raek: thanks, I guess I go with invokeConstructor. |
| 12:04 | TimMc | ,(new Integer (identity "15")) |
| 12:04 | clojurebot | 15 |
| 12:05 | TimMc | raek: In the above example, I'm sure the compiler did not know what constructor to use statically. |
| 12:06 | raek | IIRC, the compiler emits code that uses reflection when the class is known, but the exact constructor is not |
| 12:06 | hv | Perhaps there is a reflective-new somewhere? like: (defn reflective-new [c & args] (clojure.lang.Reflector/invokeConstructor c (object-array args))) |
| 12:07 | TimMc | Ah, OK. |
| 12:07 | raek | hv: where from do you get the class? |
| 12:07 | zoldar | hv: there's none (in 1.2 at least) - I have this very function in my personal toolbox |
| 12:08 | hv | zoldar: hmm, what do you call it? |
| 12:08 | zoldar | make-instance |
| 12:10 | zoldar | hv: however, if you gave more context about what you want to do, folks here could suggest some better solution |
| 12:11 | raek | hv: sometimes you can get away with something like (defmacro instantiate-class-by-name [name & args] (let [c (name->class c)] `(new ~c ~@args))) |
| 12:11 | raek | in case you know the class, but have the name in some other form |
| 12:12 | zoldar | reak, are you sure that this macro will work? |
| 12:12 | zoldar | raek, argh, sorry |
| 12:12 | hv | raek: what is name->class |
| 12:12 | hv | ,name->class |
| 12:12 | clojurebot | java.lang.Exception: Unable to resolve symbol: name->class in this context |
| 12:13 | raek | lets assume that you have the class name in string form, then name->class would be the clojure function 'symbol' |
| 12:13 | amalloy | i find myself using (juxt identity more-functions) a lot. i want to write myself a little function wrapping that up, but i can't decide if it should be like (def annotate (partial juxt identity)) or (defn decorate [obj & fns] ((apply juxt identity fns) obj)) |
| 12:14 | amalloy | ie, both names make sense, and it could plausibly either return a function or immediately apply itself to a value |
| 12:14 | raek | hv: the point is, as long as you can make some clojure code that can construct the class name as a symbol, and then invoke that code in the macro, you can do all this at compile time |
| 12:15 | hv | raek: thanks, I have to think about it. Right now I am not sure if I can know the class name at compile time. |
| 12:16 | raek | the exreme case of runtime would be if the class name is something that the user enters into a dialog box in the middle of program execution |
| 12:17 | raek | in that case you would need reflection |
| 12:17 | raek | in a case where you want to read the class name from a file at application start up, you can use macros |
| 12:18 | raek | so maybe "startup time" and "in-the-middle-of-execution-time" would be better terms :-) |
| 12:18 | hv | raek: I see, thanks. |
| 12:19 | amalloy | raek: it sounds pretty hard to read at startup time if the user is using an aot jar file though, right? |
| 12:20 | raek | hrm. good point. |
| 12:21 | amalloy | but if they have an actual clojure compiler, then yes, it can be pretty cool to have the compile cycle involve reading config from disk :) |
| 12:26 | TimMc | amalloy: That's almost as good as popping up a modal dialog from the macro to ask the user! |
| 12:26 | TimMc | Someday I will hold a Macro Abuse Competition. |
| 12:28 | amalloy | TimMc: you will have to work pretty hard to beat even the iocc, and they barely have macros available |
| 12:29 | TimMc | I'm not restricting the concept to obfuscation. |
| 12:34 | Adamant | put fear in the hearts of the unbelievers |
| 12:35 | Adamant | (I joke, of course) |
| 12:38 | Bennyl | Hi I am trying to debug some code that I am writing I use swank with debug enabled and I can di breakpoint but cannot step into/ out etc, can it be done? |
| 12:41 | @rhickey | the latest push makes it so that fns only get code to support metadata if they have metadata when defined |
| 12:41 | @rhickey | metadata support was a significant part of the code for small fns, and rarely used |
| 12:43 | fliebel | rhickey: Does this mean one cannot attach metadata to a fn later? |
| 12:43 | amalloy | fliebel: you already can't, because fns are immutable, right? |
| 12:44 | @rhickey | fliebel: right, not unless it has metadata when defined |
| 12:44 | @rhickey | amalloy: I presume he meant with-meta semantics |
| 12:44 | fliebel | right |
| 12:44 | TimMc | Is it a memory consideration? |
| 12:45 | amalloy | hm. so (with-meta (fn [] 10) {::whatever "value"}) won't be legal either? |
| 12:46 | TimMc | Or (defn annotate [f] (with-meta f {...})) |
| 12:46 | fliebel | IMO, unless there is a huge gain, I don't think it outweighs the inconsistency and possible troubles in existing code. |
| 12:47 | @rhickey | LISP programmers know the value of everything and the cost of nothing. - Alan Perlis |
| 12:48 | amalloy | actually the only time i've put meta on functions i did it with (with-meta (memoize (fn [x] ...)) {:key value}) |
| 12:48 | amalloy | and it sounds like i won't be able to do this anymore? |
| 12:49 | @rhickey | TimMc: memory, time spent in validation |
| 12:49 | TimMc | ah |
| 12:50 | @rhickey | but one could easily make a fn wrapper that had metadata and forwarded to a wrapped fn |
| 12:51 | fliebel | rhickey: Is there any way to get etadata on an existing function now, except for wraping it in another function? ah, you're faster. |
| 12:51 | amalloy | rhickey: oh, like (defn {} meta-able [f] (fn [& args] (apply f args)))? |
| 12:51 | @rhickey | user=> (meta ^{::whatever "value"} (fn [] 10)) |
| 12:51 | @rhickey | {:user/whatever "value"} |
| 12:52 | @rhickey | just put the metadata on the fn form |
| 12:52 | amalloy | i see |
| 12:52 | amalloy | i confess i'm not very comfortable with the ^ reader macro |
| 12:53 | amalloy | as in, unfamiliar, not "it disturbs me" |
| 12:54 | TimMc | What's this double-colon nonsense? |
| 12:54 | drewr | ,[:foo ::foo] |
| 12:54 | clojurebot | [:foo :sandbox/foo] |
| 12:54 | drewr | TimMc: ^^ 'sandbox is *ns* |
| 12:55 | TimMc | Namespaced keywords? Or just a way to get keywords that start with *ns*/ ? |
| 12:55 | fliebel | rhickey: Maybe a bad idea, don't know, but would it work to make with-meta wrap the function itself? (defn with-meta [bla bla] (fn? bla (fn [] (apply ^meta bla bla))) |
| 12:57 | TobiasRaeder | anyone here tried using lancet to integrate external ant tasks into leiningen? |
| 12:57 | @rhickey | fliebel: that might be possible |
| 12:58 | @rhickey | at some cost in perf vs direct support |
| 12:58 | @rhickey | direct support is still provided if you have metadata at definition |
| 12:59 | technomancy | TobiasRaeder: yeah, the lein-tar plugin does that |
| 13:02 | TobiasRaeder | @technomanct alright, thanks a ton i will look into it :) |
| 13:04 | TimMc | holy crap I *just* got the joke behind Leiningen's name |
| 13:04 | TimMc | I am an idiot. |
| 13:09 | _fogus | TimMc: The later. ::foo ---> :my-cool-ns/foo, but nothing prevents you from just doing :my-cool-ns/foo at any time |
| 13:09 | TimMc | Interesting. |
| 13:12 | @rhickey | fliebel: ok - https://github.com/clojure/clojure/commit/2b16fee78a0517bc83dd5735ab01d3d5813b1f72 |
| 13:14 | @rhickey | so, now the change is just an efficiency difference, not (much) of a capability difference |
| 13:15 | TimMc | "Keywords are like symbols, except [... t]hey cannot contain '.' or name classes." |
| 13:15 | amalloy | $source vary-meta |
| 13:15 | sexpbot | vary-meta is http://is.gd/50kMdS |
| 13:15 | @rhickey | actually no capability difference, the wrapper can't do arity chewcking but the wrappee will |
| 13:15 | TimMc | How does ##:Integer not name a class? |
| 13:16 | TimMc | ,:Integer ; rather |
| 13:16 | clojurebot | :Integer |
| 13:16 | amalloy | TimMc: the same way that "Integer" doesn't name a class: only ##(Class/forName "Integer") does |
| 13:16 | sexpbot | java.lang.ClassNotFoundException: Integer |
| 13:17 | amalloy | rhickey: so (meta (fn [])) will return {}, right? |
| 13:18 | @rhickey | amalloy: nil |
| 13:18 | amalloy | rhickey: then vary-meta needs updating |
| 13:18 | amalloy | doesn't it? |
| 13:18 | TimMc | amalloy: That seems vacuously true; keywords aren't classes therefore they can't name them. Or do I not understand the word "name" here? |
| 13:19 | amalloy | TimMc: i tend to agree; perhaps what is meant is that keywords can't be interned in your namespace to resolve to classnames |
| 13:19 | @rhickey | amalloy: no |
| 13:20 | TimMc | amalloy: In short, keywords only evaluate to themselves? |
| 13:20 | dnm | Does dmiller hang out here? |
| 13:21 | @rhickey | amalloy: |
| 13:21 | @rhickey | user=> (meta (vary-meta (fn []) assoc :a 1)) |
| 13:21 | @rhickey | {:a 1} |
| 13:21 | ahihi | is there a strict variant of map that doesn't collect results? (for side effects) |
| 13:21 | amalloy | rhickey: ##(vary-meta (fn[]) conj [:a 1]) |
| 13:21 | sexpbot | java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.IPersistentMap |
| 13:21 | amalloy | hrm |
| 13:22 | amalloy | ahihi: check out dorun and/or doseq |
| 13:22 | @rhickey | amalloy: expecting conj to work on something that might not have metadata is broken |
| 13:22 | amalloy | okay |
| 13:22 | LauJensen_ | Morning :) |
| 13:23 | ahihi | well, I guess I'm just looking for a predefined name for (comp dorun map) :) |
| 13:23 | amalloy | i assumed it was working before and broken after, but if it's broken before i don't mind - it is a bad idea, as you say |
| 13:23 | ahihi | doseq's for-style syntax seems a bit verbose since you have to introduce a variable |
| 13:23 | amalloy | ahihi: depends what you're using it for |
| 13:24 | amalloy | if you don't *really* have to use map in the first place, then dorun/map is more verbose than doseq |
| 13:24 | ahihi | basically just (dorun (map f xs)) |
| 13:24 | amalloy | ahihi: sure, if f already exists |
| 13:24 | ahihi | it does |
| 13:25 | amalloy | but compare (dorun (map #(do stuff to %) args)) to (doseq [a args] (do stuff to a)) |
| 13:25 | ahihi | sorry, the verbosity remark was only about this case, not in general |
| 13:25 | amalloy | anyway whatever, use whichever makes more sense |
| 13:25 | amalloy | yeah, i'm sorta defending doseq for no particular reason |
| 13:26 | ahihi | :) |
| 13:26 | ahihi | well, thanks for the pointers |
| 13:27 | amalloy | ahihi: no problem. here's another: 0x4ba330f8 |
| 13:28 | chouser | rhickey: I'm curious what prompted the fn metadata change. |
| 13:29 | @rhickey | chouser: I built just the Java bits of Clojure the other day, by hand, with javac - 5 secs, 500k, made me sad |
| 13:29 | @rhickey | :) |
| 13:30 | drewr | cinc is nigh? |
| 13:30 | @rhickey | chouser: but given the latest changes the ony change is less waste compiling, loading, verifying code for metadata support that no one will use |
| 13:30 | @rhickey | chouser: i.e. with wrapper gen, no loss of metadata for fns |
| 13:30 | @rhickey | just no per-fn code to support it |
| 13:33 | @rhickey | chouser: in general I was looking for ways to slim donw CLojure and improve startup time, as more people look to use it as a library, on Android etc |
| 13:34 | @rhickey | we need a way to strip out all the interactive stuff when delivering as a runtime library |
| 13:36 | fliebel | rhickey: Great, so you implemented my auto-wrapper idea? |
| 13:36 | @rhickey | yup, done |
| 13:36 | cemerick | rhickey: which is more common than not outside of "real" development -- updating a production webapp and such via a REPL is cute, but impractical most of the time. |
| 13:37 | @rhickey | cemerick: well, not so much losing the repl as losing, e.g. doc and arglist metadata, but yeah, could strip compiler and ASM too |
| 13:38 | @rhickey | I implemented lazy fn loading, helps with startup time somewhat |
| 13:38 | @rhickey | but no big wins anywhere - we suffer from class-per-fn and verification of same |
| 13:39 | fliebel | rhickey: Wait, aren't functions defined with meta already? user=> (meta (defn a [] 3)) |
| 13:39 | fliebel | {:ns #<Namespace user>, :name a, :file "NO_SOURCE_PATH", :line 3, :arglists ([])} |
| 13:39 | amalloy | fliebel: ##(meta (fn[])) |
| 13:39 | sexpbot | ⟹ nil |
| 13:40 | @rhickey | fliebel: that's the metadata of the var |
| 13:40 | fliebel | Ah, of course.... |
| 13:42 | ataggart | Regarding android space/time trade-off, the switch bytecode emitted from case can currently have up to 8k entries since it always uses table instead of lookup. Might not be significant. |
| 13:45 | @rhickey | ataggart: thanks for that patch! I hope to get some time to look at it soon |
| 13:46 | ataggart | rhickey: the code is much longer than I anticipated when first embarking on it. |
| 13:46 | __name__ | is the clojure book from pragmatic programmers still valuable for 1.2? |
| 13:49 | ataggart | rhickey: have you had a chance to look at the compiler/reflector patch on CLJ-445? |
| 13:50 | technomancy | __name__: sure |
| 13:51 | __name__ | Is it any good? The example chapters were a bit short to judge, but I liked what I saw |
| 13:52 | khaliG | is putting a form at the top level of a clj file a good way to ensure it's evaluated, and only once? |
| 13:52 | technomancy | __name__: I liked it a lot. it's short, but to the point. |
| 13:54 | khaliG | or shall i use an init atom? |
| 13:55 | amalloy | khaliG: that ensures it's evaluated exactly once, but you may want to be careful if you ever AOT-compile |
| 13:55 | amalloy | because it will be evaluated at compile time as well as runtime |
| 13:55 | khaliG | ooh, i see. ok thanks. |
| 13:56 | amalloy | (disclaimer: the above is probably an unintentional oversimplification but it's been correct enough for me in the past) |
| 13:57 | khaliG | well tell me if there is a better way to do this.. but hte first time i call get-registry, it should open up a file and read some data into a map. Subsequent calls to get-registry ought to return that map. |
| 13:58 | amalloy | khaliG: memoize |
| 13:58 | khaliG | amalloy, sounds good! |
| 13:58 | amalloy | (def get-registry (memoize (fn [] (do expensive stuff)))) |
| 14:15 | konr | Is there a doseq-like function that collects the results of every interaction? |
| 14:16 | TimMc | konr: You can force a for. |
| 14:17 | TimMc | (dorun (map ...)) or (dorun (for ...)) |
| 14:17 | konr | oh, I got it! Thanks, TimMc |
| 14:17 | TimMc | konr: Wait! |
| 14:17 | amalloy | TimMc: that doesn't collect the results |
| 14:17 | TimMc | yeah |
| 14:17 | amalloy | doall |
| 14:17 | TimMc | That's the one. |
| 14:18 | TimMc | konr: http://clojuredocs.org/clojure_core/clojure.core/doall <-- good site for finding related functions |
| 14:18 | amalloy | $findfn [1 2 3 4] [1 2 3 4] |
| 14:18 | sexpbot | [clojure.set/union clojure.set/intersection clojure.set/difference clojure.core/list* clojure.core/time clojure.core/dosync clojure.core/distinct clojure.core/lazy-cat clojure.core/sequence clojure.core/with-loading-context clojure.core/vec clojure.core/concat clojur... http://gist.github.com/849677 |
| 14:18 | amalloy | hm. not as useful as i'd hoped |
| 14:18 | amalloy | but doall is in there! |
| 14:25 | redinger | Clojure Conj 2011 information has been posted: http://clojure-conj.org |
| 14:27 | swart | so I've more or less got my clojure/emacs env set up (modulo firewall issues), but now I'm a bit confused about the dev process itself |
| 14:28 | swart | I have a repl, I have a buffer with a file in it, and I have various packages I can manage with lein. but how do I load packages into the repl and interactively update my code based on changes I make there? |
| 14:29 | amalloy | swart: do you have a swank server running? |
| 14:29 | swart | yes |
| 14:29 | amalloy | C-c C-k will feed the contents of the current buffer to the repl |
| 14:29 | swart | ah ok |
| 14:30 | swart | I saw C-c C-k and I confused it with C-c C-j to compile the buffer |
| 14:30 | amalloy | see also the many handy things under the SLIME toolbar like C-c C-d C-d to see docstring for var at point |
| 14:31 | swart | ok. I'm running emacs -nw due to the firewall problems but I think I'll have a look |
| 14:31 | swart | clearly I need to read more docs :) |
| 14:32 | amalloy | swart: ah. there's a way to get at the toolbar in -nw, and while overall i approve of -nw i don't use it that often in practice |
| 14:33 | swart | M-` does the trick |
| 14:33 | amalloy | sweet |
| 14:33 | lpetit | rhickey: hello. can you explain more what is behind "lazy fn loading" ? Does it mean that not all fn code will be JIT compiled and/or loaded in memory until it is first evaluated (in a callable or argument position) ? |
| 14:33 | amalloy | lpetit: he left |
| 14:33 | lpetit | amalloy: oh ok, thx |
| 14:33 | lpetit | amalloy: do you understand what's behind "lazy fn loading" ? |
| 14:34 | amalloy | your guess is about the same as my guess was |
| 14:34 | hiredman | lpetit: my guess is a change to how the code for namespaces is generated |
| 14:34 | lpetit | Currently if there's an area where we pay for what we don't necessarily use, it's the fact that by means of transitive deps, all code of all fns constituting one's application is loaded on startup time. |
| 14:35 | lpetit | hiredman: hmm, is your guess even more precise than that ? |
| 14:36 | hiredman | defns maybe hold a reference to a instance of FnThunkLoader instead of the instance of the function |
| 14:36 | lpetit | e.g. : unless the Android underlying framework uses lazy loading heavily itself and an Android app benefits from it out of the box (presumably via wrapper java classes), then if the android app has 20 screens, and the user only uses one, chances are the code for the 20 screens is loaded on startup, everytime |
| 14:37 | hiredman | FnThunkLoader loads the fn it puts to via something like Class/forName and caches it |
| 14:37 | hiredman | points |
| 14:37 | amalloy | hiredman: both devious and useful |
| 14:37 | hiredman | lpetit: *shrug* until android gets a real gc, I doubt it is viable anyway |
| 14:38 | hiredman | that is a guess, I just scanned the diff |
| 14:38 | lpetit | hiredman: of course, I know you can generalize from my example. Same problem for ccw with OSGi, for example. |
| 14:39 | lpetit | hiredman: the latest version of Android still not ok wrt to this problem? |
| 14:39 | hiredman | lpetit: don't follow it too closely, but I don't imagine it is a priority for google |
| 14:41 | lpetit | hiredman: granted |
| 14:41 | hiredman | oh, and then fnthunkloader sets the value of the var root to the instance of the class |
| 14:44 | lpetit | so, somehow, requiring a namespace would now just create vars full of "lazy thunks" of fn ready to load (compile?) bytecode (from disk) ? |
| 14:47 | _fogus-away | Whoa! http://clojure-conj.org |
| 14:48 | konr | What's the clojuresque way of dealing with queues, dequeuing and multiple threads? (dosync (let [new @foo] (alter foo rest) (first new)))? |
| 14:50 | brehaut | konr: if you want a queue then clojure.lang.PersistentQueue might be what you are after |
| 14:54 | hiredman | pq doesn't block |
| 14:55 | ataggart | cemerick: http://dev.clojure.org/jira/browse/CLJ-426 |
| 14:58 | brehaut | hiredman: would the java.util.concurrent.BlockingQueue be a better choice then? |
| 14:59 | hiredman | depends if you want to block (I almost always do) |
| 14:59 | brehaut | hiredman: i have no idea on his usecase |
| 14:59 | ataggart | how about seque? |
| 15:00 | Dranik | is anyone from Belarus here? |
| 15:04 | OlegYch | me |
| 15:06 | cemerick | ataggart: looks like a sizable job :-) |
| 15:07 | ataggart | it was, but the performance gains were worth it. |
| 15:07 | ataggart | plus being able to use enums will be nice |
| 15:08 | ataggart | I found your blog post when I was embarking on it. your and cgrand's comments pointed me in the right direction. |
| 15:09 | cemerick | ataggart: looks like you're evaluating e.g. static fields and such? |
| 15:10 | cemerick | er, maybe not |
| 15:10 | ataggart | evaling the symbol ns to see if it's an enum class |
| 15:10 | ataggart | then evaling the whole thing to see if it's also the same enum class |
| 15:10 | ataggart | I wanted to avoid inadvertently screwing something up, hence the ns eval first |
| 15:11 | cemerick | sure |
| 15:11 | cemerick | ataggart: did you take a shot at static final fields, or is that out of scope? |
| 15:12 | ataggart | ah, no I had forgotten. It should be perfectly doable so long as the values are themselves consistently hashed. |
| 15:12 | ataggart | I'll get on it now. |
| 15:13 | cemerick | ataggart: I suppose requiring the fields to be final is a little too persnickety. |
| 15:13 | ataggart | I can reflectively find out |
| 15:13 | ataggart | though it would be eaiser if the clojure.reflect ns was available |
| 15:13 | ataggart | instead, I can probably just make calls to clojure.lang.Reflector |
| 15:13 | ataggart | (the new one) |
| 15:14 | cemerick | True, but that restriction will cause frustration; a lot of Java constants are declared static, but not final. |
| 15:14 | ataggart | not much of a constant then |
| 15:14 | ataggart | examples? |
| 15:14 | clojurebot | examples is http://en.wikibooks.org/wiki/Clojure_Programming/Examples/API_Examples |
| 15:16 | cemerick | ataggart: perhaps "a lot" was an exaggeration ;-) |
| 15:17 | ataggart | cemerick: there is the concern that someone will want to switch on the actual symbols. |
| 15:19 | ataggart | a usecase that might occur when writing macros conditionally calling java fields/methods |
| 15:20 | cemerick | ataggart: Sneaky. I'd say 'Absurd/Coincidence would be reasonable in such cases. |
| 15:20 | cdddr | $findfn [1 nil 2 3 nil] [1 2 3] |
| 15:20 | sexpbot | [] |
| 15:21 | amalloy | &(keep identity [1 nil 2 3 nil]) |
| 15:21 | sexpbot | ⟹ (1 2 3) |
| 15:22 | cdddr | I was thinking (remove nil? [list]) :) |
| 15:22 | cdddr | More explicit. |
| 15:23 | amalloy | cdddr: meh. are you producing this seq from a (map)? |
| 15:24 | cdddr | Yes. I keep thinking there was probably a better way. |
| 15:24 | amalloy | &(keep :initials [{:name "amalloy" :initials "akm"} {:name "cdddr" :interests "caaadr"}]) |
| 15:24 | sexpbot | ⟹ ("akm") |
| 15:25 | ataggart | cemerick: The current doc for case notes that nothing need be quoted, so there's a backwards compatability issue with requiring symbols-as-symbols to be quoted. Of course that's also the case with the new enum functionality. Hmm... |
| 15:25 | amalloy | ie, keep folds together the map and the remove |
| 15:25 | cdddr | Aaaah. |
| 15:26 | cdddr | Yeah, this is definitely better. |
| 15:26 | __name__ | $source keep |
| 15:26 | sexpbot | keep is http://is.gd/2Dlrr4 |
| 15:27 | cemerick | ataggart: Once things get resolved, symbols become second-class. I think that's a reasonable tradeoff, given the prevalence of enums, static fields, etc. |
| 15:27 | __name__ | this code is scary :( |
| 15:27 | cemerick | ataggart: If "constant" vars are in play as well, then that's doubly true IMO. |
| 15:28 | ataggart | cemerick: fair point. |
| 15:29 | amalloy | __name__: clojure.core is optimized for speed rather than legibility |
| 15:29 | amalloy | if you were writing keep yourself, you would do like (defn keep [f coll] (remove nil? (map f coll))) and that would be it |
| 15:30 | __name__ | $source remove |
| 15:30 | sexpbot | remove is http://is.gd/ttw47S |
| 15:30 | amalloy | or if brehaut had his way, (def keep (comp (partial remove nil?) map)) |
| 15:30 | ataggart | cemerick: so strings, numbers, quoted symbols, evaluated constants, enums, and clojure collections of the foregoing. |
| 15:30 | __name__ | :) |
| 15:30 | brehaut | amalloy: when did i become the champion of point free :P |
| 15:31 | amalloy | brehaut: i just like to blame my crazy ideas on the haskell community |
| 15:31 | brehaut | haha |
| 15:31 | __name__ | amalloy: the standard functions just keep scaring me |
| 15:31 | amalloy | nobody ever wants to stand up for them |
| 15:31 | brehaut | amalloy i think the haskell community would be offended if they thought i was a spokesperson for them here :P |
| 15:31 | amalloy | heh |
| 15:32 | cemerick | ataggart: seems entirely reasonable to me. "Constant" is a fungible term, of course. "Values as evaluated at compilation time" perhaps. |
| 15:33 | amalloy | __name__: try implementing them yourself from reading the docstrings. it will probably be more enlightening than trying to follow the source |
| 15:33 | ataggart | cemerick: agreed, though it should probably go in as a separate enhancement. There's enough shoved into that ticket already. |
| 15:35 | ataggart | cemerick: In any case, I'll get started on a separate patch with those changes, and see what Rich, et al. have to say. |
| 15:35 | cemerick | ataggart: Sounds good, let me know if you need help (FWIW). Thanks for taking that on. :-) |
| 15:36 | ataggart | cemerick: heh, np. Gave me a chance to delve into jvm bytecode. |
| 15:40 | Despite | What is the definition of "point" in "pointfree"? |
| 15:41 | amalloy | Despite: i think the rough answer is "named bindings" |
| 15:41 | Despite | great, thanks |
| 15:41 | brehaut | Despite, amalloy: short hand for http://en.wikipedia.org/wiki/Least_fixed_point i think |
| 15:42 | kencausey | http://www.haskell.org/haskellwiki/Pointfree See point 1 |
| 15:45 | brehaut | kencausey: hah jeremy gibbons (mentioned in 2) is completely insane with the point free :) |
| 15:46 | Despite | i like that style |
| 15:46 | Despite | I wonder how far you can take it |
| 15:46 | brehaut | Despite: you can write entire programs without mentioning the arguments to anything with the right operators |
| 15:47 | TimMc | Just like you can write entire programs with only lambdas. |
| 15:48 | shachaf | Despite: http://en.wikipedia.org/wiki/SKI_combinator_calculus |
| 15:50 | amalloy | yeah, you can take it arbitrarily far |
| 15:50 | brehaut | its better as a sometimes thing though |
| 15:51 | _fogus | https://github.com/fogus/skiing |
| 15:51 | brehaut | in particular, if naming the variables would add clarity, then you should. if the function is general enough that the name is completely laking information then point free can be a win |
| 15:53 | Despite | Hrmm, guess i need to read a book. I get lost when combinators come up. |
| 15:55 | brehaut | Despite: start experimenting in a repl |
| 15:56 | shachaf | Despite: When combinators come up? But those are the simplest types of functions! :-) |
| 15:57 | shachaf | A Factor programmer I know has said that pseudo-"point-free style" can be carried much farther in Factor without losing clarity. |
| 15:59 | brehaut | shachaf: father than in what? |
| 15:59 | shachaf | brehaut: Haskell in that context. |
| 15:59 | brehaut | thats quite an astounding statement |
| 15:59 | shachaf | brehaut: Why? |
| 16:00 | brehaut | because haskell is extremely good at point free |
| 16:00 | shachaf | The normal way of expressing things in a concatenative language is in terms of stack manipulation, with no names unless you explicitly want them. |
| 16:06 | _fogus | brehaut: This series of posts was an outstanding look into that approach http://www.codecommit.com/blog/cat/the-joy-of-concatenative-languages-part-2 |
| 16:06 | brehaut | _fogus: cheers |
| 16:08 | TobiasRaeder | @technomancy i checked out lein-tar but i guess i didn't make myself too awefully clear :/ |
| 16:08 | TobiasRaeder | @technomany what i was really for was integrating some "ant-macro" (not sure about the term) |
| 16:09 | TobiasRaeder | @technomancy it's supposed to be imported via import task but i wasn't straight away to get the import task to work with lancet |
| 16:10 | dnolen | how do stack-oriented PLs deal w/ concurrency? |
| 16:13 | shachaf | dnolen: What does that mean? |
| 16:14 | shachaf | dnolen: How does any language deal with concurrency? |
| 16:17 | dnolen | shachaf: thread, green threads, locks, data structures, STM, thread pools, co-routines, explicit/implicit data parallelism, etc. does the stack oriented paradigm make these more tedious? I see these kinds of things addressed in FP literature, but I haven't seen anything like that for stack-oriented PLs. Just curious. |
| 16:19 | shachaf | dnolen: I don't think it's really a property of the fact that a language is a stack language. |
| 16:21 | dnolen | shachaf: not saying that, just curious about the lack of literature, or existence of features in the stack PLs I've (admittedly in a surface way) perused. |
| 16:27 | bartj | Regarding namespace variables |
| 16:27 | bartj | one can access them using: imported-namespace/variable |
| 16:27 | bartj | but, when one does it via an (eval (symbol namespace variable)) it fails! |
| 16:28 | bartj | can anyone please have a look at the code in this paste: |
| 16:28 | bartj | http://pastie.org/1622241 |
| 16:28 | bartj | which shows the above problem of accessing namespace variables |
| 16:28 | bartj | using (eval (symbol ....)) |
| 16:34 | bartj | anyone ? |
| 16:35 | hiredman | bartj: you are missing the difference between vars and symbols |
| 16:35 | amalloy | yes, and also (symbol us "president") doesn't work. us isn't defined; it has nothing to do with eval |
| 16:36 | bartj | sorry that was a typo |
| 16:37 | bartj | amalloy, I have corrected the paste: http://pastie.org/1622241 |
| 16:39 | bartj | hiredman, can you please tell me what I am missing ? |
| 16:40 | hiredman | there is no local binding for us and no var |
| 16:40 | raek | bartj: without using eval: (-> (symbol country f) resolve deref) |
| 16:40 | amalloy | i don't think the issue is symbols vs vars, it's more about eval being in a null lexical context, isn't it? |
| 16:41 | raek | bartj: but the most important question is: why do you use namespaces and vars, instead of, say, a map? |
| 16:41 | bartj | you mean something like: {def president {:us "obama" :uk "cameron"}) ? |
| 16:41 | raek | yes |
| 16:41 | bartj | because there are more than 20 different variables |
| 16:42 | bartj | in each country |
| 16:42 | hiredman | amalloy: no, he assumes that when he sees the symbol 'us' there must be a var backing it |
| 16:42 | hiredman | so he can refer to in an expression like (symbol us ...) |
| 16:42 | amalloy | hiredman: that was my objection to; he updated the gist to be using "us" |
| 16:43 | amalloy | and claims to still be having trouble |
| 16:43 | bartj | strangely, it works on the REPL ! |
| 16:43 | hiredman | no it doesn't |
| 16:44 | raek | I think amalloy's observation explains it pretty well. the form sent to eval is not evaluated in the lexical context where the eval call is |
| 16:44 | bartj | raek, may I ask, why not? |
| 16:45 | raek | (let [x 1] (eval 'x)) ; <-- x is not available in the scope where the form is evaled |
| 16:46 | bartj | oh no! I thought it should be, because it is defined right before in the let |
| 16:46 | amalloy | bartj: there are a lot of reasons eval is not the right tool to use for many jobs |
| 16:46 | amalloy | this is one of them |
| 16:48 | dnolen | nice, lisp 50 years ago, http://funcall.blogspot.com/2011/03/fifty-years-ago.html |
| 16:49 | raek | I think this is a result of how closures are implemented |
| 16:50 | raek | when the compiler sees (eval ...), it cannot know which variables it closes over |
| 16:50 | jkrueger | i stumbled over this as well a while back. i tried to write a backend for couchdb and wanted to evaluate functions from the db dynamically in a certain context. what would be the proper way to do this then ? |
| 16:52 | HK_ | I am a long time C# developer (since 2002 when it came out) who has discovered Clojure (and Lisp for that matter). I absolutely love the (almost non-existent) syntax, it's so elegant and it's unbelievable how many "frameworks" are all of the sudden unnecessary to achieve something. |
| 16:53 | HK_ | I think Rich has done a very good job designing and implementing Clojure, but one think I don't understand is why the keywords have to be so cryptic. Why "defn", "fn" and all the other ugly keywoards? Why not just use "function" and if that is too long just "F". F would stand out and be very short. |
| 16:53 | swart | fn works for me |
| 16:54 | ohpauleez | HK_: defn is a macro for making a function (using fn) and def'ing it using (def) |
| 16:54 | swart | besides you can change the syntax to suit yourself |
| 16:54 | ohpauleez | more or less |
| 16:54 | ssideris | HK_: but the nice thing is that the language is flexible enough to replace the keywords! |
| 16:54 | swart | angle brackets ftw! |
| 16:54 | HK_ | would replacing the keywords make the code slower? |
| 16:55 | ssideris | HK_: no, you can make it happen at compile time with macros |
| 16:55 | ohpauleez | HK_: nope, not necessarily |
| 16:55 | lucian | HK_: i find fn very nice |
| 16:55 | bartj | jkrueger, I am extremely clueless as well |
| 16:55 | lucian | much better than function |
| 16:55 | HK_ | ok, good to know, thanks. so i guess the cryptic keywords are just legacy from other lisps? |
| 16:55 | lucian | HK_: partly |
| 16:56 | technomancy | "function" is such a long word that I have to use Emacs render-time magit to make JS bearable. |
| 16:56 | technomancy | *magic |
| 16:56 | technomancy | dang |
| 16:56 | swart | at least it uses first and rest instead of car and cdr |
| 16:56 | ohpauleez | As stated, macros expand at compile time, and any code you really need to perform better than clojure enables (which I think you'd be hard pressed to find), you can write in java and then wrap in clojure as you need |
| 16:56 | jkrueger | bartj: one thing about ruby i liked was the ability to completely control the environment in which a block of code gets executed |
| 16:56 | swart | mostly I think the postfix notation is confusing to new developers |
| 16:56 | lucian | technomancy: i really like CoffeeScript's -> |
| 16:57 | jkrueger | it allowed from some pretty nifty stunts |
| 16:58 | HK_ | @swart: this is what i meant. he used first and rest instead of car and cdr, but i wished he had done the same for the other keywords |
| 16:58 | technomancy | lucian: my JS use predates coffeescript, but I'm totally going for that next time I need to do web work. |
| 16:58 | ohpauleez | jkrueger: You can use binding forms to achieve the same thing in clojure, no? |
| 16:58 | technomancy | quite sane |
| 16:58 | jkrueger | swart: who could forget good old cddadr :) |
| 16:59 | lucian | HK_: others than fn? |
| 16:59 | swart | yeah car and cdr have their appeal |
| 16:59 | jkrueger | ohpauleez: apparantly not when you are using eval |
| 17:00 | HK_ | i am still a total newbie, i don't know most clojure keywords. partly because they are hard to remember because they are so cryptic |
| 17:00 | lucian | swart: noooooooooo |
| 17:00 | swart | :) |
| 17:00 | lucian | HK_: could you give examples? i'm not much of a lisper either |
| 17:00 | swart | I like the symmetry is all |
| 17:01 | ohpauleez | jkrueger: ahh sorry, I was missing the context. I ran into a similar issue when I started working on net-ns (which I had since dropped) and realized it seemed more of a characteristic of bad design than of a real need for the project |
| 17:01 | swart | they told me in uni that they stood for "contents of address register" and "contents of data register" but I think that's incorrect. at least according to something I read online somewhere |
| 17:02 | jkrueger | HK_: I agree with you that some things are short and that may seem strange. Functions like split-at or drop-while have full names. But you tend to use "fn" so much, that it just deserves a shorthand. The same goes for a few other functions/special forms. |
| 17:02 | swart | you can always use a lambda character. unicode is ubiquitous now |
| 17:02 | jkrueger | HK_: independent of lisp folklore |
| 17:03 | HK_ | i guess, it's just personal taste |
| 17:03 | swart | not entirely. language idioms are important for sharing code |
| 17:03 | HK_ | i come from the imperative OO world where everything is very descriptive |
| 17:03 | swart | that's why I can't handle C#. too many ways to doe the same thing |
| 17:03 | lucian | HK_: so do i. what exactly bothers you in clojure's keywords? |
| 17:03 | lucian | swart: meh, that's now why i dislike it |
| 17:03 | bartj | raek, (-> (symbol country f) resolve) gives a NullPointerException ? |
| 17:04 | lucian | i do like it more than i like java |
| 17:04 | jkrueger | swart: i hope you never had to write a c++ program |
| 17:04 | HK_ | what i said earlier. i find the naming not consistent, so being a beginner i find it harder to remember |
| 17:04 | lucian | jkrueger: that's got to be the world's worst langauge |
| 17:04 | swart | I learned c++ a couple of years ago, but I've been a smalltalker for 20 odd years |
| 17:04 | lucian | HK_: i know, i was curious what names in particular |
| 17:04 | technomancy | lucian: except for the ones that are bad on purpose |
| 17:04 | lucian | technomancy: i'm not even convinced of that |
| 17:05 | lucian | brainfuck has an elegant uniformity |
| 17:05 | swart | c++ turned out to be less horrible than I thought, but apparently it gets worse the better you understand it :) |
| 17:05 | no_mind | is there a framework in clojure that will let routes registered programatically ? Lets say a module registers the routes it want to handle... |
| 17:05 | technomancy | lucian: perhaps if you measure "most harmful" rather than "worst" |
| 17:05 | hiredman | HK_: consistent with what? |
| 17:05 | lucian | swart: try metaprogramming with templates |
| 17:05 | lucian | technomancy: i guess |
| 17:05 | jkrueger | swart: i can confirm that |
| 17:05 | lucian | swart: it's plain evil |
| 17:05 | HK_ | they should have been either just initials for keywords, e.g. F for funktion, M for macro, MM for multimethod, D for define, which could then be combined to D-F for define function |
| 17:05 | HK_ | or they could be just abbreviations like func, sync, mac |
| 17:06 | hiredman | HK_: how is that more consistent? |
| 17:06 | raek | bartj: resolve returns nil if the symbol does not corresond to any var |
| 17:06 | raek | ,(resolve 'conj) |
| 17:06 | clojurebot | #'clojure.core/conj |
| 17:06 | raek | ,(resolve 'foo) |
| 17:06 | lucian | HK_: F, M, MM and D seem worse to me than fn, macro , etc |
| 17:06 | clojurebot | nil |
| 17:06 | raek | ,(resolve (symbol "clojure.core" "conj")) |
| 17:06 | clojurebot | #'clojure.core/conj |
| 17:06 | HK_ | @lucian, i can see that |
| 17:07 | amalloy | tend to agree. uppercase is evil anyway |
| 17:07 | lucian | amalloy: yeah! CL is stupid that way |
| 17:07 | HK_ | they stand out htough |
| 17:07 | swart | and - nicer than _ |
| 17:07 | lucian | HK_: so do keywords in a decent editor |
| 17:07 | swart | camelcase cramps my fingers |
| 17:07 | amalloy | HK_: so does caadr |
| 17:07 | bartj | can anyone please point to some material re: difference b/w vars and symbols ? |
| 17:07 | amalloy | but that doesn't make it a good idea |
| 17:07 | lucian | swart: meh, i find _ ok |
| 17:08 | bartj | vars = variables |
| 17:08 | hiredman | HK_: you still have not explained your use of the word consistent |
| 17:08 | technomancy | bartj: vars are storage locations; symbols are just names |
| 17:08 | bartj | symbols are attached to vars ? |
| 17:08 | HK_ | ok, guys, you're right, it was just the first thing i noticed when i started looking at clojure, now looking at some code, i noticed there aren't that many keywords anyway so it's not that bad |
| 17:08 | swart | no a symbol is a literal |
| 17:08 | bartj | and they are attached to a var ? |
| 17:08 | swart | not necessarily |
| 17:08 | HK_ | @hiredman: right, sorry, i will now |
| 17:09 | swart | they are a value |
| 17:09 | technomancy | ,(class (name #'reduce)) |
| 17:09 | clojurebot | java.lang.ClassCastException: clojure.lang.Var cannot be cast to clojure.lang.Named |
| 17:09 | technomancy | ... |
| 17:09 | technomancy | speaking of consistency... |
| 17:09 | bartj | what use are symbols if they are just names ? |
| 17:09 | swart | like a string, but unique |
| 17:09 | bartj | blahblah is a name but doesn't reference anything :) |
| 17:10 | swart | beats using numbers for everything |
| 17:10 | swart | can be used for looking things up in maps for example |
| 17:10 | HK_ | it's inconsistent because "fn" stands for function, where it used the first (f) and last letter (n) of the word, but in the case of "def" for define, it uses the first 3 letters. "defn" for define function uses the first three letters of the first word and the initial of the second word |
| 17:10 | hiredman | or look up vars in namespaces |
| 17:10 | raek | bartj: you don't use them very often as data in programs. they are used for representing names in source code though. |
| 17:10 | lucian | HK_: so you'd prefer func and defunc? |
| 17:11 | HK_ | i'd prefer func and def-func |
| 17:11 | bartj | raek, could you provide a tiny example, please ? |
| 17:11 | hiredman | HK_: how do you come to the conclusion that the 'f' in fn is the first letter of the word 'function' and the 'n' is the last? |
| 17:11 | spewn_ | HK_: I would argue that "fn" comes from FuNction, not FunctioN. |
| 17:12 | raek | the code of the expression (inc 1) is represented as a clojure list of the symbol inc followed by the integer 1 |
| 17:12 | jkrueger | i always liked "fun" |
| 17:12 | jkrueger | it's just fun to write a fun |
| 17:12 | raek | "clojure programmers have more fn" |
| 17:13 | dnolen | HK_: don't bring too many OO naming convention assumptions w/ you. Clojure is simply built on a different legacy - Scheme, CL, Standard ML, Haskell. Clojure naming conventions draw a lot from those languages. |
| 17:13 | HK_ | because the 3 most common ways to abbreviate something are: 1) use initals of two words, like "ns" for namespace 2) use first and last letter 3) use first X letters |
| 17:13 | lucian | HK_: 4) use random Y letters |
| 17:14 | HK_ | i was just interested, thanks for the discussion, i like the vibe you guys have |
| 17:14 | amalloy | HK_: i'm dubious. things ending in "ion" are special cases; mathematicians often use defn (superscript n) for definition |
| 17:16 | amalloy | and you see fn used for function all over: "The domain of the function fn"..."Let Fn be the Fibonacci sequence"... |
| 17:16 | HK_ | so it's just convention then |
| 17:16 | amalloy | oh, i think that last one is supposed to be F<sub>n, but it's not clear |
| 17:17 | amalloy | *shrug* i think it's an arbitrary compromise between brevity and legibility |
| 17:17 | ohpauleez | amalloy: Yes, F sub n |
| 17:18 | amalloy | ohpauleez: in the context i found it, it looked like Fn, and since they didn't say "the nth element" it didn't click for me right away |
| 17:18 | ohpauleez | ahh cool |
| 17:18 | HK_ | i don't mind "fn" that much anyway, it makes sense to me because i just thought they took the first and last letter of 'function" |
| 17:18 | HK_ | something like : would have been cool for define |
| 17:18 | HK_ | or := what is used in math |
| 17:18 | amalloy | HK_: we need our : for other stuff :P |
| 17:19 | amalloy | HK_: i'm curious where you see so many first-last abbreviations. i can't think of anything off the top of my head |
| 17:19 | HK_ | GMail for Google Mail |
| 17:19 | amalloy | that's not first and last at all |
| 17:19 | lucian | it's not GL |
| 17:19 | HK_ | oh sorry |
| 17:20 | amalloy | that's first and first |
| 17:20 | HK_ | i misread it |
| 17:23 | HK_ | the word Doctor is an example |
| 17:23 | HK_ | usually writen as dr |
| 17:29 | signalseeker | cake users: how do you set the classpath for cake repl? |
| 17:30 | signalseeker | It doesn't seem to honor my $CLASSPATH |
| 17:30 | HK_ | say thanks to rich from me, he is a genious, bye bye |
| 17:36 | amalloy | signalseeker: if you're in a cake project the repl there will include the project's dependencies |
| 17:36 | signalseeker | amalloy: I am not in a cake project |
| 17:37 | signalseeker | I am using the global project I guess |
| 17:37 | amalloy | then you can futz with the settings in ~/.cake/project.clj, but you're better off not trying to manage classpath entries yourself |
| 17:37 | amalloy | what do you need a custom classpath outside of a project for? |
| 17:38 | signalseeker | I don't need a custom classpath, I just want my default $CLASSPATH to be available |
| 17:38 | signalseeker | For whatever reason, I can't import my jars in cake repl although I can access them directly through java |
| 17:39 | bartj | If I have (ns blah1.blah2.blah3 :as us) |
| 17:39 | bartj | (ns-resolve 'blah1.blah2.blah3 (symbol x)) resolves properly |
| 17:39 | bartj | but, (ns-resolve (symbol us x) doesn't |
| 17:41 | ieure | What the fuck. http://stackoverflow.com/questions/5161164/python-in-memory-object-database-which-supports-indexing |
| 17:41 | amalloy | signalseeker: the point i'm getting at that if there are jars you want to import, the "proper" way to do it is specify them as dependencies wherever your code is, so that the tools can manage the fiddly low-level classpath details |
| 17:41 | amalloy | bartj: ns-resolve wants two args |
| 17:43 | amalloy | ,(resolve 'clojure.core/first) |
| 17:43 | signalseeker | amalloy: Agree, thats a better soln. But I just want to explore some java APIs using clojure, I don't have a need of a full-fledged project yet. It seems like too much trouble to have to create a project for this purpose |
| 17:43 | clojurebot | #'clojure.core/first |
| 17:43 | bartj | amalloy, oops, I mean (resolve (symbol us x)) |
| 17:43 | amalloy | HK_: aha! like soln above :) |
| 17:44 | amalloy | signalseeker: you could ask in #cake.clj |
| 17:44 | signalseeker | I did, there is no one there right now it seems :) |
| 17:44 | amalloy | that's often the case :P |
| 17:45 | signalseeker | maybe its not a cake thing, I am new to clojure. So I could be using the wrong syntax |
| 17:45 | amalloy | lein and cake both honor some kind of java env vars, i'm just not sure what they are |
| 17:45 | amalloy | $google leiningen sample project.clj |
| 17:45 | sexpbot | First out of 451 results is: sample.project.clj at master from technomancy's leiningen - GitHub |
| 17:45 | sexpbot | https://github.com/technomancy/leiningen/blob/master/sample.project.clj |
| 17:46 | HK_ | how do i direct someone in this chat? |
| 17:46 | signalseeker | (import 'foo.c) ;; I have boo.jar with the package foo in my $CLASSPATH |
| 17:48 | HK_ | amalloy: i don't know what soln is |
| 17:48 | shafire | hi |
| 17:49 | amalloy | solution |
| 17:49 | amalloy | HK_: /msg amalloy dude you are so wrong |
| 17:50 | amalloy | my point was that he said "agree that's a better soln", meaning solution. evidence for my fn claim has arrived already! :) |
| 17:50 | HK_ | see, that's why i didn't get it |
| 17:51 | HK_ | soln isn't a great abbreviation |
| 17:51 | amalloy | $google soln set |
| 17:51 | sexpbot | First out of 30900 results is: 1.5 Solution Sets Ax = 0 and Ax = b Definition. The rank of a ... |
| 17:51 | sexpbot | http://www.math.northwestern.edu/~clark/285/handouts/soln-set.pdf |
| 18:16 | konr | The java library I'm using keeps spilling NoClassDefFoundErrors and asking for classes not available on its jar file. Is this behavior expected, or something else is going on? |
| 18:17 | ohpauleez | konr, what classes? |
| 18:17 | ohpauleez | is it because you're not including Clojure or other project dep jars on your classpath? |
| 18:19 | konr | ohpauleez: org.cyberneko.html/HTMLConfiguration, for example. All my jars are in the lib/ directory, used by lein, but note that this class is not available on any jar |
| 18:19 | konr | ohpauleez: I wonder if the .jar wasn't built properly |
| 18:20 | ohpauleez | konr: That could be it, i'd check the manifest |
| 18:20 | ohpauleez | seems very weird to me |
| 18:20 | konr | s/\//./s |
| 18:20 | ohpauleez | especially if you're managing the deps with lein/mvn-dep |
| 19:11 | cdddr | Is there a clojure builtin that swaps argument order? |
| 19:13 | ohpauleez | cdddr: can you give an example? |
| 19:13 | amalloy | cdddr: sadly i don't know of one |
| 19:13 | amalloy | -> and ->> are kinda-sorta related |
| 19:14 | amalloy | ohpauleez: i think he's looking for (fn [f] (fn [a b] (f b a))) |
| 19:14 | cdddr | amalloy: Yup. |
| 19:14 | ohpauleez | ahh ok |
| 19:14 | amalloy | i've wanted that a number of times, but it's a little hard to envision how it works for non-binary functions |
| 19:16 | cdddr | Granted, but it would be useful enough for binary ones. Or it could just be "reverse-args", though that's probably not very useful for non-binary stuff. |
| 19:16 | amalloy | maybe (fn reorder [f order] (fn [& args] (apply f (map order args)))), called like (reorder fnil {0 1, 1 0}) |
| 19:16 | amalloy | er except that's totally absurd as an implementation |
| 19:16 | amalloy | as a description it kinda explains what i was getting at, i think :P |
| 19:16 | cdddr | Yeah, it does. :> |
| 19:20 | amalloy | cdddr: i'll sketch something out later this afternoon if you're interested in a more general solution |
| 19:23 | cdddr | Sure, if I'll still be around. |
| 19:40 | cdddr | $findfn 1 inc dec [2 0] |
| 19:40 | sexpbot | [] |
| 19:42 | __name__ | good night |
| 19:42 | __name__ | $source findfn |
| 19:42 | sexpbot | Source not found. |
| 19:42 | brehaut | findfn is a sexpbot command |
| 19:42 | __name__ | eh, i should just go to sleep :) |
| 19:43 | __name__ | brehaut: yes i figured |
| 19:43 | __name__ | $findfn 2 1 |
| 19:43 | sexpbot | [clojure.core/unchecked-dec clojure.core/dec] |
| 19:43 | __name__ | neat |
| 19:43 | Despite | heh, reddit is hilarious. somebody posts a year old blog about building a game in clojure from an admited newbie, and the comments are full of arguments about how immutability is inefficient |
| 19:44 | Despite | and FP'ers "live under a rock" |
| 19:44 | cdddr | Arrgh, what was that function that worked like (fn [f1 f2] (fn [x] [(f1 x) (f2 x)])) ? |
| 19:44 | brehaut | juxt |
| 19:44 | cdddr | Oh, thanks. |
| 19:46 | Adamant | reddit is crud. |
| 19:46 | Adamant | at this point. |
| 19:47 | cdddr | Arguably, reddit has been crud for ong time now. |
| 19:47 | brehaut | i am hoping that alex payne's bloomfilter is successful |
| 19:47 | Despite | yeah, i read /r/programming only, but threads like that chase me away |
| 19:47 | Adamant | cdddr: I'd agree with that argument |
| 19:47 | Despite | But I don't have much other programming stuff to read, so I start jonesing. |
| 19:47 | Adamant | i'm not huge on Hacker News, but it's way better overall |
| 19:48 | brehaut | real programmers read lambda the ultimate. sadly im not smart enough to be a real programmer |
| 19:48 | Adamant | quality-wise, no argument, as long as you don't mind a deluge of startup stuff |
| 19:49 | Adamant | I read LtU for a while. it's good to do so, but it's very academic style. everyone needs some of that, not everyone needs it forever. |
| 19:58 | cdddr | Adamant: True that. |
| 19:59 | cdddr | And to be fair, HN is actually the one tech site that doesn't make me irritated within a few minutes of visiting. ;) |
| 20:00 | TimMc | /r/programming is long overdue for fragmentation. |
| 20:00 | TimMc | I mod /r/scheme and /r/PLT (Prog Lang Theory), which are super low traffic. :-( |
| 20:01 | TimMc | The larger subreddits are basically useless. |
| 20:01 | Adamant | cdddr: I don't agree with the the views of many Ars residents, but Ars Technica is pretty good overall |
| 20:03 | cdddr | It's been a while since I visited Ars last, and I don't remember being royally pissed, so I guess I'll give it a shot. :> |
| 20:04 | cdddr | Ahh, the joy of replacing 40 lines of code with 8. |
| 20:29 | loquaciously | i think i found a spelling error in the source; do i need to do the contributors agreement, or can i just tell someone? |
| 20:47 | TimMc | Maybe we'll never know. |
| 21:10 | tomoj | no self-joins in clojureql 1.0.1, it seems? |
| 21:12 | pdk | tell me wise sages |
| 21:12 | pdk | for folks who've read the preview of joy of clojure |
| 21:12 | pdk | would it still be worth it next to a copy of practical clojure |
| 21:12 | pdk | tempting since with this gift card i could preorder for $1 |
| 21:15 | technomancy | pdk: yes, definitely |
| 21:16 | TimMc | What is the target audience? |
| 21:16 | TimMc | _fogus: Will there be updated PDFs over time if I buy JoC? |
| 21:17 | TimMc | I'm rather fond of that approach. |
| 21:25 | amalloy | cdddr: still around? |
| 21:25 | cdddr | amalloy: Yup. |
| 21:25 | amalloy | https://gist.github.com/70f5bf52417ccdef5938 |
| 21:27 | amalloy | forces args into a vector, so won't work if you want to (apply (reorder f {0 1 1 0}) (range)) |
| 21:28 | amalloy | cdddr: is what you were looking for, yeah? |
| 21:29 | amalloy | pdk: yes, JoC is sweet |
| 21:29 | cdddr | Yeah, it is. Thank! |
| 21:29 | amalloy | i haven't read practical clojure but assert anyway with 100% confidence that JoC is better :) |
| 21:29 | amalloy | cdddr: cool. had it almost done two hours ago then a coworker showed up to pair-program :) |
| 21:30 | amalloy | it's a neat idea i played with a while ago but didn't write until someone else made me. maybe i'll start using it |
| 21:30 | cdddr | Always an annoyance at work. ;) |
| 21:30 | amalloy | ugh, what is wrong with me. so many smilies today |
| 21:30 | amalloy | gonna go home. ta-ta |
| 21:30 | cdddr | toodle-oo! |
| 22:33 | amalloy | cdddr: i was thinking about the needless repetition of {0 1, 1 0} in reorder. i could redefine it as "swaps", but not sure how i would handle something that my current scheme would express as {0 1, 1 2, 2 0}. any thoughts? |
| 22:34 | TimMc | amalloy: You're looking for a better way to express a permutation? |
| 22:34 | amalloy | TimMc: yes, i suppose i am |
| 22:34 | amalloy | you caught my gist to cdddr earlier, right? |
| 22:34 | TimMc | Yes, but I didn't know the context. |
| 22:35 | TimMc | Arbitrary permutation? |
| 22:35 | amalloy | he was looking for a HOF that wraps some other function by reording the args it takes |
| 22:36 | TimMc | HOF? |
| 22:36 | amalloy | my example allowed ((reorder map {0 1, 1 0}) [1 2] inc) => [2 3] |
| 22:36 | amalloy | higher order function |
| 22:36 | TimMc | k |
| 22:37 | TimMc | It does seem verbose. |
| 22:38 | amalloy | right. and i could make it accept just {0 1}, but then what if the user wants to reorder args in a more interesting way |
| 22:38 | TimMc | I suppose yours allows some arguments to be left alone, too. |
| 22:38 | amalloy | right |
| 22:39 | amalloy | and conceivably you could write {0 1, 1 1} to mean "pass original arg 1 as new arg0 and arg1" |
| 22:39 | TimMc | I imagine the functionality could be extended such that given a vector it would use the values as a cycle. |
| 22:40 | amalloy | hm |
| 22:40 | amalloy | what do you mean? |
| 22:40 | TimMc | (reorder map [1 2 3 0]) would be (reorder map {0 1, 1 2, 2 3, 3 0}) |
| 22:41 | TimMc | (Unless I have key:value backwards.) |
| 22:44 | amalloy | rotations like that would be better expressed as integers anyway |
| 22:45 | amalloy | (reorder map 1) or (reorder map -1), depending on whether i have key:value backwards myself |
| 22:45 | TimMc | True. |
| 22:46 | TimMc | Oh! And that would allow for rotations of arbitrary arity. |
| 22:46 | amalloy | but not infinite |
| 22:47 | TimMc | I can't see using something like [1 0 3 2] anyway. |
| 22:47 | TimMc | True... |
| 22:47 | amalloy | well infinite is already impossible |
| 22:47 | TimMc | I wasn't aware you could apply... |
| 22:47 | TimMc | Yeah. |
| 22:47 | amalloy | hard to see making it ever possible, or even useful |
| 22:49 | amalloy | probly best to only allow swaps (maps) and rotations (ints) |
| 22:49 | TimMc | I'm imagining allowing seqs for &args. |
| 22:49 | TimMc | apply would have to know about the arity of the target function, etc. |
| 22:49 | amalloy | so? as long &args is finite, it's already handled |
| 22:49 | amalloy | you just (count args) before you rotate |
| 22:50 | amalloy | which you have to do anyway |
| 22:50 | TimMc | Oh, I was still thinking of the infinite case for functions. |
| 22:50 | TimMc | It's silly, though -- jut take a seq as an arg. |
| 22:51 | TimMc | Next up: Functions with uncountably infinite arity! |
| 22:52 | TimMc | :-D |
| 22:53 | TimMc | I should go to sleep before I try to come up with anything more absurd. |
| 22:53 | TimMc | night all |
| 22:55 | Thamster_ | i'm sorry for the following noob question |
| 22:56 | Thamster_ | Could not locate clojure/contrib/monads__init.class or clojure/contrib/monads.clj on classpath: (NO_SOURCE_FILE:0) |
| 22:56 | Thamster_ | so i add the jar's location to the .closure file in my home directory? |
| 22:59 | amalloy | Thamster_: the answer is likely to depend on how you are running clojure. leiningen, cake, cljr, or something else? |
| 23:00 | Thamster_ | clj in osx terminal after installing via macports |
| 23:00 | Thamster_ | ?! |
| 23:01 | amalloy | mmm. not a mac user here; i know the macports version of leiningen is hopelessly out of date, but i've no idea what the state of clj is |
| 23:02 | Thamster_ | so its that complicated in general to add a jar to the classpath in clojure? |
| 23:03 | amalloy | no, not at all |
| 23:03 | amalloy | cause nobody uses clj :P |
| 23:03 | Thamster_ | i see |
| 23:03 | Thamster_ | is there another interactive shell i could try? |
| 23:03 | amalloy | if you use leiningen or cake (as most do), you just add a line to project.clj, and it goes and downloads the jar from maven then puts it on the classpath |
| 23:03 | Thamster_ | thanks for the tips btw |
| 23:03 | amalloy | $google raynes get started with clojure |
| 23:03 | sexpbot | First out of 254 results is: An indirect guide to getting started with Clojure » I Don't Blog |
| 23:03 | sexpbot | http://blog.raynes.me/%3Fp%3D48 |
| 23:04 | amalloy | wtf sexpbot, that link sucks |
| 23:04 | Thamster_ | haha |
| 23:04 | amalloy | http://blog.raynes.me/?p=48 |
| 23:06 | Thamster_ | he skips right by cljr |
| 23:08 | amalloy | that's not an accident. cake and lein give you all the cljr features and loads more, and are barely any more complicated to install, if at all |
| 23:08 | Thamster_ | they are command line too? |
| 23:08 | Thamster_ | interactive shells? |
| 23:08 | amalloy | they include shells |
| 23:08 | Thamster_ | ok cool |
| 23:09 | amalloy | $ cake repl |
| 23:09 | amalloy | user=> (inc 1) |
| 23:09 | amalloy | 2 |
| 23:09 | Thamster_ | While Leiningen does have a command for starting an REPL outside of a project (a la cake, cljr), it does not currently have a way for you to manage dependencies for that “outside-of-a-project REPL” like cljr and cake does. If yo |
| 23:09 | Thamster_ | … is that right? |
| 23:09 | Thamster_ | i just want to do a quick tutorial on monads |
| 23:10 | Thamster_ | i don't want an ide or anything |
| 23:10 | amalloy | it probably is no longer right, but technomancy is the one to ask |
| 23:10 | amalloy | cake and lein really genuinely are command-line only tools. you don't have to worry about accidentally installing eclipse |
| 23:10 | amalloy | they both integrate with several IDEs, including eclipse, emacs, vim, and textmate |
| 23:13 | Thamster_ | sudo gem install cake; cake repl |
| 23:13 | Thamster_ | that wasn't too painful |
| 23:13 | amalloy | hurrah! |
| 23:13 | Thamster_ | drew! |
| 23:14 | amalloy | now you can just add [clojure-contrib "1.2.0"] to the :dependencies in ~/.cake/project.clj (if it's not there already), and you'll have that jar on the classpath when you launch a repl |
| 23:14 | Thamster_ | hey thanks amalloy , that seems to have worked and managed the dependencies automagically |
| 23:15 | amalloy | that's the idea! |
| 23:15 | Thamster_ | hmm |
| 23:16 | Thamster_ | java.lang.IllegalStateException: m-bind already refers to: #'clojure.contrib.monads/m-bind in namespace: user (NO_SOURCE_FILE:2) |
| 23:16 | Thamster_ | maybe i should delete my .clojure file |
| 23:20 | tomoj | I swear I remember finding the "outside-a-project" stuff in leiningen and being surprised |
| 23:21 | tomoj | but now I don't see it |
| 23:31 | Thamster_ | this is pretty nice |
| 23:32 | amalloy | cdddr: (reorder (partial reduce foo) {0 1}) vs (partial (reorder reduce {0 1}) [1 2 3]) is a funny distinction. swap the argument order for reduce, and decide which argument to partialize |
| 23:33 | amalloy | i think i'll play around with ways to make reorder more convenient then push something to clojars if you're interested |
| 23:40 | technomancy | tomoj: you can install leiningen plugins that work outside a project |
| 23:40 | technomancy | and you can set up a bare swank repl that's standalone |
| 23:40 | technomancy | I haven't heard a coherent use case for actual dependencies outside a project, so I've left that to cljr for the time being. |
| 23:41 | technomancy | IMO incanter should ship with shell-wrappers like swank does for standalone incanter hackery |
| 23:45 | ohpauleez | Raynes: fixed a bug in clj-github, pushed to master already. Can you up the version, push, and release to clojars? |
| 23:47 | amalloy | ohpauleez: probly best to tell him in #sexpbot; i think he's afk and might miss the scrollback in a noisy room like #clojure |
| 23:47 | cemerick | technomancy: My next push on ccw will probably include a way to start a REPL unassociated with any project, and allow one to add dependencies to that session dynamically. I've found myself wanting a REPL with deps X, Y, and Z of late, without the bother of setting up a project. |
| 23:47 | ohpauleez | amalloy: Thanks man, good thinking. Also I don't know if I told you, but I really loved your post the other day |
| 23:47 | amalloy | oh i'm glad |
| 23:47 | cemerick | Nothing special, but it seems useful enough (handy for beginners, too). |
| 23:48 | amalloy | i feel like the title was at once too pretentious and too hard to search for, so i tried to make up for it with content :P |
| 23:48 | ohpauleez | amalloy: haha. Well I sent it around the office, we all enjoyed it. |
| 23:48 | amalloy | great |
| 23:49 | ohpauleez | I'm working on a longer post right now (re-starting up the blog) |
| 23:49 | amalloy | ohpauleez: yeah, my blog had been silent for a month or so |
| 23:49 | amalloy | not counting a post about emacs/vim vs notepad that nobody really noticed |
| 23:50 | ohpauleez | I've been polling clojars and github (soon bitbucket), to grab clojure projects, scan their project.clj if they have one, and make a heat map of dependencies per version of artifact |
| 23:50 | ohpauleez | to help answer the question, "Which package should I be using?" |
| 23:50 | amalloy | ohpauleez: which version, or which package? |
| 23:51 | ohpauleez | version of artifact (you could sum all versions if you wanted) |
| 23:51 | amalloy | $findfn 1 [1 2 3] [3 1 2] |
| 23:51 | sexpbot | [] |
| 23:51 | amalloy | $findfn [1 2 3] 1 [3 1 2] |
| 23:51 | sexpbot | [] |
| 23:51 | ohpauleez | {"aleph" {"1.01" 10 "1.02" 15}} |
| 23:51 | amalloy | man, seriously? we don't have a rotate? |
| 23:52 | ohpauleez | amalloy: we have rotate, I'm almost certain of it |
| 23:53 | amalloy | ohpauleez: i can't find it on the clojure cheatsheet, and sexpbot is usually better at it than i am |
| 23:54 | amalloy | likewise (find-doc "rotate") returns nothing |
| 23:55 | ohpauleez | amalloy: is there some weird thing you can do with cycle, if it's a seq |
| 23:55 | ohpauleez | I'm scouring my code, I could have sworn I've done a rotate before |
| 23:55 | ohpauleez | and I can't believe we have shuffle and not rotate |
| 23:55 | amalloy | i suppose so. it seems easier to do it by hand than hack it into a cycle op |
| 23:55 | tomoj | rotations should be free |
| 23:56 | tomoj | s/free/almost free/ |
| 23:56 | amalloy | sexpbot: botsnack |
| 23:56 | sexpbot | amalloy: Thanks! Om nom nom!! |
| 23:56 | tomoj | of vectors anyway |
| 23:56 | amalloy | tomoj: yes |
| 23:56 | ohpauleez | sure |
| 23:56 | amalloy | but you have to write the code |
| 23:57 | technomancy | I don't really see the utility of adding dependencies to something that isn't a project |
| 23:57 | technomancy | it's not like you could make it any more streamlined than editing :dependencies in a new project |
| 23:58 | amalloy | technomancy: suppose that i like to have c.c.condition available in all my repls or some such |
| 23:58 | amalloy | or com.amalloy.rlyawesome |
| 23:58 | tomoj | the number of interfaces it seems you'd have to implement for free rotation is discouraging |