2016-03-08
| 00:51 | AndreasO | (Select root [:#tag]) seesaw. How do I address the root widget? |
| 01:03 | TEttinger | AndreasO: I seem to remember a method that goes up in the hierarchy... let me check |
| 01:04 | TEttinger | http://daveray.github.io/seesaw/seesaw.core-api.html#seesaw.core/to-root |
| 01: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. |
| 01: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 |
| 01:15 | AndreasO | TEttinger: can I pass a tag? |
| 01:16 | TEttinger | you could select one first I think |
| 01:16 | TEttinger | do you not have the root to pass to select, so you can't use the tag for that reason? |
| 01:30 | AndreasO | TEttinger: I'm not sure what count as the root. |
| 01:30 | AndreasO | I'll bin the codefinger |
| 01:32 | AndreasO | TEttinger: pastebin.com/E63QbV7C |
| 01:33 | AndreasO | TEttinger: line 11-13 and 60-68 |
| 01:33 | AndreasO | Damn. Pastebin not codefinger |
| 01:33 | TEttinger | hm, well Draw shouldn't be capitalized |
| 01:37 | AndreasO | I've been banging my head for days. I made simple GUIs before, this is somwath more complicated. |
| 01:39 | TEttinger | ohhh |
| 01:39 | TEttinger | this looks oddly familiar |
| 01:39 | TEttinger | I seem to recall a swing thread thing that the demos used |
| 01:40 | TEttinger | see the thing with invoke-later ? https://github.com/daveray/seesaw#tldr |
| 01:42 | AndreasO | I found a nother mistake now, draw needs one more arg... g2d? |
| 01:46 | TEttinger | seems to be a Graphics2D, doesn't look like that section is meant to be used often |
| 01:48 | TEttinger | https://github.com/daveray/seesaw/blob/master/test/seesaw/test/examples/clock.clj uses it |
| 01:51 | AndreasO | I'll try that. |
| 01:51 | TEttinger | it seems to be a :paint related thing |
| 01:51 | AndreasO | I might be overthinking this. |
| 01:52 | TEttinger | so you can call g2d-taking methods when you're in a fn that is called as a callback from :paint |
| 01:52 | TEttinger | since :paint gives the current g2d with it |
| 01:53 | AndreasO | Okay |
| 01:53 | TEttinger | also the require statement at the top seems weird, two slashes is not normally what I see |
| 01:54 | TEttinger | it may be because it isn't used yet that it isn't causing trouble |
| 01:55 | AndreasO | You mean the photomath? |
| 01:56 | TEttinger | YEAH |
| 01:56 | TEttinger | yeah |
| 01:58 | AndreasO | Well that's my own lib. It worked well in a nother test I did. |
| 02:02 | AndreasO | I'll look into the clock example, hopefully I'll get it. :-) |
| 02:02 | TEttinger | hm, not sure where the / is appropriate in those require sections |
| 02:02 | TEttinger | it's the part at the bottom |
| 02:03 | TEttinger | (canvas :id :canvas :background "#BBBBBB" :paint paint-clock) |
| 02:03 | TEttinger | paint-clock is called with a g2d as one of its args |
| 02:04 | AndreasO | Thanks! |
| 02: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" |
| 02:06 | TEttinger | 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 |
| 02:08 | AndreasO | I see, seems a redesign is in order. |
| 02:10 | AndreasO | (run :dispose)? |
| 02:17 | AndreasO | TEttinger: still there? |
| 02:22 | TEttinger | yeah |
| 02:22 | TEttinger | it does seem like it needs some moving around |
| 02:22 | TEttinger | graphics-related stuff needs to essentially modify a canvas or something like it... I think.... |
| 02: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. |
| 02:24 | TEttinger | hm? |
| 02:25 | TEttinger | :paint is given a fn, it calls it whenever it repaints |
| 02:25 | TEttinger | I don't think config! would help here since it would just change the fn but not tell it to use it |
| 02:27 | AndreasO | Hmm... I see. Maybe I can put values in a vector that the :paint function reads . |
| 02:29 | AndreasO | The lines and dots need to bee saved anyway. |
| 02:29 | TEttinger | makes sense, I think |
| 02:29 | TEttinger | if they change you might want them in an atom, or you might want to pass them into the next update somehow |
| 02:32 | AndreasO | I did something similar in Python. APOS80 |
| 02:33 | AndreasO | GitHub.com/APOS80/GeoCad |
| 02:34 | AndreasO | Some things is made to be mutable.:-) |
| 02:47 | AndreasO | TEttinger: thank you!!! I have now painted a circle!! |
| 02:48 | TEttinger | woohoo! |
| 02:49 | TEttinger | yeah, the examples for seesaw were the most valuable resource I had trying to learn it |
| 02:49 | TEttinger | 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 |
| 02:50 | TEttinger | she had bizarre nutrition constraints, like couldn't have much phosphorus, and that isn't on most labels |
| 02:51 | AndreasO | For some reason I always try things that don't work instead of doing it right in the first place. |
| 02:51 | TEttinger | GUI is much better for grandma than CLI, haha |
| 02:51 | AndreasO | I like cli, but a cad in cli?? Nono |
| 02:51 | p_l | AndreasO: ever seen AutoCAD? |
| 02:52 | AndreasO | I use topical at work |
| 02:52 | p_l | or BRL-CAD (which is even more CLI-oriented) |
| 02:52 | amalloy | ed | cad |
| 02:52 | AndreasO | Topocad |
| 02:53 | p_l | also, OpenSCAD seems to be currently popular thingy on the lower end |
| 02:53 | AndreasO | Hmmm... What graphical lib is used for cli? |
| 02:53 | p_l | Cadence CAD tools aren't CLI oriented, but IIRC include Lisp REPL :) |
| 02:54 | TEttinger | OpenSCAD is good |
| 02:54 | p_l | AndreasO: depends on environment - a CAD can have CLI despite being very graphical (the interaction might be through CLI) |
| 02:55 | p_l | https://en.wikipedia.org/wiki/OpenSCAD#/media/File:Openscad_screen_english.png <--- example from openscad |
| 02:55 | p_l | https://upload.wikimedia.org/wikipedia/commons/e/eb/BRL-CAD_screenshot.jpeg <--- upper left corner has the main editor interface, iirc |
| 02:56 | p_l | AndreasO: quite possibly lots of old CAD tools worked well in xterm thanks to its vector graphics support, too :) |
| 02:59 | AndreasO | True, but isn't a little more complicated? |
| 02:59 | p_l | AndreasO: not necessarily. And can be a godsend when you need to manipulate precisely |
| 03:00 | p_l | AutoCAD had very good interface in this which coupled command line with mouse/tablet |
| 03:01 | p_l | for example, how easy it is to convey by mouse that you want exactly X milimeters? |
| 03:02 | AndreasO | Isn't autocad written in lisp? |
| 03:02 | AndreasO | Heard that |
| 03:02 | p_l | and most of those CAD programs are directly extensible (AutoCAD with AutoLisp, Cadence stuff in SKILL - a lisp dialect, etc) |
| 03:02 | p_l | AndreasO: it isn't |
| 03:02 | p_l | it has a very old-school lisp dialect however |
| 03:03 | AndreasO | Like scheme? |
| 03:03 | p_l | used for interaction and automation (though, similarly to AutoCAD REPL, had been pushed to wayside) |
| 03:03 | p_l | AndreasO: Scheme is very modern lisp dialect :D |
| 03:03 | p_l | AutoLISP is old style, really old |
| 03:04 | p_l | older than elisp by now, because elisp evolved |
| 03:04 | p_l | last time I checked, AutoLISP still didn't have lexical scope |
| 03:16 | AndreasO | I'm new to lisp, I like it. |
| 05:28 | spba | Has anyone here worked through HtDP? |
| 05: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? |
| 05:43 | hyPiRion | ridcully: should be safe, yes |
| 05:44 | amalloy | ridcully: yes, it's intended to work fine. you can always distinguish from context whether a namespace is meant or a var |
| 05: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) |
| 06: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? |
| 06:25 | Empperi | clgv: check Edit -> Structural Editing |
| 06:25 | Empperi | you can bind those to any shortcuts you wish |
| 06:26 | clgv | Empperi: sure, but which one is it` |
| 06:26 | Empperi | well, I don't know what "CTRL+W" is so :) |
| 06:28 | clgv | "extend selection to the next full s-expression" is what I am looking for |
| 06:29 | clgv | "CTRL+W" is "extend selection" which will select all expressions with an s-expression, then the whole s-expression and so on |
| 06: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 |
| 06:30 | Empperi | ah yeah, it's that then |
| 06:30 | Empperi | it's in Idea itself |
| 06:30 | Empperi | search for "shrink selection" and "extend selection" in keymap bindings |
| 06:30 | Empperi | and it will work in every editor |
| 06:30 | clgv | I want (->> xs |(map bla)| (map blubb)) to (->> xs |(map bla) (map blubb)|) where the selected part is enclosed in | | |
| 06:31 | Empperi | ok, that's not then exactly the same thing :) |
| 06:31 | clgv | I am used to that from CCW ;) |
| 06:32 | Empperi | shrink/grow would grow from |(map bla)| to both left and right |
| 06:33 | Empperi | dunno if there's a selection functionality exactly for that |
| 06:33 | Empperi | cfleming will know if anyone knows :) |
| 06:33 | clgv | is there bugtracker for cursive? |
| 06:36 | ridcully | clgv: i used https://github.com/cursive-ide/cursive/issues the last time - still seems active |
| 06:38 | clgv | ridcully: ok, thanks |
| 06:38 | Empperi | yeah, that is the place |
| 06:38 | Empperi | Cursive itself isn't opensource |
| 06:39 | clgv | btw is (.-some_field some-deftype-instance) preferred over (.some-field some-deftype-instance) for field access on deftypes? |
| 06:39 | clgv | Cursive tries to convince me strongly |
| 07:04 | Empperi | well, deftypes compile to java classes |
| 07:04 | Empperi | and you can't name java fields into private Foo some-field; |
| 07:05 | Empperi | it's a syntax error |
| 07:05 | Empperi | sure they don't compile to java source code but same rules apply on bytecode level |
| 07:05 | Empperi | more or less |
| 07:05 | Empperi | so yeah, I'd say it's better to stick with those conventions |
| 07:06 | Empperi | not sure actually how that will work on bytecode, it just might work |
| 07:06 | Empperi | field names with - in them that is |
| 07:06 | Empperi | but if you try to access those from java code... |
| 07:07 | Empperi | so at least for the sake of java interop you should avoid those |
| 07: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? |
| 07:36 | Empperi | irctc: https://groups.google.com/d/msg/datomic/jYjWvut3v3E/GZeod3hYaRQJ |
| 07:36 | Empperi | from 2012 but I guess that's still correct |
| 07:37 | Empperi | however this seems to indicate that branching is currently supported http://vvvvalvalval.github.io/posts/2016-01-03-architecture-datomic-branching-reality.html |
| 07:38 | Empperi | much less official source though but also much more recent |
| 07: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 |
| 07:44 | hyPiRion | (I think that's what they're sort-of used for?) |
| 07: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. |
| 07:46 | justin_smith | 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) |
| 08:10 | clgv | Empperi: yes you can name them like that - Clojure takes care of that |
| 08:10 | irctc_ | Great, thanks for the resources regarding branching and Datomic! |
| 08: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 |
| 08:13 | Empperi | no idea |
| 08:16 | Kah0ona | Quick question; i'm using compojure-api, and for one route I want to stream back a file rather than JSON data. |
| 08:16 | Kah0ona | what is the recommended way for setting up such a route, should it use compojure-api at all? |
| 08:16 | Kah0ona | or should i drop down to native compojure routes? |
| 08:27 | Empperi | well, no point in defining the return type then |
| 08:27 | Empperi | you can use compojure-api |
| 08:27 | Empperi | just don't define return schema |
| 08:27 | Kah0ona | ah so not defining it as s/Any then? :-) |
| 08:27 | Kah0ona | thanks |
| 08:28 | Empperi | we have it like that without :return and works nice |
| 08:28 | Kah0ona | cool will try |
| 08:28 | Empperi | then you have to handle response building yourself but that's what you want in that case |
| 08:28 | Empperi | actually we stream data through our app from another app of ours straight to browser |
| 08:28 | Empperi | it never sits in memory on our servers since we just use InputStreams all the way |
| 08:36 | Kah0ona | yeah i'm planning to do the same, when generating PDFs for instance, don't want them to hit the disk |
| 08:41 | Empperi | yeah, we are actually serving PDFs too |
| 08:41 | Empperi | some of them are HUGE |
| 08:41 | Kah0ona | great this works neat :-) |
| 08:41 | Kah0ona | neatly* |
| 08:42 | Empperi | yeah, it's nice that you can just throw InputStream for ring and it handles it correctly |
| 08:42 | Kah0ona | yeah |
| 08:42 | Kah0ona | I used to have pretty ugly servlets 'back' in the java days :-) |
| 08:42 | Kah0ona | this is really elegant |
| 08:42 | Kah0ona | <3 |
| 08:46 | Empperi | servlets were revolutionary back when they were introduced |
| 08:47 | Empperi | but yeah, that was some time ago now :) |
| 08:47 | Empperi | world has gone forward |
| 08: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? |
| 08:48 | sharms | where :key1, :key2 ... :keyN |
| 08:49 | Empperi | use walk api |
| 08:49 | Empperi | https://clojuredocs.org/clojure.walk |
| 08:50 | sharms | Would you happen to know how I could get the keys required to get to the point I have walked to? |
| 08:50 | sharms | I have tried a few walk functions, tree seq etc but I am a bit hung up |
| 08: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 |
| 08:51 | Empperi | well, your scenario isn't trivial |
| 08:51 | Empperi | would take some time to implement the solution with walk api |
| 08:52 | Empperi | would love to help but I've spent too much time doing all other stuff except the stuff I'm supposed to do :D |
| 08: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 |
| 08:52 | Empperi | don't want to sound like a total prick leaving you in distress but really, I need to do some work :/ |
| 08:52 | Empperi | sorry |
| 08:52 | sharms | thank you for your help |
| 09: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 |
| 09:33 | the-kenny | namespaces, adding :name to gen-class, requiring the namespace of the exception, running compile beforehand, etc. etc. |
| 09:34 | the-kenny | 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 |
| 09:34 | the-kenny | All I get is ClassNotFoundExceptions everywhere. |
| 09:36 | the-kenny | The only "solution" I see right now is removing all usage of ValidationException in our codebase, running `lein compile`, then uncomment all usages. |
| 09:40 | justin_smith | do you require the namespace that defines the exception in the code that wants to throw that exception? |
| 09:40 | the-kenny | Tried that. |
| 09:41 | the-kenny | Same result. |
| 09: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. |
| 09:41 | justin_smith | OK |
| 09:42 | justin_smith | 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? |
| 09:43 | justin_smith | can you make a minimum reproduction of this error (eg. two namespaces, one tries to throw an exception defined in the other)? |
| 09:43 | the-kenny | Yeah, that's likely the next step. |
| 09:43 | the-kenny | Working on it, give me a minute |
| 09:48 | the-kenny | justin_smith: https://github.com/the-kenny/clojure-custom-exception-minimal-case |
| 09:49 | the-kenny | error is different, give me another minute. My brain doesn't really work today |
| 09:49 | the-kenny | okay, it works in that minimal example. I'll be damned |
| 09:50 | the-kenny | Okay, I'm getting some food and throw my day's work away afterwards and starting from scratch. |
| 09: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 |
| 09: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. |
| 09: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 |
| 09: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. |
| 09:55 | Kah0ona | It seems to be reset by compojure-api / compojure / ring? |
| 09:55 | Kah0ona | 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 |
| 09:56 | Kah0ona | how can i figure out which response middle ware (is there even such a thing?) is working in my compojure-api route? |
| 09:56 | justin_smith | Kah0ona: yeah, many middleware will alter the response |
| 09:57 | justin_smith | 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 |
| 09: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 |
| 09:57 | justin_smith | (by returning a new function that wraps a handler and does those things) |
| 09:57 | Empperi | Kah0ona: if you are using cursive then you can just use the debugger |
| 09: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 |
| 09:57 | Kah0ona | yeah i see the point of mw, but since there are some defaults being put in place by compojure-api |
| 09:57 | justin_smith | Empperi: oh, great point |
| 09:58 | justin_smith | Kah0ona: yeah, compojure-api is just a bunch of middlewares iirc |
| 09:58 | Empperi | well, that and some macro magic to build the route mapping :) |
| 09:58 | Kah0ona | yeah with some macro's that does some coercion and checking |
| 09:58 | Kah0ona | yeah |
| 09:58 | Kah0ona | okay so i gotta figure out which mw resets my content-length to 0 |
| 09:59 | Empperi | pretty much |
| 09:59 | Empperi | default compojure-api mws shouldn't do it |
| 09:59 | Empperi | since we have compojure-api in use |
| 09:59 | Empperi | so I'd look at something else at first |
| 09:59 | Kah0ona | hmm don't have much else there actually... |
| 10:00 | Kah0ona | 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 | Empperi | and are you 100% certain of that? |
| 10:06 | Empperi | 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 | Kah0ona | 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 | Kah0ona | 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 | Kah0ona | yeah i have one /files?file_id=1 |
| 10:14 | Kah0ona | 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 | Kah0ona | 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 | Empperi | ikitommi_ that is |
| 10:16 | Kah0ona | yeah i see that :-) |
| 10:17 | Kah0ona | well i dont have any that modify the response |
| 10:17 | Kah0ona | only some that modify the request |
| 10:17 | Kah0ona | 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 | Kah0ona | yeah |
| 10:17 | Kah0ona | 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 | ikitommi_ | 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 | justin_smith | 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 | Kah0ona | so i already got the hint of Empperi to _not_ put a `:return something` key in the options |
| 10:23 | Kah0ona | which got me around the default json encoder that tried to encode my file as json |
| 10:23 | Kah0ona | but now since content-length is always 0 i can't download my file (or it is empty that is) |
| 10:23 | Kah0ona | but it would be nice to also define this route in compojure-api |
| 10:25 | Kah0ona | 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 | Kah0ona | 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 | Kah0ona | 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 | cortexman | (for emacs) |
| 10:35 | prohobo | hey guys, i have a problem |
| 10:35 | prohobo | 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 | Kah0ona | thanks all |
| 10:37 | Kah0ona | 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 | justin_smith | 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 | the-kenny | (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 | justin_smith | 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 | Kah0ona | 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 | Kah0ona | lol Deraen that did it |
| 10:48 | Kah0ona | and it removed like 10 lines of custom header building stuff |
| 10:48 | Kah0ona | just remove a File |
| 10:48 | Kah0ona | return* |
| 10:48 | Kah0ona | 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 | Kah0ona | yeah somehow i sometimes have trouble how thigns work together |
| 10:49 | Kah0ona | 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 | Kah0ona | 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 | Kah0ona | =0 |
| 10:51 | Kah0ona | =) |
| 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 | Deraen | Aleph checks if response already has content-length and only sets it if it is not already set :) |
| 10:59 | sdegutis | Hello. |
| 11:00 | sdegutis | Is there a way to make this template function prettier? http://sdegutis.github.io/2016-03-07/clojure-template-no-deps/ |
| 11:01 | sdegutis | 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 | sdegutis | justin_smith: oh, you mean /instead/ of having a template function? like, each "usage" of (template) would actually be its own function? |
| 11:04 | sdegutis | 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 | sdegutis | oh |
| 11:05 | sdegutis | justin_smith: never mind my last statement to you then |
| 11:05 | sdegutis | justin_smith: I'm always hesitant to make helper functions like that, but.. |
| 11:06 | sdegutis | 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 | justin_smith | or if you want things that call helpers in templates |
| 11:06 | justin_smith | 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 | justin_smith | 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 | sdegutis | 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: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 | sdegutis | 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 | justin_smith | 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 | sdegutis | Oops I meant (comp (partial apply str) flatten) |
| 11:13 | sdegutis | So that you can just return any number of levels of nested strings and then just string-build those suckers together. |
| 11:13 | sdegutis | That works easiest with the sequence-transforming functions in clojure.core, e.g. for, reduce, range, take-while, etc. |
| 11:14 | sdegutis | ~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: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 | sdegutis | Emacs is as simple as it can be for my usage given my needs |
| 11:20 | sdegutis | anything simpler would cripple my productivity |
| 11:20 | sdegutis | also I feel so bad for people who use vim |
| 11:20 | sdegutis | 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 | sdegutis | 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 | sdegutis | 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 | sdegutis | C-r " |
| 11:21 | sdegutis | that's a common one |
| 11:21 | justin_smith | sdegutis: I know otherwise. I never use C-r " |
| 11:22 | justin_smith | I don't even know what that does |
| 11:22 | sdegutis | how do you paste from " then justin_smith? |
| 11:22 | sdegutis | justin_smith: it's a way to paste from " which is like some special thing |
| 11:22 | sdegutis | lemme go look it up |
| 11:22 | justin_smith | "*p pastes from my system clipboard |
| 11:22 | sdegutis | hmm |
| 11:22 | sdegutis | oh wait |
| 11:22 | justin_smith | "<foo>p pastes from foo |
| 11:22 | sdegutis | i remember now i think |
| 11:22 | sdegutis | C-r " is like when you need to paste while you're in the fake-minibuffer-thing |
| 11:23 | sdegutis | 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 | sdegutis | 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 | sdegutis | btw, ive given my kids piano sheet music for FFVII songs, and they're killin it |
| 11:30 | sdegutis | i love hearin that while i work, its amazing |
| 11:31 | sdegutis | 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 | sdegutis | which btw is a song off the Super Metroid soundtrack :D |
| 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 | sdegutis | 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 | sdegutis | 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 | justin_smith | 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 | sdegutis | 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 | sdegutis | justin_smith: that's just an implementation technique of how to include all the system components in the router |
| 11:47 | sdegutis | 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 | justin_smith | 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 | justin_smith | via its definition of the middleware |
| 11:51 | justin_smith | I think that's going to allow clean isolation |
| 11:53 | justin_smith | 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 | sdegutis | 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 | justin_smith | that's my theory at least. |
| 12:07 | sdegutis | hmm |
| 12:08 | RedNifre | Hey there clojuristas. |
| 12:09 | RedNifre | ,(+ 1 2) |
| 12:09 | clojurebot | 3 |
| 12:09 | RedNifre | clojurebot step up your game, you're getting slow! |
| 12:09 | RedNifre | ,(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 | RedNifre | 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 | mokuso | ,'(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 | justin_smith | ,(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 | justin_smith | ,(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 | clojurebot | #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 | justin_smith | RedNifre: $ is jvm syntax for an inner class |
| 12:13 | justin_smith | 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 | justin_smith | there is no distinction |
| 12:15 | justin_smith | same thing, two names |
| 12:16 | RedNifre | okay, so only one nil and it's equal to itself. got it. |
| 12:17 | RedNifre | 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 | justin_smith | 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 | justin_smith | which is also different but kind of "nothing yet" |
| 12:19 | sdegutis | NaN is just weird, never use NaN |
| 12:19 | sdegutis | and never use Doubles or Floats. |
| 12:19 | sdegutis | 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 | justin_smith | (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 | justin_smith | ns-unmap |
| 12:23 | justin_smith | 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 | justin_smith | (ns-unmap 'user 'y) |
| 12:26 | justin_smith | that's why I expect it to be called unintern, intern also uses symbols |
| 12:26 | RedNifre | ah. |
| 12:27 | RedNifre | 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 | sdegutis | ,*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 | sdegutis | 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 | justin_smith | OK |
| 12:28 | justin_smith | 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 | clojurebot | #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 | RedNifre | ,(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 | sdegutis | ,(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 | sdegutis | oh wait |
| 12:30 | sdegutis | 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 | sdegutis | } ([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 | sdegutis | )))))) ([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 | sdegutis | hmm |
| 12:31 | sdegutis | yeah we'll just have to wait til clojurebot resets its jvm which afaik happens every few minutes |
| 12:31 | sdegutis | my bad. |
| 12:31 | RedNifre | Or you just write a new map, using for or something :) |
| 12:32 | sdegutis | Smart RedNifre. |
| 12:32 | sdegutis | ,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 | sdegutis | 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 | sdegutis | 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 | sdegutis | 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 | 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 | :/ |
| 12:42 | amalloy | RedNifre: there's no pattern matching |
| 12:43 | amalloy | but also (- n 2) (- n 1) doesn't make sense even if there were |
| 12:43 | RedNifre | why not? |
| 12:43 | RedNifre | Yeah, I meant ([n] (+ (fib (- n 2)) (fib (- n 1)))) |
| 12:44 | RedNifre | 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 | sdegutis | amalloy: hmm, his pattern matching idea would be really cool though |
| 12:50 | sdegutis | It'd be like a version of defn that has core.match built in. |
| 12:50 | sdegutis | That said, I would have basically no need for it ever. |
| 12:50 | sdegutis | The only time I /might/ use it is to replace uses of defmulti/defmethod. |
| 12:50 | sdegutis | 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 | RedNifre | 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 | amalloy | i actually saw a co-worker go over the 64KB limit in java |
| 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 | amalloy | ,(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 | sdegutis | ,(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 | sdegutis | ,(correct-answer-for "Who's better at Clojure than rhickey?") |
| 13:02 | clojurebot | rhickey |
| 13:02 | sdegutis | touché clojurebot. |
| 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 | RedNifre | ,(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 | justin_smith | 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 | justin_smith | and you can avoid aot too pretty easily |
| 13:06 | RedNifre | huh? |
| 13:07 | RedNifre | 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 | RedNifre | 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 | justin_smith | wacky scenarios like two classes with the same exact name that are not identical |
| 13:10 | justin_smith | and one extends the protocol you are using and the other does not |
| 13:10 | justin_smith | 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 | justin_smith | 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 | justin_smith | 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 | sdegutis | ,(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 | sdegutis | ,(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 | clojurebot | "<h1>" |
| 16:09 | justin_smith | you don't need to escape anything in that re |
| 16:09 | justin_smith | 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 | justin_smith | ,(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 | justin_smith | ,(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 | sdegutis | 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 | sdegutis | 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 | sdegutis | justin_smith: how do you specify that flag in a regex Clojure literal? |
| 16:13 | sdegutis | ,#"foo"g |
| 16:13 | clojurebot | #"foo" |
| 16:13 | sdegutis | Hmm. |
| 16:13 | sdegutis | ,#"foo" you suck |
| 16:13 | clojurebot | #"foo" |
| 16:13 | sdegutis | hahah clojurebot sucks |
| 16:14 | sdegutis | Oh! |
| 16:14 | sdegutis | (?m) at the beginning? |
| 16:14 | sdegutis | 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 | sdegutis | ,(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 | sdegutis | "occurrence" |
| 16:16 | sdegutis | huh, yeah |
| 16:16 | sdegutis | weird. |
| 16:17 | sdegutis | Woo! |
| 16:17 | sdegutis | ,(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 | backnforth | Hey |
| 16:20 | backnforth | Should I use sequences or lists? |
| 16:23 | backnforth | 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 | TMA | backnforth: lists are a specific kind of sequences |
| 16:24 | sdegutis | backnforth: lists, always lists |
| 16:24 | sdegutis | 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 | sdegutis | 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 | backnforth | 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 | TMA | backnforth: if the data might be infinite (like sequence of all primes) use lazy-seq |
| 16:30 | TMA | 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 | TMA | 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 | backnforth | 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 | TMA | oh |
| 16:43 | TMA | conj prepends an element to a list |
| 16:43 | TMA | ,(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 | TMA | ,(conj '(a b c) 'd) |
| 16:44 | clojurebot | (d a b c) |
| 16:45 | TMA | to get to the b you can: |
| 16:45 | TMA | ,(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 | TMA | 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 | sdegutis | 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 | backnforth | ,(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 | backnforth | ,(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 | ddellacosta | 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 | justin_smith | 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 | GroundhogTest | Removed that, added a throw to my first test, and finally got a failure |
| 17:38 | justin_smith | interesting |
| 17:38 | justin_smith | 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 | backnforth | using some constant as a range |
| 19:00 | backnforth | ... 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 | rhg135 | 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 | backnforth | 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 | backnforth | 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 | Malnormalulo | ,'\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 | amalloy | 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 | troydm | also is there a way to attach comment to variable definition |
| 21:02 | troydm | when u defn function you can add description to it |
| 21:03 | troydm | but I was wondering if it's possible to add description to arbitary variable too |
| 21:03 | troydm | 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 | Malnormalulo | *if you've got a function |
| 21:25 | Malnormalulo | (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 | TimMc | 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 | amalloy | so a lot of things are wacky |
| 22:55 | TimMc | 1 << 32 // 1 |
| 22:56 | TimMc | ,(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 | ajb | 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 | TEttinger | there may be someone who did this already |
| 23:03 | TEttinger | 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 | TEttinger | 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 | TEttinger | ,(Long/toHexString -805452285) |
| 23:09 | clojurebot | "ffffffffcffdc603" |
| 23:10 | TEttinger | that is not shifted over by 16... |
| 23:10 | TEttinger | ,(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 | TEttinger | in the JS one |
| 23:11 | TEttinger | thanks kvey for the 32-bit tip |
| 23:12 | TEttinger | 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 | TEttinger | bit-or? |
| 23:14 | TEttinger | 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 | TEttinger | unchecked-XXX stuff is also pretty fast |
| 23:15 | TEttinger | 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 | kvey | whereas int throws an exception |
| 23:18 | TEttinger | no, I don't think so |
| 23:18 | TEttinger | hm |
| 23:19 | TEttinger | ,(unchecked-int 0xffff0001) |
| 23:19 | clojurebot | -65535 |
| 23:19 | TEttinger | correct |
| 23:19 | TEttinger | ,(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 | TEttinger | unchecked casts are useful for when you want something to replicate java or possibly other languages' behavior |
| 23:23 | TEttinger | 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 | TEttinger | so not actually garbage data, intentional just from a source I can't see |
| 23:25 | kvey | ah I see |
| 23:25 | kvey | makes sense |
| 23:59 | TimMc | ,(Long/toBinaryString -805502976) |
| 23:59 | clojurebot | "1111111111111111111111111111111111001111111111010000000000000000" |