#clojure log - May 18 2012

0:00fil512: it kinda feels like you have to be above-average smart to develope in it, and it's easy to write code that's hard to understand...

0:00PeregrinePDX: I don't think I am above average smart for a programmer.

0:00 I'm also pretty new to clojure and it takes me awhile but I can figure out a lot of clojure.

0:01ivan__: fil512: i think you have to be open minded more than smart - so many developers never seem to want to try anything new

0:01fil512: I want to have the confidence that anyone from any team could walk up to the clojure code and understand what it's doing. but I worry this is not the case with clojure the way it is with more structured languages like java

0:02 I work on million dollar software projects. Our code has to be maintainable.

0:08 idk, im all for clojure - but if you have 120 guys that dont know it, but know java - it seems like it would be a big deal to move to it heh

0:08eggsby: I think the biggest practical difference between clojure and scala, while both can mostly implement the features of the other without too much pain, if you switch from java to scala you don't need to learn anything, just a bit of syntax

0:09eggsby: but if you switch to clojure, you'll have to completely change how you think about writing programs

0:09 i.e. you can have 10 years of java experience and pick up scala in a few days, clojure would probably take a few weeks/months if you haven't had prior FP experience

0:09ivan__: there arent many scala guys at work (and no clojure), but i can get away with using scala as long as I keep it nice and clean and dont try and do stuopid stuff with type system - java guys can read the code

0:10eggsby: if you are using groovy you could probably switch to scala without people really noticing :p

0:10ivan__: eggsby: yeah - for me I started by writting scala in a very java way, over time i learnt how to work with immutable data, fp stuff etc

0:11 not that i want to rant on about scala in #clojure haha - but i was just finding it wierd the objections that guy has to it

0:11eggsby: I liked fogus' talk about macros, where he implemented BASIC as a DSL in scala, then showed how because it didn't have macros parts of the language peeked through in the implementation

0:15eggsby: Clojure has been an enlightening experience. Kind of a lesson in the power of abstractions

0:16 I've been making the finishing touches to a system I built for work in clojure, the architecture from it was lifted from ring's middleware implementation, seemed like a good way to model transformations over data... then I ran into this article today: stuartsierra.com/2012/05/16/syntactic-pipelines

0:16 I had a lot of the same problems, repeated logic deep inside function bodies, seeing that repetition just plucked away with macros is so beautiful

0:17 I guess any language with metaprogramming capabilities can make something like that happen, but it just seems so elegant/general in clj/lisp

6:45 i will look into how to implement bresenham's line algorithm in clojure, i think it isn't very complex

6:48mduerksen: myarray: i think the preference of max-key is more intuitive the way its implemented now: left-to-right, just like e.g. merge. but intuition aside (which may vary), it should be explicitely written in the doc.

6:53hyPiRion: Would jumping directly over Leiningen 1.x to Leiningen 2 be smart? I haven't used any, and I'm going to port a 1.2 project over to 1.4.

9:16 solussd: CLHS says "the consequences are undefined if the local macro definitions reference any local variable or function bindings that are visible in that lexical environment" (i.e. the lexical environment where the macrolet form appears) http://www.lispworks.com/documentation/HyperSpec/Body/s_flet_.htm -- that applies to CL, but I'd expect the same from tools.macro

9:39weavejester: goodieboy: Hm, not sure why that wouldn't be working, but I haven't tested using configurator with lein-ring before

9:40goodieboy: weavejester: ok. Using ~(prn "configure!") does work, but I guess that doesn't really mean that lein-ring is doing anything with the :configurator value, just that the prn is getting evaluated immediately right?

10:38jweiss: i have some data. most of the data is fixed, iow, always evaluates to the same thing. pieces of it are not - for instance it evaluates to a timestamped string. so far i've been enclosing this literal in (fn [] ...) so that i can call the fn and get a "new" piece of data each time. but that creates an awful lot of functions to compile. i'm wondering if i can implement this where the data is consumed, maybe with protocols.

10:44jweiss: llasram: yeah, but i don't see how i can do it. some of the data need to refer to the same timestamped string.

10:45llasram: jweiss: Yeah, I was thinking that would make it kind of problematic... What's the down-side of having a function generate the data? Do you have a v large number of these functions being dynamically `eval`ed or such?

10:50timvisher: how would you go about converting an io/input-stream into a byte[]?

10:50llasram: jweiss: Wellll. Not necessarily. That might be an easy way to implement things at first, but still locks your data into executable code. I don't know -- it probably depends on the details of the data

10:52jweiss: llasram: have stuff like (fn [] {:a (unique-name "joe")}) which produces a different value each time. but then sometimes i need to refer to the same thing twice: (let [x {:a (unique-name "foo")}] (dothing x))

11:00jweiss: llasram: i'm not sure it's a problem, just thought there might be another way. i'm ok with leaving it as is, just sometimes gets confusing as to exactly when something gets evaluated, because as i compose data, each level needs to be wrapped in a function. and then of course i need a construct to explicitly call it.

11:01 llasram: seems like lisp's quote/unquote constructs kind of do the same thing

11:03llasram: jweiss: Do you have an example of where it gets confusing? The version I have in my head of just normal functions returning and composing normal data-structures seems fairly straightforward to me

11:04Borkdude: ibdknox: I don'tknow the details of ycombinator's process, but I read they invest 18k and you get to be three months over there.. isn't 200k better?

11:04solussd: dependency question: I'm using a version of (lein-marginalia dev-dependency) marginalia in my project that itself depends on hiccup 0.3.7 (in this version escape-html is in hiccup.core), in my project I use hiccup 1.0.x. Running marginalia (lein marg) results in an exception complaining about not being able to find escape-html. it seems that marginalia is using hiccup 1.0, even though it has a dependency on hiccup 0.3.7. How do I get it to us

11:04 the older hiccup while continuing to use hiccup 1.0 in my project?

11:04ibdknox: Borkdude: there's another guaranteed 150k as well. But the value of YC isn't the money, it's the guidance, the name, and the network.

11:14misislavski: both chrome and ff throw: "Uncaught Error: URI file:/robots.txt is invalid for field ppu"

11:14llasram: jweiss: Right. I think the part I'm questioning is the function nesting. It seems like the whole system would be really straightforward if you ultimately just have functions which produce fully evaluated datastructures

11:15 jweiss: You could compose those functions by having higher-level functions call lower-level ones, just like in normal code

11:24gtrak`: I'd like to do some cool startup one of these days, too :-), sounds exciting

11:25ibdknox: foxdonut: the main thing is that before people threw in money to ensure that the project had a chance, now it does, so the circumstances under which that "investment" was made have changed.

11:25 foxdonut: ultimately getting YC is a very, very good thing for the project

11:25pbostrom: ibdknox: just curious, did you approach YC, or did they come after you?

11:25jweiss: i'm a little confused, KS and YC seem totally different. i thought KS was "if you really want this thing built, contribute so you can get it". and then for all the developer might care, everyone else can get it for free. YC doesn't seem like they would want anyone getting it for free.

11:25llasram: ibdknox: OOC, was the successful Kickstarter effort a factor in getting YC?

12:10* zakwilson can't think of many other places someone would be famous for writing Clojure libraries and an IDE.

12:11llasram: zakwilson: That's funny -- I too forgot for a while what had motivated me to learn Clojure in the first place. I'm now pretty sure it was Yegge's forward to /JoC/, although I couldn't tell you why exactly

12:43zakwilson: Anyway, what I have in mind is slightly more ambitious than just compiling to C or doing C with Lisp syntax, but less ambitious than trying to do systems programming with Clojure semantics.

12:44krawitz: hi, does anyone knows a convenient way to parse multipart responses in clj-http, except using commons-fileupload? i found only functions to make multipart requests, but not to parse responses. :-(

14:19hiredman: you have a source of events > queue > a consumer of the events, which component has the responsibility to throttle?

14:19zakwilson: pg says "When we realized that multiple YC partners had already independently contributed to the Kickstarter project because they wanted to use Light Table themselves, it was not a hard decision."

14:46hiredman: weavejester: you have some kind of file watcher thread that generates filesystem events, that thread has a list of weak or soft references to queues, you have listeners on each side of the queues

15:16muhoo: i love it. an exception in projectname.views.something/eval24214

15:16raek: the defmacro form could look like this then: (defmacro my-macro [action & args] ...)

15:17 action will be a keyword and args will be a sequence of code expressions

15:17amalloy: eggsby: you know this macro can only recognize :some-action if you pass it as a compile-time literal, right? you can't do (let [action (if foo :some-action :other-action)] (my-macro action a b c))

15:18raek: if the call looks like (my-macro :someaction (+ 1 2)), action will be bound to :someaction and args to '((+ 1 2)), and not '(3)

15:39 Because the "refresh" is a response returned, I can't do that exactly

15:44 Hm, also, a queue wouldn't work because there could be multiple consumers.

15:47TimMc: weavejester: To recap, you need to take an action iff at least one event has occurred since the last time you took action, but only once x milliseconds have passed since the first such event?

16:08TimMc: weavejester: When a waiter comes in, it creates an atom and registers a closure over it with the notification service, then sleeps for 100 ms. Each time a file event happens, all the closures are called with the event info. In this case, each closure sets its atom's state to true. When the timeout is over, the waiter returns the atom's value.

16:12 weavejester: Alternatively, the notification service maintains a file event count. Client-side code keeps this as an opaque data value and sends it along with the XHR, getting a replacement value back each time -- along with whether to refresh as calculated by (!= old new).

16:12Raynes: TimMc: Man, I thought you were talking about a restaurant for a moment there.

16:13TimMc: This approach does not rely on any queue, and each waiter simply sets a timeout and does that simple calculation when the timer fires.

16:52devn: Raynes: do you know off the top of your head, is it possible to capture *out* from (sandbox (safe-read "(println 1)"))? I'm using (with-out-str and I'm just getting back empty string. How would I capture *out* here?

16:54ibdknox: devn: you can supply a set of bindings to the sandbox, you need to bind *out* to your own thing and then read from that

16:54Licenser: devn not sure how it is in raynes sandbox but for clj-sandbox stuff like *out* and stuff were bound on the creation of a sandbox

17:08Raynes: devn: You can run lazybot and let his eval plugin work without a sandbox. It is useful in private company channels and stuff where you know your employees and coworkers aren't going to delete your machine.

18:20technomancy: late 2008; the scars were still fresh when I joined.

18:22espeed: TimMc: thanks. I am for something more like __getattr__, which is a function that's called if an object doesn't contain an attribute; so that the default value doesn't have to be explicitly passed to "get"

18:28yoklov: espeed: if you implement IFn, and use the record as a function (as you also often do with maps and such), you can handle it the way you would like. there might be another way, but I'm not aware of it

23:27lazybot: ⇒ "Macro ([n]); Prints the source code for the given symbol, if it can find it. This requires that the symbol resolve to a Var defined in a namespace for which the .clj is in the classpath. Example: (source filter)"

23:28ForSpareParts: Not sure which would do it. I'm thinking about unit testing and regression -- it would be useful to be able to list all the functions called by a given function.

23:29 Unless there's a much better way of doing that sort of thing that I'm just missing...?

23:29dnolen`: ForSpareParts: it's possible but you would need to adapt an analyzer like the one that ships with ClojureScript