#clojure log - Mar 08 2016

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

0:51 AndreasO: (Select root [:#tag]) seesaw. How do I address the root widget?

1:03 TEttinger: AndreasO: I seem to remember a method that goes up in the hierarchy... let me check

1:04 http://daveray.github.io/seesaw/seesaw.core-api.html#seesaw.core/to-root

1:13 AndreasO: TEttinger: I think that function returns the root of the widget that triggers the event. In my case a button is pushed and triggers an action that should paint a canvas.

1:15 TEttinger: to-root takes a widget as an argument, you could pass it the event-triggering widget or another widget in a different frame/window

1:15 AndreasO: TEttinger: can I pass a tag?

1:16 TEttinger: you could select one first I think

1:16 do you not have the root to pass to select, so you can't use the tag for that reason?

1:30 AndreasO: TEttinger: I'm not sure what count as the root.

1:30 I'll bin the codefinger

1:32 TEttinger: pastebin.com/E63QbV7C

1:33 TEttinger: line 11-13 and 60-68

1:33 Damn. Pastebin not codefinger

1:33 TEttinger: hm, well Draw shouldn't be capitalized

1:37 AndreasO: I've been banging my head for days. I made simple GUIs before, this is somwath more complicated.

1:39 TEttinger: ohhh

1:39 this looks oddly familiar

1:39 I seem to recall a swing thread thing that the demos used

1:40 see the thing with invoke-later ? https://github.com/daveray/seesaw#tldr

1:42 AndreasO: I found a nother mistake now, draw needs one more arg... g2d?

1:46 TEttinger: seems to be a Graphics2D, doesn't look like that section is meant to be used often

1:48 https://github.com/daveray/seesaw/blob/master/test/seesaw/test/examples/clock.clj uses it

1:51 AndreasO: I'll try that.

1:51 TEttinger: it seems to be a :paint related thing

1:51 AndreasO: I might be overthinking this.

1:52 TEttinger: so you can call g2d-taking methods when you're in a fn that is called as a callback from :paint

1:52 since :paint gives the current g2d with it

1:53 AndreasO: Okay

1:53 TEttinger: also the require statement at the top seems weird, two slashes is not normally what I see

1:54 it may be because it isn't used yet that it isn't causing trouble

1:55 AndreasO: You mean the photomath?

1:56 TEttinger: YEAH

1:56 yeah

1:58 AndreasO: Well that's my own lib. It worked well in a nother test I did.

2:02 I'll look into the clock example, hopefully I'll get it. :-)

2:02 TEttinger: hm, not sure where the / is appropriate in those require sections

2:02 it's the part at the bottom

2:03 (canvas :id :canvas :background "#BBBBBB" :paint paint-clock)

2:03 paint-clock is called with a g2d as one of its args

2:04 AndreasO: Thanks!

2:05 TEttinger: I'm not sure how to explain the root thing other than "I tried a bunch of stuff and found some stuff that worked"

2:06 one of the things I did that I don't know if it's recommended is to, instead of using def to immediately create a widget, use defn to make a fn I can call when everything's ready and only then make the widget

2:08 AndreasO: I see, seems a redesign is in order.

2:10 (run :dispose)?

2:17 TEttinger: still there?

2:22 TEttinger: yeah

2:22 it does seem like it needs some moving around

2:22 graphics-related stuff needs to essentially modify a canvas or something like it... I think....

2:23 AndreasO: I se an error. Yes, you can :paint at the moment of creation as in the clock example. But to change it after creation you need to use the config! Command.

2:24 TEttinger: hm?

2:25 :paint is given a fn, it calls it whenever it repaints

2:25 I don't think config! would help here since it would just change the fn but not tell it to use it

2:27 AndreasO: Hmm... I see. Maybe I can put values in a vector that the :paint function reads .

2:29 The lines and dots need to bee saved anyway.

2:29 TEttinger: makes sense, I think

2:29 if they change you might want them in an atom, or you might want to pass them into the next update somehow

2:32 AndreasO: I did something similar in Python. APOS80

2:33 GitHub.com/APOS80/GeoCad

2:34 Some things is made to be mutable.:-)

2:47 TEttinger: thank you!!! I have now painted a circle!!

2:48 TEttinger: woohoo!

2:49 yeah, the examples for seesaw were the most valuable resource I had trying to learn it

2:49 I did make some tiny things early on, it's good for a lot of stuff. One I'm proud of was a nutrition DB searcher for my grandma

2:50 she had bizarre nutrition constraints, like couldn't have much phosphorus, and that isn't on most labels

2:51 AndreasO: For some reason I always try things that don't work instead of doing it right in the first place.

2:51 TEttinger: GUI is much better for grandma than CLI, haha

2:51 AndreasO: I like cli, but a cad in cli?? Nono

2:51 p_l: AndreasO: ever seen AutoCAD?

2:52 AndreasO: I use topical at work

2:52 p_l: or BRL-CAD (which is even more CLI-oriented)

2:52 amalloy: ed | cad

2:52 AndreasO: Topocad

2:53 p_l: also, OpenSCAD seems to be currently popular thingy on the lower end

2:53 AndreasO: Hmmm... What graphical lib is used for cli?

2:53 p_l: Cadence CAD tools aren't CLI oriented, but IIRC include Lisp REPL :)

2:54 TEttinger: OpenSCAD is good

2:54 p_l: AndreasO: depends on environment - a CAD can have CLI despite being very graphical (the interaction might be through CLI)

2:55 https://en.wikipedia.org/wiki/OpenSCAD#/media/File:Openscad_screen_english.png <--- example from openscad

2:55 https://upload.wikimedia.org/wikipedia/commons/e/eb/BRL-CAD_screenshot.jpeg <--- upper left corner has the main editor interface, iirc

2:56 AndreasO: quite possibly lots of old CAD tools worked well in xterm thanks to its vector graphics support, too :)

2:59 AndreasO: True, but isn't a little more complicated?

2:59 p_l: AndreasO: not necessarily. And can be a godsend when you need to manipulate precisely

3:00 AutoCAD had very good interface in this which coupled command line with mouse/tablet

3:01 for example, how easy it is to convey by mouse that you want exactly X milimeters?

3:02 AndreasO: Isn't autocad written in lisp?

3:02 Heard that

3:02 p_l: and most of those CAD programs are directly extensible (AutoCAD with AutoLisp, Cadence stuff in SKILL - a lisp dialect, etc)

3:02 AndreasO: it isn't

3:02 it has a very old-school lisp dialect however

3:03 AndreasO: Like scheme?

3:03 p_l: used for interaction and automation (though, similarly to AutoCAD REPL, had been pushed to wayside)

3:03 AndreasO: Scheme is very modern lisp dialect :D

3:03 AutoLISP is old style, really old

3:04 older than elisp by now, because elisp evolved

3:04 last time I checked, AutoLISP still didn't have lexical scope

3:16 AndreasO: I'm new to lisp, I like it.

5:28 spba: Has anyone here worked through HtDP?

5:32 ridcully: is it "safe" to have a fn and an aliased ns with the same name. e.g. defn json and cheshire :as json - seems to work as expected in the repl, but maybe this is foolish?

5:43 hyPiRion: ridcully: should be safe, yes

5:44 amalloy: ridcully: yes, it's intended to work fine. you can always distinguish from context whether a namespace is meant or a var

5:45 ridcully: hyPiRion, amalloy: thanks. i thought it would since str is often used for clojure.string - but i was never sure, if that would shadow (str)

6:16 clgv: Hello, in Cursive is there something similar to CTRL+W that extends the selection to the next complete s-expr on the left or on the right?

6:25 Empperi: clgv: check Edit -> Structural Editing

6:25 you can bind those to any shortcuts you wish

6:26 clgv: Empperi: sure, but which one is it`

6:26 Empperi: well, I don't know what "CTRL+W" is so :)

6:28 clgv: "extend selection to the next full s-expression" is what I am looking for

6:29 "CTRL+W" is "extend selection" which will select all expressions with an s-expression, then the whole s-expression and so on

6:29 Empperi: hmm, still not sure what that means, so you want to extend selection so that it contains a full s-expression? Yeah, there is that. But it's not in Cursive but in Idea and it works everywhere

6:30 ah yeah, it's that then

6:30 it's in Idea itself

6:30 search for "shrink selection" and "extend selection" in keymap bindings

6:30 and it will work in every editor

6:30 clgv: I want (->> xs |(map bla)| (map blubb)) to (->> xs |(map bla) (map blubb)|) where the selected part is enclosed in | |

6:31 Empperi: ok, that's not then exactly the same thing :)

6:31 clgv: I am used to that from CCW ;)

6:32 Empperi: shrink/grow would grow from |(map bla)| to both left and right

6:33 dunno if there's a selection functionality exactly for that

6:33 cfleming will know if anyone knows :)

6:33 clgv: is there bugtracker for cursive?

6:36 ridcully: clgv: i used https://github.com/cursive-ide/cursive/issues the last time - still seems active

6:38 clgv: ridcully: ok, thanks

6:38 Empperi: yeah, that is the place

6:38 Cursive itself isn't opensource

6:39 clgv: btw is (.-some_field some-deftype-instance) preferred over (.some-field some-deftype-instance) for field access on deftypes?

6:39 Cursive tries to convince me strongly

7:04 Empperi: well, deftypes compile to java classes

7:04 and you can't name java fields into private Foo some-field;

7:05 it's a syntax error

7:05 sure they don't compile to java source code but same rules apply on bytecode level

7:05 more or less

7:05 so yeah, I'd say it's better to stick with those conventions

7:06 not sure actually how that will work on bytecode, it just might work

7:06 field names with - in them that is

7:06 but if you try to access those from java code...

7:07 so at least for the sake of java interop you should avoid those

7:23 irctc: Hello, please forgive me just jumping into a question, my ignorance and the assumption that Datomic questions are relevant here. I think I understand queries across history in Datomic. What I'm unsure of is can one create a branch in that history and continue adding data? Can one create a tree of db states or can db history be linear only?

7:36 Empperi: irctc: https://groups.google.com/d/msg/datomic/jYjWvut3v3E/GZeod3hYaRQJ

7:36 from 2012 but I guess that's still correct

7:37 however this seems to indicate that branching is currently supported http://vvvvalvalval.github.io/posts/2016-01-03-architecture-datomic-branching-reality.html

7:38 much less official source though but also much more recent

7:43 hyPiRion: irctc: you also have the notion of sagas, which is explained at the later parts of the presentation named "understanding and using reified transactions" over at http://www.datomic.com/videos.html

7:44 (I think that's what they're sort-of used for?)

7:46 justin_smith: TEttinger3: regarding ATS and the benchmarks game - the ATS that wins is idiomatic ATS and is not calling assembly libs - it's a low level language with very strong typing. It's a hard language to learn though. Imagine Haskell where gc is explicit instead of implicit.

7:46 also it uses the type system to ensure correctness of resource usage (mem used but not provably freed, or files opened but not provably closed, are type errors)

8:10 clgv: Empperi: yes you can name them like that - Clojure takes care of that

8:10 irctc_: Great, thanks for the resources regarding branching and Datomic!

8:11 clgv: Empperi: I was just asking whether the preferred field access syntax in Clojure changed when they introduce the .- syntax which is compatible with ClojureScript

8:13 Empperi: no idea

8:16 Kah0ona: Quick question; i'm using compojure-api, and for one route I want to stream back a file rather than JSON data.

8:16 what is the recommended way for setting up such a route, should it use compojure-api at all?

8:16 or should i drop down to native compojure routes?

8:27 Empperi: well, no point in defining the return type then

8:27 you can use compojure-api

8:27 just don't define return schema

8:27 Kah0ona: ah so not defining it as s/Any then? :-)

8:27 thanks

8:28 Empperi: we have it like that without :return and works nice

8:28 Kah0ona: cool will try

8:28 Empperi: then you have to handle response building yourself but that's what you want in that case

8:28 actually we stream data through our app from another app of ours straight to browser

8:28 it never sits in memory on our servers since we just use InputStreams all the way

8:36 Kah0ona: yeah i'm planning to do the same, when generating PDFs for instance, don't want them to hit the disk

8:41 Empperi: yeah, we are actually serving PDFs too

8:41 some of them are HUGE

8:41 Kah0ona: great this works neat :-)

8:41 neatly*

8:42 Empperi: yeah, it's nice that you can just throw InputStream for ring and it handles it correctly

8:42 Kah0ona: yeah

8:42 I used to have pretty ugly servlets 'back' in the java days :-)

8:42 this is really elegant

8:42 <3

8:46 Empperi: servlets were revolutionary back when they were introduced

8:47 but yeah, that was some time ago now :)

8:47 world has gone forward

8:48 sharms: If I have a nested map of maps that occassionally has a {:key1 {:key2 {nil nil}} and want to create a new map with {nil nil} replaced with the (:key2 (:key1 another-map)), what is the clojure way to do it?

8:48 where :key1, :key2 ... :keyN

8:49 Empperi: use walk api

8:49 https://clojuredocs.org/clojure.walk

8:50 sharms: Would you happen to know how I could get the keys required to get to the point I have walked to?

8:50 I have tried a few walk functions, tree seq etc but I am a bit hung up

8:51 the-kenny: Is there no way to use a :gen-class via `lein repl` *without* having to call `lein compile` first? I'd rather not introduce another step for devs to start developing

8:51 Empperi: well, your scenario isn't trivial

8:51 would take some time to implement the solution with walk api

8:52 would love to help but I've spent too much time doing all other stuff except the stuff I'm supposed to do :D

8:52 sharms: oh that is ok, I just wanted to make sure something like this wasn't a "oh just type this one line in" type thing

8:52 Empperi: don't want to sound like a total prick leaving you in distress but really, I need to do some work :/

8:52 sorry

8:52 sharms: thank you for your help

9:33 the-kenny: Okay, I'm out of ideas: I've got a custom Exception generated via :gen-class in a namespace, foo.ValidationException. Now I want to import that in some other namespace, for example foo.model. As soon as I add it to the :import of foo.model, leiningen won't compile nor repl anymore, saying it can't find foo.ValidationException. I got it in my :aot in project.clj and tried *every* combination of aot, different

9:33 namespaces, adding :name to gen-class, requiring the namespace of the exception, running compile beforehand, etc. etc.

9:34 A colleague next to me did *exact* the same thing in clj-oauth2 before (some years ago): https://github.com/DerGuteMoritz/clj-oauth2/blob/master/src/clj_oauth2/OAuth2Exception.clj

9:34 All I get is ClassNotFoundExceptions everywhere.

9:36 The only "solution" I see right now is removing all usage of ValidationException in our codebase, running `lein compile`, then uncomment all usages.

9:40 justin_smith: do you require the namespace that defines the exception in the code that wants to throw that exception?

9:40 the-kenny: Tried that.

9:41 Same result.

9:41 justin_smith: if the namespace is compiled before the other namespace tries to use the class, then you should not see this error. You ensure this by using require.

9:41 OK

9:42 so you both require the namespace, you import the exception in the same ns that requires the namespace, and the exception defined in the required namespace is not available?

9:43 can you make a minimum reproduction of this error (eg. two namespaces, one tries to throw an exception defined in the other)?

9:43 the-kenny: Yeah, that's likely the next step.

9:43 Working on it, give me a minute

9:48 justin_smith: https://github.com/the-kenny/clojure-custom-exception-minimal-case

9:49 error is different, give me another minute. My brain doesn't really work today

9:49 okay, it works in that minimal example. I'll be damned

9:50 Okay, I'm getting some food and throw my day's work away afterwards and starting from scratch.

9:51 justin_smith: the-kenny: my suspicion is the whole package vs. namespace vs. class thing, it's a messy corner conceptually, even when people think they get it it's easy to confuse things

9:51 the-kenny: justin_smith: Yes, I'm aware of that. It's just that this is closest to the working example I've found. And I want to minimize the complexity.

9:53 justin_smith: I think the interactions are weird - the class does not exist unless you require the namespace but requiring the namespace doesn't import the class yadda yadda

9:54 Kah0ona: i've got something weird. I return a response with Content-Length 30705, but somehow it shows Content-Length 0 in the response header.

9:55 It seems to be reset by compojure-api / compojure / ring?

9:55 The header code is picked up, because if i change Content-Length to Content-Length2 it'll show that Content-Length2 header in the response

9:56 how can i figure out which response middle ware (is there even such a thing?) is working in my compojure-api route?

9:56 justin_smith: Kah0ona: yeah, many middleware will alter the response

9:57 Kah0ona: the idea of a middleware is that it is free to alter the parameters before they hit your handler, or the response that comes out

9:57 Kah0ona: okay so how can i actually see what middleware is active? because my handler code just returns a response map of which I know it is correct

9:57 justin_smith: (by returning a new function that wraps a handler and does those things)

9:57 Empperi: Kah0ona: if you are using cursive then you can just use the debugger

9:57 justin_smith: Kah0ona: the only way I know of is to look into the compojure api code you are calling and seeing which middleware it inserts

9:57 Kah0ona: yeah i see the point of mw, but since there are some defaults being put in place by compojure-api

9:57 justin_smith: Empperi: oh, great point

9:58 Kah0ona: yeah, compojure-api is just a bunch of middlewares iirc

9:58 Empperi: well, that and some macro magic to build the route mapping :)

9:58 Kah0ona: yeah with some macro's that does some coercion and checking

9:58 yeah

9:58 okay so i gotta figure out which mw resets my content-length to 0

9:59 Empperi: pretty much

9:59 default compojure-api mws shouldn't do it

9:59 since we have compojure-api in use

9:59 so I'd look at something else at first

9:59 Kah0ona: hmm don't have much else there actually...

10:00 only some mw that modifies the request, but not the response

10:06 Empperi: so are you setting the content-length into your response headers correctly?

10:06 and are you 100% certain of that?

10:06 obviously ring cannot do that for you when you pass InputStream for it

10:08 justin_smith: ,(.available (java.io.ByteArrayInputStream. (.getBytes "hello")))

10:08 clojurebot: 5

10:08 justin_smith: not in the general case, but sometimes

10:13 Kah0ona: yeah i'm certain

10:13 and i think the middleware: wrap-format-response causes it

10:13 Empperi: justin_smith: yeah but that is far from reliable

10:13 Kah0ona: https://github.com/ngrunwald/ring-middleware-format/blob/master/src/ring/middleware/format_response.clj#L202

10:14 how can i disable that one for a certain route

10:14 Empperi: for a single route?

10:14 Kah0ona: i somehow find the compojure-api docs not really clear on how to disable a preconfigured mw

10:14 yeah i have one /files?file_id=1

10:14 route

10:14 Empperi: just define it separately from your other routes

10:15 justin_smith: Kah0ona: one option is a middleware wrapping that middleware that knows how to fix your Content-Length

10:15 Kah0ona: yeah but i defined it using compojure-api

10:15 justin_smith: Kah0ona: another is to replace the default middleware stack with something that behaves correctly

10:15 Kah0ona: ah like a new mw that undo's it

10:15 hm

10:15 justin_smith: yeah, should be easy to write - it checks for your :real-content-length and applies it if present?

10:15 Empperi: hacky but would work

10:16 Kah0ona: ok i'll try that

10:16 justin_smith: the cleaner fix is to build your own custom middleware stack that isn't broken - depends on time available, how much work you want to put into it

10:16 Empperi: we actually have something like that in place for one of our custom middlewares

10:16 ikitommi_: Kah0ona: what mw's do you have outside of c-api `api`?

10:16 Empperi: which prevents it from doing it's magic for responses

10:16 Kah0ona: ah care to share?;-)

10:16 Empperi: Kah0ona: now you got compojure-api author to help you ;)

10:16 ikitommi_ that is

10:16 Kah0ona: yeah i see that :-)

10:17 well i dont have any that modify the response

10:17 only some that modify the request

10:17 atleast, as far as i can tell now

10:17 ikitommi_: can you throw in a gist?

10:17 Kah0ona: ikitommi_, : i'll make a little gist of the defroute

10:17 yeah

10:17 k

10:18 ikitommi_: the default mw-stack in c-api touches the reponse in two ways: 1) response coercion IF the endpoint has defined a Schema for it 2) using ring-middleware-format

10:20 and the response coercion is defined in the endpoint, so if your route doesn't define a return schema, r-m-f is the only party doing something

10:20 justin_smith: ikitommi_: he just linked to the middleware that is setting his content-length - wrap-format-response

10:21 so maybe that means compojure-api is misled about the type of response or how to handle it?

10:22 Kah0ona: https://gist.github.com/Kah0ona/11c338cef61cd83ec7f0

10:22 so i already got the hint of Empperi to _not_ put a `:return something` key in the options

10:23 which got me around the default json encoder that tried to encode my file as json

10:23 but now since content-length is always 0 i can't download my file (or it is empty that is)

10:23 but it would be nice to also define this route in compojure-api

10:25 for the purpose of this single route disabling the ring-middleware-format would probably fix my problem

10:25 ikitommi_: lot's of extra middlewares, is it possible to test without those?

10:25 Kah0ona: yeah okay i will try to disable them all

10:25 Deraen: r-m-f should do nothing with response body is not collection (i.e. it is Stream) and when no `:return` is not set

10:27 Kah0ona: by the way, i'll update the gist to show my file download function, which uses PipeInputStream

10:27 ikitommi_: yes, your compojure-api GET is really just a Compojure GET, so it's rendering rules apply (https://github.com/weavejester/compojure/blob/master/src/compojure/response.clj)

10:28 Kah0ona: one of which appearantly sets the Content-length automatically by checking the body, which, since it is a stream, doesnt give the correct Content-Length?

10:29 so what is the best way to fix this?

10:29 clojurebot: Titim gan éirí ort.

10:30 Kah0ona: thanks so far by the way, for pointing in the right direction

10:31 Deraen: I don't think Compojure Renderable matters in this case. If response is map, it is used nearly as is.

10:32 ikitommi_: it could, if find-and-stream-file returns a stream and some evil external code has overridden the Stream-responses. Not likely thou.

10:32 Kah0ona: https://gist.github.com/Kah0ona/9c52f4932cc4de4219ae

10:33 this is my fn that creates the stream by the way

10:33 cortexman: anyone using parinfer? https://github.com/edpaget/parinfer-mode

10:33 (for emacs)

10:35 prohobo: hey guys, i have a problem

10:35 nvm

10:35 TimMc: phew

10:36 Deraen: Interestingly file download code I have doesn't set content-length but the response has correct value, and the response body is a InputStream from Mongo GridFS

10:36 ikitommi_: Kah0ona: have to go, hopefully you find a solution for this with @Deraen & @Empperi

10:37 Kah0ona: yeah i go for the 'undo middle ware' approach

10:37 thanks all

10:37 then at least i think i ca nget it working without too much fuss

10:38 TimMc: I just took a look at the parinfer thing cortexman linked... it's weeeeeird.

10:38 justin_smith: sometimes you just have to add it to the "technical debt" list and go get other shit done, and some day you'll have the lightning bolt of inspiration that tells you how to fix it

10:38 TimMc: type python, get clojure

10:39 the-kenny: justin_smith: Found my issue. My user.clj required foo.core. And user being the repl's init-ns caused much much weirdness.

10:40 (my user ns requires core to use it in start/stop/reload for Component)

10:40 Deraen: Kah0ona: Btw. if the response is just a File, you don't need to turn it into Stream, you can just send File as response body

10:40 justin_smith: the-kenny: (dec user.clj)

10:41 because it's too easy to forget that it's modifying your environment

10:42 Kah0ona: Deraen aaahhhhh

10:42 the-kenny: yeah. We even moved it to dev-src/ so it's only loaded in dev environments. Very annoying.

10:42 Kah0ona: that's a good insight :)

10:42 so just return a File?

10:43 Deraen: Yeah. And I think there is a good chance that content-length will be set automatically when you send a File.

10:43 Kah0ona: will definitely try now

10:47 lol Deraen that did it

10:48 and it removed like 10 lines of custom header building stuff

10:48 just remove a File

10:48 return*

10:48 thanks man!!

10:48 justin_smith: awesome

10:48 Deraen: File response is mentioned in Ring wiki: https://github.com/ring-clojure/ring/wiki/Concepts#responses

10:48 Kah0ona: thanks

10:48 yeah somehow i sometimes have trouble how thigns work together

10:49 because at some point i'm working with compojure-api, and i now and then miss the link to how it pieces together with compojure/ring

10:49 well bugs like this do make that more clear though :)

10:49 sdegutis: Good evening.

10:50 Kah0ona: good afternoon! ;-)

10:50 sdegutis: It's morning here.

10:51 Kah0ona: nice curveball then

10:51 =0

10:51 =)

10:52 Deraen: Looks like http server itself (e.g. http-kit) might overwrite content-length: https://github.com/http-kit/http-kit/blob/master/src/java/org/httpkit/HttpUtils.java#L437-L441 (check bodyBuffer method for code which handles File/InputStream etc. response bodies)

10:53 Aleph checks if response already has content-length and only sets it if it is not already set :)

10:59 sdegutis: Hello.

11:00 Is there a way to make this template function prettier? http://sdegutis.github.io/2016-03-07/clojure-template-no-deps/

11:01 I'm trying to do it via fricken like -> and/or ->> etc but it like just aint workin or whatever

11:02 cortexman: i'm wondering if there's a way to use distinct (presumably as a stateful transducer) to distinct-ify objects based on a specific property

11:02 justin_smith: sdegutis: why not make that fn a helper with real variable names?

11:03 sdegutis: justin_smith: wait, what?

11:04 justin_smith: oh, you mean /instead/ of having a template function? like, each "usage" of (template) would actually be its own function?

11:04 justin_smith: kinda like this? (defn something [bar quux] (str "foo " bar " " bar " " quux)) ?

11:04 justin_smith: like (defn apply-key-to-template [s from to] (str/replace s (str "{{" from "}}") to)) (reduce (fn [s [k v]] (apply-key-to-template s (name k) v)) s m)

11:05 sdegutis: justin_smith: interestingly enough, I have done that in most places where I was using clostache (which I removed yesterday because it is a clustercluck on clojars and the latest version(s) are all broken with regard to dollar signs)

11:05 oh

11:05 justin_smith: never mind my last statement to you then

11:05 justin_smith: I'm always hesitant to make helper functions like that, but..

11:06 justin_smith: yeah, even in this case I'm hesitant to extract a helper function (even if it's private) for very little gain

11:06 justin_smith: sdegutis: bonus with that approach is that things like {{{}}} etc. become much easier

11:06 or if you want things that call helpers in templates

11:06 etc.

11:07 sdegutis: hm

11:07 justin_smith: that is, the gain is more if you plan on allowing different kinds of substitution

11:07 if you only do that one kind? leave it as is, it's fine

11:07 sdegutis: justin_smith: I see

11:08 justin_smith: and if you don't plan on doing more than simple substitution, why are you even writing this yourself? lots of libs do that

11:08 sdegutis: Wow. It's hard to imagine that only a year ago I was interested in Haskell and seriously considered it a viable alternative to Clojure: http://sdegutis.github.io/2015-02-10/haskell/

11:09 That blog post was extracted from an email I sent to my employers in hopes it might persuade them to consider Haskell instead of Clojure.

11:09 * sdegutis sighs

11:10 justin_smith: sdegutis: so if you had more than one kind of interpolation it would be like (comp (apply-key-to-template k v) (apply-escaped-key-to-template k v) (apply-helper-to-template k v)) where each returns a function that takes and returns the template itself

11:10 sdegutis: justin_smith: ah I see now, neat

11:11 justin_smith: that would be a cool start to an alternative templating library, possibly one with more configurability than clostache has

11:11 justin_smith: sdegutis: and you could have evil recursive templates if you repeat all steps until output string is equal to input

11:11 haha

11:12 sdegutis: Unfortunately I don't believe I'd ever like such a library. My preferred templating library so far is (comp (partial apply str) (flatten))

11:12 Oops I meant (comp (partial apply str) flatten)

11:13 So that you can just return any number of levels of nested strings and then just string-build those suckers together.

11:13 That works easiest with the sequence-transforming functions in clojure.core, e.g. for, reduce, range, take-while, etc.

11:14 ~flatten

11:14 clojurebot: flatten is rarely the right answer. Suppose you need to use a list as your "base type", for example. Usually you only want to flatten a single level, and in that case you're better off with concat. Or, better still, use mapcat to produce a sequence that's shaped right to begin with.

11:14 sdegutis: WRONG clojurebot, you're WRONG

11:15 rcassidy: Heh

11:15 justin_smith: :b4

11:17 sdegutis: ?

11:17 justin_smith: sdegutis: I added a plugin to my irc client, sometimes I use that plugin wrong

11:17 sdegutis: silly justin

11:18 justin_smith: sdegutis: you can pretend that says "C-u 4 M-x switch-to-buffer-by-number"

11:18 sdegutis: haha

11:18 * sdegutis is glad LimeChat is so simple

11:19 justin_smith: this is simple, but not yet familiar (I think a clojure user can recognize that these can be separate things)

11:19 sdegutis: oh for sure, I'm an Emacs user remember? :P

11:19 Emacs is as simple as it can be for my usage given my needs

11:20 anything simpler would cripple my productivity

11:20 also I feel so bad for people who use vim

11:20 like, how can you get anything done in vim?

11:20 justin_smith: sdegutis: your sympathy is noted and appreciated.

11:20 sdegutis: maybe there is a way I just didn't learn about back when I used vim/mvim for a few years

11:21 haha justin_smith you dont use vim

11:21 justin_smith: sdegutis: I used evil for a while, it is an easy switch. I used evil because my wrists are mortal and are vulnerable to key chording.

11:21 sdegutis: haha

11:21 justin_smith: but even when I did use vim, I was always using chords, because you just can't use vim without them

11:21 C-r "

11:21 that's a common one

11:21 justin_smith: sdegutis: I know otherwise. I never use C-r "

11:22 I don't even know what that does

11:22 sdegutis: how do you paste from " then justin_smith?

11:22 justin_smith: it's a way to paste from " which is like some special thing

11:22 lemme go look it up

11:22 justin_smith: "*p pastes from my system clipboard

11:22 sdegutis: hmm

11:22 oh wait

11:22 justin_smith: "<foo>p pastes from foo

11:22 sdegutis: i remember now i think

11:22 C-r " is like when you need to paste while you're in the fake-minibuffer-thing

11:23 that's what it was

11:23 justin_smith: oh, I don't find myself doing that, maybe I'm not yet advanced enough for such things

11:23 sdegutis: i like how in emacs the minibuffer has the same commands as any other buffer for the most part, so you can backtrack with C-b and copy with M-w etc

11:23 justin_smith: dont worry ull get there in time

11:24 justin_smith: sdegutis: the top priority for me is nothing I do average 10 times a minute or more should be a chord. In vim I have a workflow that pulls that off (given I can use alternate hand for the shift key)

11:26 amalloy: but where will you find time for piano practice?

11:27 sdegutis: amalloy: i dont get it

11:27 justin_smith: amalloy: some day the jazz world will appreciated my unique pointellistic style without chords

11:28 amalloy: sdegutis: if the audience doesn't get it, it wasn't a joke after all

11:28 sdegutis: amalloy: i vaguely remember that i had practiced piano in like 2013, but i dont recall any association between that and our current vim vs emacs conversation

11:29 amalloy: chords

11:29 sdegutis: amalloy: oh man wow yeah i got that it just seemed a little too obvious for an amalloy joke

11:30 btw, ive given my kids piano sheet music for FFVII songs, and they're killin it

11:30 i love hearin that while i work, its amazing

11:31 like, right now, my 12yo son is playing Forested Temple on the piano by ear.. i go and ask him "where did you even hear that?" because he doesnt have sheet music for it, and he said "from your room [office]" lol!!

11:32 justin_smith: sdegutis: https://www.youtube.com/watch?v=Y-Elr5K2Vuo

11:34 sdegutis: also he fricken did Rocky Maridia for his piano recital https://www.youtube.com/watch?v=nAR38Rf4ig4

11:34 which btw is a song off the Super Metroid soundtrack :D

11:40 * michaelw

11:41 sdegutis: I'm still trying to figure out the best way to use Components with a Router component. It feels very ugly to pass the whole system component into the Router component, but it feels even uglier to pass almost every single other component in the system through the router.

11:41 This is on account of how the whole Router contains many different kinds of routes, each of which use only some of the system's components, but all of which use almost all of them (probably all except the router).

11:42 I suppose splitting the routes up and giving them to the Router, per justin_smith's previous suggestion, is one way of de-tangling this, but then each route needs to become its own Component, which feels unnecessarily heavy.

11:43 justin_smith: sdegutis: what about letting each component define middlewares, and composing those in your router

11:43 all stateful stuff would be provided via middleware, and not directly in the handler definition

11:43 sdegutis: In my experience, Components and/or Records should only be used when a bit of functionality (1) needs to be started/stopped, (2) comes with configuration that it would like to have initialized with only once and carried with it through the lifetime of the system, or (3) I forgot #3.

11:44 justin_smith: sdegutis: right, and a middleware can be a bridge so that a handler (which the components need not know about / handle) can access something stateful

11:45 sdegutis: Oh right, (3) is when the thing inherently affects an external service (such as sending a live email) and it would be handy to have a "fake" version of that thing.

11:46 And in #3, there would be a Protocol that handles the thing, a live Record and a fake (usually in-memory) Record which both implement the Protocol, which inherently conform to Components and can be reasonably considered a stand-alone component in a system.

11:46 justin_smith: that's just an implementation technique of how to include all the system components in the router

11:47 justin_smith: it still comes with the drawback of having all the individual system components being passed to the router and thus the individual routes (via the request map).

11:47 justin_smith: not if you explicitly pass in only the middlewares - you can have each component optionally return a :middlewares key with a hash-map of keys to middleware provided

11:48 then the exposure is just the middlewares you pass in

11:49 sdegutis: justin_smith: afaiu, that's just a slight inversion of where the middlewares are defined; but the routes still need to access the component's provided functionality via a key in the request map, right?

11:50 justin_smith: the component decides how its state / functionality is exposed

11:51 via its definition of the middleware

11:51 I think that's going to allow clean isolation

11:53 for example it can provide a query function, instead of a handle to the db itself

12:05 sdegutis: justin_smith: I was thinking it would just provide itself to the request map; for example, the middleware would just (assoc request :db-conn db-conn-component), and then routes would access it via (:db-conn request) and use it like (myapp.interfaces.db-conn/query (:db-conn request)) assuming that query function lives in a Protocol or something.

12:05 Also, I cleaned up my thoughts about Components and put them at http://sdegutis.github.io/2016-03-08/when-to-use-clojure-components/ for everyone here

12:06 justin_smith: sdegutis: but if you do it that way, you need to mock a db. If you provide a query facade, that's much easier to test with, you just pass in a stub for the query facade instead of needing to mock a db api.

12:06 that's my theory at least.

12:07 sdegutis: hmm

12:08 RedNifre: Hey there clojuristas.

12:09 ,(+ 1 2)

12:09 clojurebot: 3

12:09 RedNifre: clojurebot step up your game, you're getting slow!

12:09 ,(def y)

12:09 clojurebot: #'sandbox/y

12:10 sdegutis: ,(def x #'x)

12:10 clojurebot: #'sandbox/x

12:10 mokuso: hehe

12:10 mavbozo: ,(get get get get)

12:10 clojurebot: #object[clojure.core$get 0x6ab31f44 "clojure.core$get@6ab31f44"]

12:10 sdegutis: ,x

12:10 clojurebot: #'sandbox/x

12:10 sdegutis: ,(x)

12:10 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.StackOverflowError\n :message nil\n :at [clojure.lang.Var fn "Var.java" 363]}]\n :trace\n [[clojure.lang.Var fn "Var.java" 363]\n [clojure.lang.Var invoke "Var.java" 375]\n [clojure.lang.Var invoke "Var.java" 375]\n [clojure.lang.Var invoke "Var.java" 375]\n [clojure.lang.Var invoke "Var.java" 375]\n [clojure.lang.Var invoke "Var.java" 375]...

12:10 sdegutis: HAHAHA

12:10 RedNifre: That output isn't that helpful in my case.

12:10 See, I have troubles understanding what an unbound var is.

12:10 justin_smith: RedNifre: do you know what a var is?

12:11 mokuso: '(expt 2 2)

12:11 ,'(expt 2 2)

12:11 clojurebot: (expt 2 2)

12:11 mokuso: ,(expt 2 2)

12:11 clojurebot: #error {\n :cause "Unable to resolve symbol: expt in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: expt in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: expt in this co...

12:11 RedNifre: When I do this in the REPL: (def y) (def x y) (def z) then it looks like x and y point to the same "nothing" but z points to a different "nothing".

12:11 mokuso: meh

12:11 RedNifre: What exactly does this output mean: #object[clojure.lang.Var$Unbound 0x15b5893c "Unbound: #'user/y"]

12:11 mokuso: ,(math/expt 2 2)

12:11 clojurebot: #error {\n :cause "No such namespace: math"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: No such namespace: math, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "No such namespace: math"\n :at [clojure.lang.Util runtimeException "Util.java" 221]}]...

12:11 justin_smith: RedNifre: a var is a container. (def x y) points the container x to hold the uninitialized default value held in the container y

12:12 RedNifre: What's an uninitialized default value? It sounds like it's different from nil?

12:12 mokuso: ,(Math/pow 2 2)

12:12 clojurebot: 4.0

12:12 justin_smith: RedNifre: yes, it is

12:12 ,(def x)

12:12 clojurebot: #'sandbox/x

12:12 justin_smith: ,x

12:12 clojurebot: #'sandbox/x

12:12 justin_smith: ahh, x already existed

12:12 ,(def uninitialized)

12:12 clojurebot: #'sandbox/uninitialized

12:12 sdegutis: ,(x x)

12:12 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.StackOverflowError\n :message nil\n :at [clojure.lang.Var invoke "Var.java" 379]}]\n :trace\n [[clojure.lang.Var invoke "Var.java" 379]\n [clojure.lang.Var invoke "Var.java" 379]\n [clojure.lang.Var invoke "Var.java" 379]\n [clojure.lang.Var invoke "Var.java" 379]\n [clojure.lang.Var invoke "Var.java" 379]\n [clojure.lang.Var invoke "Var.ja...

12:12 sdegutis: ,(x x x)

12:12 justin_smith: ,uninitialized

12:12 clojurebot: #object[clojure.lang.Var$Unbound 0x1317c009 "Unbound: #'sandbox/uninitialized"]

12:12 #error {\n :cause nil\n :via\n [{:type java.lang.StackOverflowError\n :message nil\n :at [clojure.lang.Var invoke "Var.java" 383]}]\n :trace\n [[clojure.lang.Var invoke "Var.java" 383]\n [clojure.lang.Var invoke "Var.java" 383]\n [clojure.lang.Var invoke "Var.java" 383]\n [clojure.lang.Var invoke "Var.java" 383]\n [clojure.lang.Var invoke "Var.java" 383]\n [clojure.lang.Var invoke "Var.ja...

12:13 mokuso: ,(Math/pow 2 (Math/pow 2 4))

12:13 clojurebot: 65536.0

12:13 mavbozo: ,(deref #'sandbox/uninitialized)

12:13 clojurebot: #object[clojure.lang.Var$Unbound 0x1317c009 "Unbound: #'sandbox/uninitialized"]

12:13 RedNifre: Yeah, so there is this "Unbound" thing and it has this hex number. What's up with that?

12:13 justin_smith: RedNifre: an unbound var is automatically given that special value - an instance of clojure.lang.Var$Unbound

12:13 RedNifre: $ is jvm syntax for an inner class

12:13 Unbound is a class created inside Var

12:14 RedNifre: Okay, so there is a type Var$Unbound and every unbound var gets a newly created value of that type assigned?

12:14 justin_smith: unbound vars are initialized to hold an instance of unbound

12:14 sdegutis: ,(apply apply (repeat 10 (constantly 9)))

12:14 clojurebot: #error {\n :cause "Don't know how to create ISeq from: clojure.core$constantly$fn__4614"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "Don't know how to create ISeq from: clojure.core$constantly$fn__4614"\n :at [clojure.lang.RT seqFrom "RT.java" 542]}]\n :trace\n [[clojure.lang.RT seqFrom "RT.java" 542]\n [clojure.lang.RT seq "RT.java" 523]\n [clojure.core$seq__4357 invokeS...

12:14 mavbozo: ,(type uninitialized)

12:14 clojurebot: clojure.lang.Var$Unbound

12:14 justin_smith: RedNifre: exactly

12:14 RedNifre: So it's kinda like nil except that there's only one nil but many unbound?

12:14 justin_smith: RedNifre: and it's less ambiguous where an Unbound came from

12:14 mavbozo: ,(def un-init-0)

12:14 clojurebot: #'sandbox/un-init-0

12:14 justin_smith: RedNifre: there's so many ways to generate or end up accidentally with nil

12:14 mavbozo: ,(def un-init-1)

12:14 clojurebot: #'sandbox/un-init-1

12:15 mavbozo: ,(= un-init-0 un-init-1)

12:15 clojurebot: false

12:15 justin_smith: RedNifre: the two ways to get an Unbound are to not yet bind a var, or create one on purpose

12:15 RedNifre: Well, but there's only one null in Java and null is thus equal to null. Is the same true for nil in Clojure? I gather that comparing two unbound vars would be false since they contain different unbounds?

12:15 justin_smith: RedNifre: nil is null

12:15 there is no distinction

12:15 same thing, two names

12:16 RedNifre: okay, so only one nil and it's equal to itself. got it.

12:17 Are nil and Unbound the only "nothings" in Clojure or are there more? E.g. JavaScript also has undefined which is what you get when you read from a nonexistant var (where Clojure would throw an exception).

12:18 justin_smith: hmm, does Double/NaN count?

12:18 different kind of not a thing

12:18 RedNifre: I guess so, I mean NaN is for Doubles what null is for objects, huh?

12:18 justin_smith: there's also a promise that is not realized

12:18 which is also different but kind of "nothing yet"

12:19 sdegutis: NaN is just weird, never use NaN

12:19 and never use Doubles or Floats.

12:19 Prefer to use Strings for all your number manipulation.

12:19 justin_smith: doubles and floats would be less useful without NaN though

12:20 RedNifre: I'm not a fan of NaN either.

12:21 justin_smith: would you prefer (/ 0.0 0.0) throw an exception?

12:21 (not to mention various usages of trig functions)

12:21 mavbozo: ,(/ 0.0 0.0)

12:21 RedNifre: I'm not sure. Maybe.

12:21 clojurebot: NaN

12:21 sdegutis: It's interesting how often I end up using (reduce).

12:22 RedNifre: In the REPL, can I undef something?

12:22 justin_smith: RedNifre: yes, you can

12:22 sdegutis: 'reduce' is the simplest functionally pure way of transforming something based on the current and any/all past elements in a sequence.

12:22 RedNifre: Great. When I need it I'll ask how.

12:22 justin_smith: RedNifre: remembering...

12:23 ns-unmap

12:23 I keep forgetting that name though, I keep wanting unintern or something

12:26 RedNifre: Hm, how to use it? From (doc ns-unmap) I thought I should do (ns-unmap user y) but that complains about not finding user.

12:26 justin_smith: RedNifre: it wants symbols

12:26 (ns-unmap 'user 'y)

12:26 that's why I expect it to be called unintern, intern also uses symbols

12:26 RedNifre: ah.

12:27 How do I fetch the current ns?

12:27 justin_smith: ,*ns*

12:27 clojurebot: #object[clojure.lang.Namespace 0x29fac779 "sandbox"]

12:27 sdegutis: ,(ns-unmap *ns* 'map)

12:27 clojurebot: nil

12:27 justin_smith: ns-unmap will accept that value

12:27 sdegutis: Hahahha stupid clojurebot.

12:27 justin_smith: ,(map inc [0])

12:27 clojurebot: (1)

12:27 sdegutis: ,(map inc [1 2 3])

12:27 clojurebot: (2 3 4)

12:27 sdegutis: wha?

12:28 RedNifre: Do these asterisks have a special meaning or is it just the name of the function?

12:28 sdegutis: Oh, it probably creates a new *ns* every time? or something?

12:28 ,*ns*

12:28 clojurebot: #object[clojure.lang.Namespace 0x29fac779 "sandbox"]

12:28 sdegutis: ,*ns*

12:28 clojurebot: #object[clojure.lang.Namespace 0x29fac779 "sandbox"]

12:28 sdegutis: hmmmmm

12:28 justin_smith: sdegutis: you maybe want ns-unalias

12:28 sdegutis: justin_smith: no i dont think so

12:28 ns-unmap worked locally for me

12:28 justin_smith: ,(ns-unalias *ns* 'map)

12:28 clojurebot: nil

12:28 sdegutis: justin_smith: alias is for things like str

12:28 justin_smith: ,(map inc [0])

12:28 clojurebot: (1)

12:28 sdegutis: clojure.string :as str = alias

12:28 justin_smith: hrm

12:28 OK

12:28 sdegutis: must be clojurebot weirdness then

12:29 sdegutis: ,(do (ns-unmap *ns* 'map) (map inc [1 2 3]))

12:29 RedNifre: ,(def undef [symbol] (ns-unmap *ns* symbol))

12:29 clojurebot: #error {\n :cause "Unable to resolve symbol: map in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: map in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: map in this conte...

12:29 #error {\n :cause "Too many arguments to def"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Too many arguments to def, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.RuntimeException\n :message "Too many arguments to def"\n :at [clojure.lang.Util runtimeException "Util.jav...

12:29 sdegutis: ,(map inc [1 2 3])

12:29 clojurebot: (2 3 4)

12:29 RedNifre: ,(defn undef [symbol] (ns-unmap *ns* symbol))

12:29 sdegutis: WHA

12:29 clojurebot: #'sandbox/undef

12:29 sdegutis: i think whoever writes clojurebot wised up after i did this last time (2013 maybe?)

12:29 RedNifre: (def backupinc inc)

12:29 ,(def backupinc inc)

12:29 clojurebot: #'sandbox/backupinc

12:29 RedNifre: ,(undef inc)

12:29 clojurebot: #error {\n :cause "clojure.core$inc cannot be cast to clojure.lang.Symbol"\n :via\n [{:type java.lang.ClassCastException\n :message "clojure.core$inc cannot be cast to clojure.lang.Symbol"\n :at [clojure.core$ns_unmap invokeStatic "core.clj" 4048]}]\n :trace\n [[clojure.core$ns_unmap invokeStatic "core.clj" 4048]\n [clojure.core$ns_unmap invoke "core.clj" 4048]\n [sandbox$undef invokeStatic ...

12:30 sdegutis: ,(ns-unmap 'clojure.core 'map)

12:30 clojurebot: nil

12:30 sdegutis: (map inc [1 2 3])

12:30 ,(map inc [1 2 3])

12:30 clojurebot: #error {\n :cause "Attempting to call unbound fn: #'clojure.core/map"\n :via\n [{:type java.lang.IllegalStateException\n :message "Attempting to call unbound fn: #'clojure.core/map"\n :at [clojure.lang.Var$Unbound throwArity "Var.java" 43]}]\n :trace\n [[clojure.lang.Var$Unbound throwArity "Var.java" 43]\n [clojure.lang.AFn invoke "AFn.java" 36]\n [sandbox$eval399 invokeStatic "NO_SOURCE_FIL...

12:30 sdegutis: HAHAHAHA

12:30 oh wait

12:30 oops. sorry everyone.

12:30 mike7: ,(loop for c across "abc" collect c)

12:30 clojurebot: #error {\n :cause "loop requires a vector for its binding in sandbox:"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "loop requires a vector for its binding in sandbox:"\n :at [clojure.core$loop invokeStatic "core.clj" 4425]}]\n :trace\n [[clojure.core$loop invokeStatic "core.clj" 4425]\n [clojure.core$loop doInvoke "core.clj" 4419]\n [clojure.lang.RestFn invoke "RestFn.java...

12:30 RedNifre: Hm, did you assign map to a backup var first or is it now gone forever?

12:31 sdegutis: ,(do (ns clojure.core) (defn map "Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments. Returns a transducer when no collection is provided." {:added "1.0" :static true

12:31 } ([f] (fn [rf] (fn ([] (rf)) ([result] (rf result)) ([result input] (rf result (f input))) ([result input & inputs] (rf result (apply f input inputs)))))) ([f coll] (lazy-seq (when-let [s (seq coll)] (if (chunked-seq? s) (let [c (chunk-first s) size (int (count c)) b (chunk-buffer size)] (dotimes [i size] (chunk-append b (f (.nth c i)))) (chunk-cons (chunk b) (map f (chunk-rest s)))) (cons (f (first s)) (map f (rest s)

12:31 )))))) ([f c1 c2] (lazy-seq (let [s1 (seq c1) s2 (seq c2)] (when (and s1 s2) (cons (f (first s1) (first s2)) (map f (rest s1) (rest s2))))))) ([f c1 c2 c3] (lazy-seq (let [s1 (seq c1) s2 (seq c2) s3 (seq c3)] (when (and s1 s2 s3) (cons (f (first s1) (first s2) (first s3)) (map f (rest s1) (rest s2) (rest s3))))))) ([f c1 c2 c3 & colls] (let [step (fn step [cs] (lazy-seq (let [ss (map seq cs)] (when (every? identity ss)

12:31 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

12:31 sdegutis: (cons (map first ss) (step (map rest ss)))))))] (map #(apply f %) (step (conj colls c3 c2 c1)))))))

12:31 hmm

12:31 yeah we'll just have to wait til clojurebot resets its jvm which afaik happens every few minutes

12:31 my bad.

12:31 RedNifre: Or you just write a new map, using for or something :)

12:32 sdegutis: Smart RedNifre.

12:32 ,map

12:33 clojurebot: #object[clojure.core$map 0x753294f6 "clojure.core$map@753294f6"]

12:33 sdegutis: its back i guess

12:34 RedNifre: ,(defn varargs [a & b] (vector a b))

12:34 clojurebot: #'sandbox/varargs

12:34 RedNifre: ,(varargs 1 2)

12:34 clojurebot: [1 (2)]

12:34 RedNifre: ,(varargs 1)

12:34 clojurebot: [1 nil]

12:34 RedNifre: Why does the vararg parameter turn into nil instead of () ?

12:35 sdegutis: ,(apply (repeat 5 varargs))

12:35 clojurebot: #error {\n :cause "Wrong number of args (1) passed to: core/apply"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (1) passed to: core/apply"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.RestFn invoke "RestFn.java" 412]\n [sandbox$eval118 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox...

12:35 RedNifre: Is it because nil is falsy so it's easier to check whether there are any extra args?

12:35 sdegutis: ,(apply apply (repeat 5 varargs))

12:35 clojurebot: #error {\n :cause "Don't know how to create ISeq from: sandbox$varargs"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "Don't know how to create ISeq from: sandbox$varargs"\n :at [clojure.lang.RT seqFrom "RT.java" 542]}]\n :trace\n [[clojure.lang.RT seqFrom "RT.java" 542]\n [clojure.lang.RT seq "RT.java" 523]\n [clojure.lang.RT cons "RT.java" 662]\n [clojure.core$cons__4331 ...

12:35 sdegutis: I'm confused.

12:35 RedNifre: because it probably uses 'next

12:35 RedNifre: ,(varargs 1 2 3 4)

12:35 clojurebot: [1 (2 3 4)]

12:36 RedNifre: sdegutis I don't understand that explanation, what's 'next?

12:36 sdegutis: ,(map (juxt next rest) [[] [1] [1 2]])

12:36 clojurebot: ([nil ()] [nil ()] [(2) (2)])

12:36 sdegutis: Hmm. That wasn't very clear.

12:36 RedNifre: sorry i meant #'next but yeah i could be wrong

12:36 RedNifre: Well, I understand nothing since I just started with the Joy of Clojure book :)

12:37 sdegutis: RedNifre: ok

12:37 bbl

12:38 RedNifre: Speaking of JoC, they write that they prefer to always use numbered % e.g. #(bla %1). I find that strange, why number parameters if there's only one? Isn't #(bla %) simpler in this case? Why number it?

12:39 ridcully: % is just fine; using %1 %2 i find polite to signal, that there is some higher arity at work

12:42 RedNifre: ,(defn fib ([1] 1) ([2] 1) ([n] (- n 2) (- n 1))))

12:42 clojurebot: #error {\n :cause "Unsupported binding form: 1"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.Exception: Unsupported binding form: 1, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.Exception\n :message "Unsupported binding form: 1"\n :at [clojure.core$destructure$pb__5167 invoke "core.clj" ...

12:42 RedNifre: What's the correct way to write what I mean?

12:42 sdegutis: Hi!

12:42 RedNifre: howdy

12:42 ,(defn fib ([1] 1) ([2] 1) ([n] (- n 2) (- n 1))))

12:42 clojurebot: #error {\n :cause "Unsupported binding form: 1"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.Exception: Unsupported binding form: 1, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.Exception\n :message "Unsupported binding form: 1"\n :at [clojure.core$destructure$pb__5167 invoke "core.clj" ...

12:42 RedNifre: :/

12:42 amalloy: RedNifre: there's no pattern matching

12:43 but also (- n 2) (- n 1) doesn't make sense even if there were

12:43 RedNifre: why not?

12:43 Yeah, I meant ([n] (+ (fib (- n 2)) (fib (- n 1))))

12:44 So how to write this correctly then?: (defn fib ([1] 1) ([2] 1) ([n] (+ (fib (- n 2)) (fib (- n 1)))))

12:47 ridcully: RedNifre: http://rosettacode.org/wiki/Fibonacci_sequence#Clojure

12:49 sdegutis: Good evening.

12:50 amalloy: hmm, his pattern matching idea would be really cool though

12:50 It'd be like a version of defn that has core.match built in.

12:50 That said, I would have basically no need for it ever.

12:50 The only time I /might/ use it is to replace uses of defmulti/defmethod.

12:50 But even then, I might as well just use (case x) within the (defn foo [x] ...)

12:51 RedNifre: Thanks for the rosetta link ridcully. Hm, core.match sounds like it might be interesting as well, I'll check that out next.

12:51 justin_smith: the big gotcha is if you combine core.match with things like core.logic or core.async in the same code, it is easy to get method-too-large errors

12:52 RedNifre: what's a method-too-large error?

12:52 justin_smith: the jvm has a maximum method size for the resulting bytecode

12:52 ridcully: RedNifre: there is also https://github.com/killme2008/defun - i have never tried it, but it looks like it could make your initial version working (it uses core match under the hood)

12:53 justin_smith: RedNifre: since core.async, core.logic, and core.match all do a lot of code generation, combining them can hit that limit

12:53 RedNifre: Uhm, I thought the bytecode limit was 64KiB? Shouldn't that be enough for everybody?

12:53 justin_smith: RedNifre: you haven't macroexpanded core.async code have you

12:55 RedNifre: huh, interesting.

12:55 did that ever happen to you? if so, what did you do about it?

12:55 amalloy: i mean, core.match has something like defn built in. defne or something

12:55 justin_smith: RedNifre: https://gist.github.com/noisesmith/0fd7db0d239113c1d0c8

12:55 amalloy: RedNifre: you can macroexpand into some pretty silly stuff

12:56 i actually saw a co-worker go over the 64KB limit in java

12:56 * justin_smith tries pulling in core.match to see what that expansion would look like...

12:56 RedNifre: I'm new to clojure so I don't know what "macroexpand" means. Does it mean looking at the code that gets compiled after all macros got expanded?

12:57 justin_smith: RedNifre: exactly

12:57 amalloy: basically by trying to hard-code a several-megabyte Map<String, String>, using sed or something to produce a series of .put calls from a text file

12:57 justin_smith: amalloy: nice

12:57 RedNifre: okay, so core-async sounds like it contains macros that add a lot of "synchronized" and locks and stuff like that everywhere?

12:58 amalloy: RedNifre: a lot of things you do are macros underneath, some of them quite involved

12:58 ,(macroexpand-1 '(for [x (range 10), y [x (- x)]] (/ y 10)))

12:58 clojurebot: (clojure.core/let [iter__5216__auto__ (clojure.core/fn iter__27 [s__28] (clojure.core/lazy-seq (clojure.core/loop [s__28 s__28] (clojure.core/when-first [x s__28] (clojure.core/let [iterys__5212__auto__ (clojure.core/fn iter__29 [s__30] (clojure.core/lazy-seq #)) fs__5213__auto__ (clojure.core/seq (iterys__5212__auto__ #))] (if fs__5213__auto__ (clojure.core/concat fs__5213__auto__ (iter__27 #)) (...

12:58 hiredman: the go macro in core.async doesn't expand to any calls to thing like syncronized (locking)

12:58 RedNifre: Well, generating a lot of .put calls in Java from a text file through sed is kinda the same as using macros in clojure, huh?

12:58 amalloy: well, try that in your repl; it's much too large to fit here

12:59 RedNifre: can macros read external files?

12:59 hiredman: the locking is all inside the channel operations

12:59 amalloy: RedNifre: the difference is that in clojure you can use clojure

12:59 sdegutis: ,(defn correct-answer-for [q] (->> q (reverse) (apply str) (read-string) (name) (reverse) (apply str)))

12:59 clojurebot: #'sandbox/correct-answer-for

12:59 sdegutis: ,(correct-answer-for "Which is better? Ice cream or pizza")

12:59 amalloy: in java you ahve to use sed

12:59 clojurebot: "pizza"

12:59 sdegutis: ,(correct-answer-for "sdegutis is better at Clojure than amalloy: true or false")

12:59 clojurebot: "false"

12:59 RedNifre: i.e. could I have a macro (big-string-map-from-file "stuff.txt") that expands into a giant map with the text file in it?

12:59 sdegutis: ,(defn correct-answer-for [q] (->> q (reverse) (apply str) (read-string) (name) (reverse) (apply str) (read-string)))

12:59 clojurebot: #'sandbox/correct-answer-for

13:00 amalloy: RedNifre: you can, but you generally shouldn't

13:00 ridcully: RedNifre: yes, that works. i found that a nice way to have configs etc in clojurescript

13:01 sdegutis: ,(defn correct-answer-for [q] (->> q (reverse) (apply str) (read-string) (name) (reverse) (remove #{\?}) (apply str) (read-string)))

13:01 clojurebot: #'sandbox/correct-answer-for

13:01 justin_smith: RedNifre: https://gist.github.com/noisesmith/db3b90abb6b9e5f7f282

13:01 sdegutis: (correct-answer-for "Will the Bears ever win the super bowl again? I mean, probably not, right?")

13:01 ,(correct-answer-for "Will the Bears ever win the super bowl again? I mean, probably not, right?")

13:01 clojurebot: right

13:01 sdegutis: Best function ever.

13:02 ,(correct-answer-for "Who's better at Clojure than rhickey?")

13:02 clojurebot: rhickey

13:02 sdegutis: touché clojurebot.

13:03 * RedNifre reads links

13:04 RedNifre: Wow, those macro expands look incomprehensible to me.

13:04 justin_smith: hey, I pprinted the second one

13:04 RedNifre: ,(correct-answer-for "Which language should I use when I'm done learning Clojure?")

13:04 clojurebot: Clojure

13:04 RedNifre: hmkay.

13:05 ,(correct-answer-for "Whazzap?")

13:05 clojurebot: Whazzap

13:05 justin_smith: RedNifre: usually the macroexpansion is irrelevant if the macro is well written and used properly, there's just the size gotcha, as I was mentioning, for the crazy ones

13:06 ones where a whole mini language is implemented in a macro

13:06 RedNifre: Yeah, I get that. You saved me from future "Hey, why is my jar so big?"-moments.

13:06 justin_smith: well, the expanded code shouldn't usually end up in the jar

13:06 and you can avoid aot too pretty easily

13:06 RedNifre: huh?

13:07 I thought macros always expand? Or can you compile them as function calls?

13:07 justin_smith: RedNifre: all you need in a jar is the clojure source.

13:07 RedNifre: hmmmm

13:07 justin_smith: the expansion happens at compilation, which in clojure happens during startup usually.

13:07 RedNifre: I thought that was unusual and you usually compile to java bytecode?

13:08 justin_smith: RedNifre: avoiding aot if possible is usually better almost always

13:08 RedNifre: That's surprising. Why?

13:08 What's the advantage of a jar full of source code other than the jar size?

13:09 justin_smith: when you aot compile you can end up in a state where the source code conflicts with the byte code on disk

13:09 wacky scenarios like two classes with the same exact name that are not identical

13:10 and one extends the protocol you are using and the other does not

13:10 most of it comes down to caching issues I think, since laoding byte code and loading the source are two equally valid ways to get the same ns

13:12 OscarZ_: anyone familiar with cemerick/friend ring auth library?

13:13 sdegutis: Good morning.

13:14 justin_smith: RedNifre: also, when you deploy a library, to compile your byte code means you tie your user to the exact library code you developed with, which can interfere with the correctness of their own code

13:15 so while aot in an app is debatable (I'd argue minimize the amount of code that gets aot compiled as much as possible), you should strictly never aot compile libraries if you want anyone to ever use them

13:28 RedNifre: I understand that the JVM has no tail call optimization... but why do I have to use recur? Can't the compiler figure out that I want TCO whenever possible?

13:29 justin_smith: RedNifre: yes, but by requiring the usage of recur we can catch the otherwise common error that someone assumes TCO is applied where it can't be

13:29 RedNifre: this is a big problem in cl / scheme worlds where it is implicit

13:29 RedNifre: fair point.

13:30 justin_smith: because you don't even see the problem until you get a big enough stack at runtime

13:56 OscarZ_: i have a compojure route like this (route/resources "/static") and i'd like to secure this with cemerick/friend library.. i can use macro called "authenticated" to protect any function, but i guess in this case i dont have a function

14:52 sdegutis: OscarZ_: I've avoided Friend because its API design didn't quite fit into my application. It's not hard to roll your own solution though.

15:39 justin_smith: I've avoided friend because I'm just too dumb to figure out how I should use it

16:05 sdegutis: Why is this returning nil?

16:05 ,(re-matches #"\<h1\>" "<h1>foo")

16:05 clojurebot: nil

16:06 sdegutis: Help me #clojure, you're my only hope.

16:06 TMA: ,(re-matches #"<h1>" "<h1>foo")

16:06 clojurebot: nil

16:07 TMA: ,(re-matches #"[<]h1[>]" "<h1>foo")

16:07 clojurebot: nil

16:07 TMA: sdegutis: no idea. everything apparently does

16:08 sdegutis: ,(re-matches #".*\<h1\>.*" "foo<h1>bar")

16:08 clojurebot: "foo<h1>bar"

16:08 sdegutis: That almost works:

16:08 ,(re-matches #".*\<h1\>.*" "quux \n foo<h1>bar")

16:08 clojurebot: nil

16:08 sdegutis: But it ignores everything after the first newline.

16:08 TMA: ,(re-matches #"\<h1\>" "<h1>")

16:08 clojurebot: "<h1>"

16:09 TMA: ,(re-matches #"\_.*\<h1\>" "<h1>")

16:09 clojurebot: nil

16:09 TMA: (doc re-matches)

16:09 justin_smith: ,(re-matches #"<h1>" "<h1>")

16:09 clojurebot: "([re s]); Returns the match, if any, of string to pattern, using java.util.regex.Matcher.matches(). Uses re-groups to return the groups."

16:09 "<h1>"

16:09 justin_smith: you don't need to escape anything in that re

16:09 and it needs to match the whole string, not just a substring

16:10 TMA: ,(re-matches #"(.|\n)*\<h1\>" "<h1>")

16:10 clojurebot: ["<h1>" nil]

16:10 sdegutis: Oh.

16:10 TMA: ,(re-matches #"(?:.|\n)*\<h1\>" "<h1>")

16:10 clojurebot: "<h1>"

16:10 justin_smith: TMA: you don't need to escape < or >

16:10 ,(re-matches #"<h1>\w+" "<h1>foo")

16:10 clojurebot: "<h1>foo"

16:11 TMA: justin_smith: yeah, i have read that when you told it before, it does not hurt either

16:11 sdegutis: Hmm, I'm going about this all wrong.

16:11 justin_smith: it hurts readability

16:11 ,(re-matches #"<h1>(\w+)" "<h1>foo")

16:11 clojurebot: ["<h1>foo" "foo"]

16:11 TMA: sdegutis: use (?:.|\n)* instead of .*

16:11 sdegutis: Given a multi-line string, how can return all occurreeanncces of #"<h\d>" ?

16:12 I have no idea how to spell ocurances.

16:12 TMA: sdegutis: occurences

16:12 sdegutis: You sure? That doesn't look right.

16:12 ocurrances?

16:12 TMA: nothing does at the moment

16:12 justin_smith: there's also a flag to make . match newlines

16:13 TMA: sdegutis: I am patently sure there is no -a- in that word

16:13 sdegutis: I'm not so sure.

16:13 justin_smith: how do you specify that flag in a regex Clojure literal?

16:13 ,#"foo"g

16:13 clojurebot: #"foo"

16:13 sdegutis: Hmm.

16:13 ,#"foo" you suck

16:13 clojurebot: #"foo"

16:13 sdegutis: hahah clojurebot sucks

16:14 Oh!

16:14 (?m) at the beginning?

16:14 Yes!

16:14 justin_smith: ,(re-matches #"(?m).*<h1>(\w+)" "\n <h1>foo")

16:14 clojurebot: nil

16:14 sdegutis: (re-find #"(?m)(<h1>)" "foo\nbar<h1>quux")

16:14 ,(re-find #"(?m)(<h1>)" "foo\nbar<h1>quux")

16:14 clojurebot: ["<h1>" "<h1>"]

16:14 justin_smith: sdegutis: hmm, worked in my local

16:14 sdegutis: Yay!

16:15 justin_smith: nice

16:15 TMA: sdegutis: there are two -r-s but still no -a-: http://www.merriam-webster.com/dictionary/occurrence

16:15 sdegutis: TMA: I'm not so sure.

16:15 "occurrence"

16:16 huh, yeah

16:16 weird.

16:17 Woo!

16:17 ,(re-seq #"(?m)<h\d>" "foo\nbar<h1>quux<h2>")

16:17 clojurebot: ("<h1>" "<h2>")

16:17 sdegutis: take THAT, clojurebot!

16:20 backnforth: hiberno

16:20 Hey

16:20 Should I use sequences or lists?

16:23 Sorry.. I'm new to clojure.

16:23 TMA: sdegutis: it is a common misspelling (because there are other words like "happenstance" where there is a -stance and there is -currant (blackcurrant) with an -a-) -- the reason for the -e- is that in latin the verb is occurro, occurrere, occurri, occursum; with present participle occurrens [from the unprefixed curro, currere, cucuri, cursum there is english current, currency, course, ...]

16:24 backnforth: lists are a specific kind of sequences

16:24 sdegutis: backnforth: lists, always lists

16:24 backnforth: avoid anything that conforms to (sequence?), always use lists

16:25 TMA: backnforth: notwithstanding the advice of sdegutis, I would consider arrays or lazy sequences too, on a case-by case basis

16:25 sdegutis: ,(map (juxt sequential? map? list? vector? seq?) [() [] #{} {} (lazy-seq)])

16:25 clojurebot: ([true false true false true] [true false false true false] [false false false false false] [false true false false false] [true false false false true])

16:26 backnforth: Sequences are a multi dimensional list to my understanding. Although, yes I would prefer to use arrays.

16:26 sdegutis: ,(map (juxt sequential? map? set? list? vector? seq?) [() [] #{} {} (lazy-seq)])

16:26 clojurebot: ([true false false true false ...] [true false false false true ...] [false false true false false ...] [false true false false false ...] [true false false false false ...])

16:26 sdegutis: backnforth: see that clode

16:26 backnforth: clode is short for Clojure code. It's a shorthand way of saying "Clojure code"

16:27 backnforth: I don't understand. I'm new to lisp structured.

16:28 But yes, there are other structures I could use.

16:29 TMA: backnforth: if you need to quickly prepend an item to a beginning of a sequence, use lists. if to the end, use vector, if you need random element access (give me the 3rd, give me the 7th, ...) use vector

16:29 backnforth: if the data might be infinite (like sequence of all primes) use lazy-seq

16:30 backnforth: if the computation is expensive and you might not need all the elements use lazy-seq

16:32 backnforth: I assume lazy-sequences have better jumps.

16:32 TMA: backnforth: and finally, when you need a set use a set, whereas when you need a key->value store use a map

16:33 backnforth: What are sets?

16:34 TMA: backnforth: #{} ... you represent whether an element belongs to/is contained in the set

16:35 backnforth: instead of list of visited nodes, you keep a set of them, so that you do not need to traverse the entire list every time to find out, whether a node was visited

16:36 backnforth: Ah

16:37 I should read on sets.. How do I works with the values in a list.. I can't find anything about them in the clojure.org reference

16:40 TMA: backnforth: you mostly take the value out of the list and work with the value -- there is nothing magical with the value caused by it being (also) in a list

16:42 backnforth: I'm looking for syntax

16:42 TMA: backnforth: say you have a list of your friends, say Jo, Alex and Xi ... if you write the list of friends somewhere you still interact with the persons the same way as if there were no list

16:43 oh

16:43 conj prepends an element to a list

16:43 ,(first '(a b c))

16:43 clojurebot: a

16:43 TMA: ,(rest '(a b c))

16:43 clojurebot: (b c)

16:44 TMA: and you can use first and rest to get to the elements

16:44 ,(conj '(a b c) 'd)

16:44 clojurebot: (d a b c)

16:45 TMA: to get to the b you can:

16:45 ,(first (rest '(a b c)))

16:45 clojurebot: b

16:45 backnforth: How do I simply read the value? And how do I read the index?

16:46 TMA: in list there is no index

16:47 backnforth: I have shown you how to read the first and second element of the list.

16:47 justin_smith: backnforth: you can get an item by index with nth, but you can't find any info about the list (including index or anything else) from the item

16:47 sdegutis: TMA: i dont think lazy seqs are still recommended for infinite data

16:47 TMA: i think the new recommended approach is transducers

16:47 justin_smith: ,(nth 3 [:a :b :c :d :e :f :g :h])

16:47 clojurebot: #error {\n :cause "clojure.lang.PersistentVector cannot be cast to java.lang.Number"\n :via\n [{:type java.lang.ClassCastException\n :message "clojure.lang.PersistentVector cannot be cast to java.lang.Number"\n :at [sandbox$eval121 invokeStatic "NO_SOURCE_FILE" -1]}]\n :trace\n [[sandbox$eval121 invokeStatic "NO_SOURCE_FILE" -1]\n [sandbox$eval121 invoke "NO_SOURCE_FILE" -1]\n [clojure.lang....

16:48 justin_smith: ,(nth [:a :b :c :d :e :f :g :h] 3)

16:48 clojurebot: :d

16:51 backnforth: List test[:a :b :c]

16:51 ,(nth test 3)

16:51 clojurebot: #error {\n :cause "nth not supported on this type: core$test"\n :via\n [{:type java.lang.UnsupportedOperationException\n :message "nth not supported on this type: core$test"\n :at [clojure.lang.RT nthFrom "RT.java" 888]}]\n :trace\n [[clojure.lang.RT nthFrom "RT.java" 888]\n [clojure.lang.RT nth "RT.java" 854]\n [sandbox$eval169 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox$eval169 invoke "NO...

16:52 backnforth: list test [:a :b :c]

16:52 ,(nth test 3)

16:52 clojurebot: #error {\n :cause "nth not supported on this type: core$test"\n :via\n [{:type java.lang.UnsupportedOperationException\n :message "nth not supported on this type: core$test"\n :at [clojure.lang.RT nthFrom "RT.java" 888]}]\n :trace\n [[clojure.lang.RT nthFrom "RT.java" 888]\n [clojure.lang.RT nth "RT.java" 854]\n [sandbox$eval193 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox$eval193 invoke "NO...

16:53 backnforth: list test [:a :b :c] ,(nth test 2)

16:53 TMA: backnforth: saying "list test whatever" does not have any effect on clojurebot

16:53 backnforth: Was that the right syntax?

16:54 sdegutis: backnforth: that's closer to haskell

16:54 ddellacosta: &(let [test [:a :b :c]] (nth test 2))

16:54 TMA: ,(let [variable [:a :b :c]] (nth variable 2))

16:54 ddellacosta: oh, guess lazybot no longer runs

16:54 clojurebot: :c

16:54 ddellacosta: ,(let [test [:a :b :c]] (nth test 2))

16:54 clojurebot: eval service is offline

16:55 ddellacosta: yeah, thanks so much hiredman

16:55 nevermind

16:55 TMA: ,test

16:55 clojurebot: #object[clojure.core$test 0x45d4887d "clojure.core$test@45d4887d"]

16:55 backnforth: ,variable

16:55 clojurebot: #error {\n :cause "Unable to resolve symbol: variable in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: variable in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: variabl...

16:56 backnforth: ,test

16:56 clojurebot: #object[clojure.core$test 0x45d4887d "clojure.core$test@45d4887d"]

16:56 TMA: backnforth: test is a name, that is already predefined

16:56 backnforth: I like you, clojurebot.

16:56 TMA: backnforth: on the other hand, variable is not predefined

16:57 backnforth: Ok

16:57 TMA: that's why there is a difference when evaluating them

17:32 GroundhogTest: My speclj tests will not fail.

17:35 justin_smith: GroundhogTest: are you doing the classic (should [1] vector-of-1) thing and forgetting the =?

17:36 actually maybe that only happens in clojure.test

17:37 GroundhogTest: I don't think so. I was using (around [it] (with-out-str it)), though.

17:38 Removed that, added a throw to my first test, and finally got a failure

17:38 justin_smith: interesting

17:38 yeah, I just checked, should doesn't take multiple args like clojure.test/is anyway

17:41 GroundhogTest: Thinking about putting the around call back in to confirm, but hesitant to make my tests completely useless on purpose

18:55 backnforth: How do I create an incrementing for loop like for(i=0;i<n;i++) ... is it: for((range n n+4))

18:57 rhg135: my brain hurts from the lack of intent. I think that'd be like (dotimes [i 4] ...)

18:58 amalloy: rhg135: don't provice useless answers to useless questions. figure out how to get enough information that the question becomes useful

18:59 backnforth: I'm just looking to do a basic loop

19:00 using some constant as a range

19:00 ... the reason for doing is to interact through a list to compare its values with some other value.

19:00 rhg135: amalloy: usually I would, but the sensible part of my brain is asleep

19:00 or dead or stuff

19:05 backnforth: How would I iterate through some list, compare its values with some value, then put values into a new list?

19:05 The program is to: take some value n, check the list if there exist some value n, then put the locations that n exist in the list into some other list.

19:08 I really want to learn clojure

19:16 amalloy: backnforth: what do you mean, the locations? what is a location?

19:20 rhg135: probably indices

20:42 troydm: let's say I have character \space, how do I make Clojure print it in a form of \space instead of space character, e.g. unescaped form?

20:47 Malnormalulo: quote it?

20:47 ,'\space

20:47 clojurebot: \space

20:48 Malnormalulo: nope nevermind that doesn't work for print. Hm, that's a puzzle

20:50 amalloy: ,(pr \space)

20:50 clojurebot: \space

20:50 amalloy: don't use print for anything except like...honestly there are not a lot of good reasons to use print

20:51 the pr family of functions is great for printing data readably and unambiguously, and print does a mediocre job of producing human-friendly text

21:02 troydm: amalloy: thx

21:02 also is there a way to attach comment to variable definition

21:02 when u defn function you can add description to it

21:03 but I was wondering if it's possible to add description to arbitary variable too

21:03 Common Lisp has this kind of functionality I think

21:07 Malnormalulo: troydm: def accepts doc strings before the value

21:07 troydm: ,(def a "doc" 1)

21:07 clojurebot: #'sandbox/a

21:07 troydm: ,(pr a)

21:07 clojurebot: 1

21:08 troydm: ic, thx

21:08 Malnormalulo: ,(meta (def a "doc" 1))

21:08 clojurebot: {:line 0, :column 0, :file "NO_SOURCE_PATH", :doc "doc", :name a, ...}

21:13 TimMc: amalloy: What do you mean? println is great when you want to print strings.

21:14 amalloy: okay true. if you have something that's already a string, print and friends are good

21:16 troydm: also I've deftype'd some type and I defn'd some mytype? function which is basicly (= (type %) mytype) is this correct way to handle checking if object is of particular type?

21:23 Malnormalulo: It should work, but you might consider using a protocol instead, if you've got a method whose behavior depends on its argument's type

21:25 *if you've got a function

21:25 (curse my hours every day spent in Java)

22:50 ajb-: Why is bit shift left output on the jvm different from the output in the browser?

22:50 TimMc: ajb: Different numerics between JVM and JS.

22:50 Example?

22:51 ajb: ,(bit-shift-left 53245 16)

22:51 clojurebot: 3489464320

22:51 ajb: so that's the jvm, and the js output of `53245 << 16` is -805452285

22:53 amalloy: javascript doesn't have integers

22:53 so a lot of things are wacky

22:55 TimMc: 1 << 32 // 1

22:56 ,(bit-shift-left 1 32)

22:56 clojurebot: 4294967296

22:56 TEttinger: ,(unchecked-int (bit-shift-left 1 32))

22:56 clojurebot: 0

22:57 TEttinger: ajb: I'd strongly distrust JS when it tries to do any bit twiddling

22:58 ajb: yeah, well I need to since I am trying to render reagent on the server and react requires a checksum for the dom

22:58 I wish I didn't have to do any of this in js

22:58 TEttinger: I'd check for any libs that can compute the checksum

22:59 there may be someone who did this already

23:03 not sure how easy it is to call JS from CLJS, but this might be port-able http://stackoverflow.com/a/3276730

23:03 ajb: in cljs it does <<, I'm trying to get the same behavior in clj

23:04 TEttinger: ah.

23:04 well cljs would be doing that on a float or double, I think, since JS doesn't have integers as amalloy said

23:05 kvey: js converts the number type to 32 bit ints for bitwise operations (via research)

23:07 TEttinger: ,(unchecked-int (bit-shift-left 53245 16))

23:07 clojurebot: -805502976

23:08 TEttinger: looks like what you want, almost. the lower bits are off

23:09 ,(Long/toHexString -805452285)

23:09 clojurebot: "ffffffffcffdc603"

23:10 TEttinger: that is not shifted over by 16...

23:10 ,(Long/toHexString (unchecked-int (bit-shift-left 53245 16)))

23:10 clojurebot: "ffffffffcffd0000"

23:11 TEttinger: it looks like the shift filled the lower bits with garbage?

23:11 in the JS one

23:11 thanks kvey for the 32-bit tip

23:12 oh. herp derp me

23:12 kvey: welcome - ajb and I work together

23:13 TEttinger: ,(let [b (Long/toBinaryString (bit-shift-left 53245 16))] [b (count b)])

23:13 clojurebot: ["11001111111111010000000000000000" 32]

23:13 ajb: oh, derp

23:13 TEttinger: I think it may be outside 32 bits

23:14 ajb: I just forgot to apply the bit-or to the return value

23:14 TEttinger: ah ok

23:14 bit-or?

23:14 I was thinking bit-and

23:14 ajb: but thank you, uncheck-ing it made it work

23:14 TEttinger: ah ok! good

23:15 unchecked-XXX stuff is also pretty fast

23:15 it's using something very similar to what Java would output in the same set of calls with operators on primitives

23:15 kvey: thanks! - I'd tried uncheck-int'ing the parameters but not the return value haha

23:16 TEttinger: yeah, surprising that clojure on JVM doesn't have smaller sizes of bit-whatever ops

23:16 kvey: the unchecked-int should be what's padding the result with garbage like that right?

23:17 whereas int throws an exception

23:18 TEttinger: no, I don't think so

23:18 hm

23:19 ,(unchecked-int 0xffff0001)

23:19 clojurebot: -65535

23:19 TEttinger: correct

23:19 ,(unchecked-int 0x00000001)

23:19 clojurebot: 1

23:19 TEttinger: ,(unchecked-int 0xf00000001)

23:20 clojurebot: 1

23:20 TEttinger: yeah, that last one truncated the bits above 32 correctly

23:21 unchecked casts are useful for when you want something to replicate java or possibly other languages' behavior

23:23 I think the garbage in the JS version (JVM had 16 0 bits where it had shifted over, JS has 16 random-seeming bits) was maybe the bit-or thing ajb mentioned and was a result of a later step?

23:23 so not actually garbage data, intentional just from a source I can't see

23:25 kvey: ah I see

23:25 makes sense

23:59 TimMc: ,(Long/toBinaryString -805502976)

23:59 clojurebot: "1111111111111111111111111111111111001111111111010000000000000000"

Logging service provided by n01se.net