#clojure logs

2016-05-20

01:04tolstoyHm. UUIDs for web-app routing: maybe a bit much.
02:15ben_vulpestolstoy: i use 'em everywhere!
02:16tolstoy#/thing/<giant-uuid>/sub/<giant-uuid>/thing
02:16tolstoyOf course, giving up on REST purity helps: just need enough to recover state from a bookmark.
02:16dysfunno, just don't do that
02:17tolstoydo what?
02:17dysfunurls are for humans, not machines
02:17dysfunat least urls for html documents
02:17tolstoyThis is just hash stuff, after the #.
02:18dysfunoh i remember when that was the fashion before we all learned better
02:19tolstoyHeh. Well, soon as I figure out how to make it work in this SPA, I'll ditch it.
02:26tolstoyThose wankers over at gmail still use # routes. Twiiter, however, has seen the light.
02:27dysfungmail still uses GWT, so, y'know... ;)
02:28tolstoyI log in to it one a quarter or so and delete all the spam from the spam folder.
03:58Keksikewhats a function I can use instead of some, which iterates in the same way but doesnt brake at any point
03:59Keksikeso for example I have data {1 foo, 2 bar, 3 baz} and I wanna iterate through all of em and use the key-value pairs
03:59lumawhat do you want to do with the key-value pairs?
04:00lumajust get a sequence of them?
04:00Keksikesend them to functions as parameters
04:00lumaany example?
04:01Keksikeso what I tried to do was like (some (fn [id value] (my-function id value)) myData)
04:01Keksikewhere id would be for example 2 and value would be bar
04:01lumaand you want to call that function for each pair and get out a sequence of the results?
04:02ridcullymap?
04:02clojurebotmap is *LAZY*
04:02opqdonutKeksike: map, or perhaps doseq
04:02KeksikeI dont need to get any results, the my-function just saves stuff to db
04:02opqdonutthen doseq
04:02opqdonutsince map is lazy
04:02opqdonut(or can of course use (doall (map f xs)))
04:02Keksikehmm ok thanks
04:03Keksikehow would the syntax go in doseq
04:03luma(doseq [[id value] my-data] (my-function id value))
04:03Keksikeright, thanks :)
06:43jonathanj,(clojure.string/join "" ["one" "two" "three"])
06:43clojurebot"onetwothree"
06:43jonathanjis there a more concise way of joining a bunch of strings with no separator?
06:44dysfun(str "one" "two" "three")
06:46MJB47,(apply str ["one" "two" "three"])
06:46clojurebot"onetwothree"
06:47jonathanjhrm, the order of the arguments to `clojure.string/replace` is kind of annoying.
06:47dysfunwhy?
06:47clojurebothttp://clojure.org/rationale
06:47dysfun:)
06:48jonathanjat the moment i have some code that's of the order (s/replace (->> xs (map foo) (apply str)) #"..." ",,,")
06:48jonathanjit's annoying that replace can't be part of the threading
06:49dysfunnot everything has to run through a single thread you know
06:49jonathanjthe problem is you can't thread -> inside ->>
06:50dysfunoh that's a problem is it?
06:50jonathanjso as-> might be the only possibility, other than the original
06:50dysfunor there's -<> from swiss-arrows
06:51jonathanjanyway, it's annoying because if you think about partial application of something like `replace`, isn't the 99% case where you partially apply the replace/substitution stuff and have the string to apply those to be the param?
06:51jonathanjcertainly that's my experience with string replacing
06:51dysfunon this, i'm inclined to agree
06:52dysfunif i'm going to use partial, i'm going to want to change the string more often than the match
06:52jonathanji guess i could write (->> xs a b c #(s/replace % #"..." ",,,")) and that would probably work because the #() only takes one param?
06:53ridcullythat must be (->> ... (#(...))) right?
06:53dysfunactually you'll probably want to put that inside extra parens
06:53dysfunwhat ridcully said :)
06:54jonathanjridcully: oh right, yeah, that would definitely explain my unexpected result
06:58ridcullyif your replace #"..." "..." is "fixed", i'd just turn that into it's own defn with a proper name and then you can thread along as you like
06:59jonathanjyeah, that was what i was thinking too
06:59jonathanjthat's probably the choice with the best result
07:04RovanionHi all! I've got a bunch of database functions which I want to wrap in a try-clause. What would be the equivelent of a decorator in clojure?
07:04dysfunthere are no decorators in clojure
07:05dysfunwhat do you mean wrap them in a try clause? are they written in java or clojure?
07:05RovanionSo what would be the equivalent of a decorator in clojure?
07:05Rovaniondysfun: They end up in the java psql driver so they throw a ConnectionError if no db connection could be established.
07:06dysfunokay, so for each function, you want to wrap them in a new function that executes in a try?
07:07RovanionI want to (try (function-i-want-to-wrap) (print "print some error message")) around a whole bunch of db-access functions.
07:07RovanionIf that makes it clear.
07:08dysfunrealistically you're going to factor that behaviour out into a higher order function like this
07:08dysfun(defn safely [f] (try (f) (catch Exception e nil)))
07:08dysfunthen dedicate a new namespace to these wrapper functions
07:09dysfunand for each one define it like (defn my-fn [&args] (safely #(.method %)))
07:10dysfunif you want to reduce it further, you will have to use macros
07:14Bronsajonathan youn can always (-> xs (->> (map foo) (apply str)) (s/replace ..))
07:25Rovaniondysfun: Thank you, think I got the hang of it now!
07:30jonathanjBronsa: yeah you can but i don't think that adds much value over (replace (->> ...)) personally
07:30jonathanjcertainly not when you're threading a value through a single function
07:41tikotusI would like an indexed sorted data structure. I could use vec and sort it after insert, but only inserting the value at correct location would be more optimal. Any thoughts?
07:45MJB47you could use sorted map, but performance wise, is inserting it into the correct position actually faster than just sorting it after the fact?
07:45tikotusInserting in sorted vec is O(n), sorting it is O(nlogn)
07:46tikotusNaturally I could implement an insert function that keeps the vec sorted, but I'm slightly annoyed a ready solution for this doesn't seem to exist :(
07:46opqdonutwhy do you need sorting & indexing btw?
07:47tikotusI need a quick way to find element n and then I need it's neighbors
07:47opqdonutright
07:47opqdonuta sorted-set would work but you can't really get an "iterator" into there
07:47tikotusyeah :/
07:47opqdonutbut yeah, there really aren't any data structure libraries for clojure
07:48opqdonutcould you use the java SortedSet?
07:49MJB47correct me if im wrong, but i think inserting into a sorted array in O(n^2) ?
07:49opqdonutsorry I mean NavigableSet
07:49MJB47worst case anyway
07:49opqdonutsee https://docs.oracle.com/javase/7/docs/api/java/util/NavigableSet.html
07:50tikotusWorst case would just be iterating through the whole array. I guess it could even be O(logn) with binary search
07:50tikotusThanks, I'll see what Java has to offer me
07:50MJB47interating through the whole array for each element to insert (so * n elements)
07:51lumaworst case is O(n) because if you need to insert the item in the first place you need to move all items +1 place
07:51MJB47so to insert 1 element i guess its n (or logn)
07:51tikotusOh yeah, I'm looking at the case of one element... maybe I should take the whole set into consideration
10:22JireHey guys, REALLY new to Clojure. I'm using IDEA with Cursive. Creating a project with the Leiningren creator, I can't seem to figure out how to add dependencies. I'm assuming to add for example Netty, I should just define it after the Clojure 1.8.0 like [io.netty/netty-all "4.1.0.CR7"]. Unfortunately it doesn't seem like Netty is in my classpath.
10:23justin_smithJire: if you restart leiningen after adding that, it should see that dependency. Did you try running 'lein cp' from inside the project in the console?
10:24justin_smithalso I assume your irc client added those smart quotes and you are using real "" in the file
10:24justin_smithwait those aren't smart quotes, just me using an unfamiliar font, sorry
10:25ridcullyalso hit the "reload" button in the lein tab in cursive
10:25Jire@justin_smith: I don't understand what you mean by "restart" leiningen. Should I restart IDEA?
10:26justin_smithJire: I mean if a repl is running, restart that repl (lein starts the repl)
10:26justin_smithJire: but as ridcully said, reload button
10:27JireNot sure what you're referring to. This is my screen: http://i.imgur.com/VEyxfM3.png
10:28justin_smithJire: I meant a command line
10:28justin_smithlein cp, not lein comp
10:28justin_smithas in a shell, not the repl
10:28JireI'll install lein and add it to my cp on windows.
10:29justin_smithif you have a repl you have lein...
10:29justin_smithand that's still not what I meant!
10:29justin_smithI mean cp is an argument to lein
10:29justin_smithnever mind, I guess cursive does things weird, and another cursive user would probably be more helpful
10:30ridcullyJire: click that open square in the lower left corner. there is something like leiningen in the list
10:30ridcullyJire: this shows, what i meant with "lein tab". there is a reload button
10:31JireCool, lein cp did fix it when ran within the project directory. :)
10:32Jire@ridcully: This seems to be the way to do it without opening up a shell, thanks!
10:33ridcullyin the past you always had to do it in IDEA, since Cursive would not reload changes to project.clj automatically. don't know, if this changed
10:34justin_smithI meant 'lein cp' as a diagnostic, not a fix - just to check if the classpath it shows includes the jars desired (and maybe you'd see some downloads too) - but regardless, sounds like it's sorted out
10:35ridcullyyet the cp would load any missing deps, right? so restarting the repl would most likely pick up the change too. but autocomplete etc in idea/cursive would still fail
10:36justin_smithridcully: right - I was trying to help as much as I could without knowing the cursive specific stuff
10:36ridcullyi don't know them either ;)
10:41JireHmm, seems like all of a sudden the classpath got messed up. http://i.imgur.com/85tyWM3.png
10:41justin_smithJire: that's not the right syntax
10:41justin_smithServerBootstrap is the class, (ServerBootstrap.) creates one, but ServerBootstrap. without parens is invalid
10:42justin_smithalso, def inside defn is always a bad idea - it doesn't work like def in scheme, it only creates top level bindings
10:43JireSo you recommend var defs to reside outside of functions?
10:43dysfunyes
10:43justin_smithJire: defs always exist outside the function, regardless of where you create them
10:43justin_smithand yes, running def inside the function is a bad idea
10:44Bronsaespecially since def will intern the Var at compile time, so it will exist even if you never run the function
10:47JireOK, well I'll keep working on this server and leave a Gist if you're interested in reviewing my colossal failure of a first Lisp project. :P
10:47justin_smithhah, just trying to be helpful - theres some good docs out there and you might want to start by following a book or tutorial
10:48justin_smithbest of luck
10:48justin_smithJire: for the stuff you are doing now, I think this might be helpful http://clojure.org/reference/java_interop
10:49JireJust referencing clojure in Y minutes and the clojure site ref. Thanks for the link
12:06sdegutisThis is neat:
12:06sdegutis,(-> :a #{:a :b})
12:06sdegutisAlso:
12:06sdegutis,(-> :a {:a :b})
12:06clojurebot:b
12:06clojurebot:a
12:06sdegutisUseful for checking whether a thing is in a thing without some or contains.
12:07justin_smiththere is also find
12:07justin_smith,(find {:a nil} :a)
12:07clojurebot[:a nil]
12:14dimon_does Luminus allow creating helper methods which I can use in html templates?
12:16fijwg/j emacs
12:16fijwg
12:16dysfunyes
12:16dysfunit uses selmer
12:16dysfunhttp://www.luminusweb.net/docs/html_templating.md
12:17dimon_dysfun: where?
12:17dysfunactually looks like it has options for selmer and hiccup
12:17dysfunwhich one are you using?
12:18dimon_selmer
12:18dimon_is it add-tag! ?
12:18dysfunwell on that page at the top you will find a table of contents
12:18dysfundo you want a custom filter or a custom tag?
12:19dysfun(links 5 and 7)
12:19dimon_now I see, thx
12:20dysfunyw :)
12:33dimon_I need to "take while" a substring from a string. So that "aaa bbb ccc 999 eee ddd" => take while 999 => aaa bbb ccc
12:33dimon_it's like indexof, then find a substring
12:34dimon_but maybe clojure has a special function for this?
12:37dysfunif it has to be efficient, do it with the java string functions
12:38dimon_ok
13:16justin_smithdimon_: dimon_: that's just (subs s 0 (min 999 (count s))) (which uses the most efficient native method)
13:17justin_smithdefinitely not a take-while of any sort
13:17justin_smithoh, wait, you mean take until the first index of 999?
13:21justin_smith,(defn cut-at [a b] (apply subs a 0 (replace {-1 (count a)} [(.indexOf a b)])))
13:21tolstoystring/split then take-while normally?
13:21clojurebot#'sandbox/cut-at
13:21justin_smith,(cut-at "aaa bbb ccc 999 eee ddd" "999")
13:21clojurebot"aaa bbb ccc "
13:21justin_smith,(cut-at "aaa bbb ccc 999 eee ddd" "hhh")
13:21clojurebot"aaa bbb ccc 999 eee ddd"
13:22justin_smithmaybe that implementation is too clever though
13:26sdegutisjustin_smith: find!?
13:26sdegutisI never knew find existed.
13:26sdegutisWow. That's the most useless function ever.
13:26sdegutis(doc find)
13:26clojurebot"([map key]); Returns the map entry for key, or nil if key not present."
13:27sdegutisfind should actually be filter + first
13:27justin_smithsdegutis: there are often situations where you need to know whether the key is really there, and also what the value is. find does this in a single call.
13:27sdegutisjustin_smith: what's a good example situation?
13:28justin_smithsdegutis: any sitution where nil is a valid entry that doesn't mean the same thing as the absence of the key in the collection
13:29sdegutisjustin_smith: why wouldn't (get get get get) work there?
13:29justin_smithbecause the nil from get is ambiguous
13:29sdegutis,(get {} :a :404)
13:29clojurebot:404
13:29justin_smithsdegutis: but it could have :404 in there in the first place, why not just get the actual key/val pair?
13:29justin_smith,(find {} :a)
13:29clojurebotnil
13:30justin_smith,(find {:a 0} :a)
13:30clojurebot[:a 0]
13:30justin_smith,(find {:a nil} :a)
13:30clojurebot[:a nil]
13:30sdegutisjustin_smith: then why not contains? & get
13:31sdegutis(if (contains? m k) (get m k) :404)
13:31justin_smithsdegutis: like I said, one call instead of two
13:31sdegutisAn because of that we now have to settle for two calls instead of one: (->> coll (filter f) (first))
13:32sdegutisrather than (find f coll)
13:32justin_smithsdegutis: so your complaint is that you think something else should have had dibs on the name?
13:32sdegutisYep.
13:32sdegutisI think this is a much more common case.
13:32sdegutisTo the point where it deserves a core fn more than the other case.
13:33justin_smithsdegutis: I assure you that nobody at cognitect said "we would make (comp first filter) a function in clojure.core, but the name we wanted was already taken so fuck it"
13:33sdegutisit's not as simple as (comp first filter) btw
13:34justin_smithhow so?
13:34sdegutis,((comp first filter) pos? [0 1 2])
13:34clojurebot1
13:34sdegutisoh
13:35sdegutisSure, they may not have said that. But Clojure's been getting /weird/ ever since 1.5-ish
13:35dysfunweird like adding cljc files and unrolled collections to improve performance?
13:35justin_smith,(:added (meta #'find))
13:35clojurebot"1.0"
13:35dysfunthose crazy kids!
13:35sdegutishaha
13:35sdegutisyou guys, actin like i know what im talkin bout
13:36dysfuni can assure you we don't
13:36dysfunit's just you show up in obvious need of being corrected ;)
13:36lumaaww, he mad
13:36justin_smithsdegutis: well you sure punked me good, that will show me to go around acting like people have earnest opinions that deserve consideration!
13:37justin_smithwhat a jackass, huh
13:37dysfunjustin_smith: yeah, he's clearly shown you to be an awful person
13:38lumawell, now that we're on this topic, here's a similar function that always finds its way into util.cljc: (defn find-where [f v coll] (first (filter #(= v (f %)) coll)))
13:38dysfuncan you give an example use of it?
13:39luma(find-where :nick "dysfun" people)
13:39dysfunah
13:41dysfunmap-keys and map-vals are common ones
13:42hiredmanI hate that, like, are you really searching for the first hit so often that you write a function for it, but don't change your data representation so it is a faster operation?
13:42dysfunhiredman: that was my first thought too, however i can see it useful for taking apart whatever shitty data you've been given
13:43hiredmanlike, just sort the damn list and use a binary search
13:43hiredman(or actually make it something like a map, or ...)
13:44tolstoyIt's a process. Sometimes you struggle and come to realize there's just "too much code" or "this should be easier" and then you have a moment of clarity.
13:45dysfunsometimes you really don't care about maintaining it for faster future access because that will never come
13:46tolstoy'It'll take me a day to refactor this whole thing and remove 1/2 the code." "No."
14:20TimMcWelp, I found out why our server was getting weird hangs periodically with tons of blocked threads implicating taoensso.tower: tower has `dev-mode?` on by default, which reloads the dictionary each time a translation is needed.
14:20TimMcMuch sad, wow.
14:21justin_smithouch
14:22TimMcand I guess newer versions of tower don't have this problem because of some other caching, but ugh.
14:28ystaelTimMc: :( :( :( sorry
14:52sdegutisHave more people moved to Boot from Lein? Is Boot becoming the new de facto build tool?
14:53dysfunno
14:53dysfunpeople are using boot when they have more complicated things to do than lein caters for
14:53jballancsdegutis: I use both. Lein is a better tool for "libraries", boot is better for "projects"
14:53dysfuni'm not convinced about that
14:54dysfuni find boot useful for libraries that do clj+cljs
14:54jballancah yeah, the clj+cljs story for Lein is still not anywhere near boot
14:54jballancbut how many libraries mix the two?
14:54dysfunseveral of mine...
14:54sdegutisjballanc: like, apps?
14:54sdegutishow so?
14:55jballancso, complicated deployments, maintenance tasks, etc. are all easier to do with boot since tasks are just clojure code
14:55sdegutisAh.
14:55dysfunit is people like me upgrading their libraries to support clojurescript that keeps you in libraries when you're using clojurescript
14:55sdegutisThe only thing making me consider Boot is that I then get to use AWS Java SDK libraries directly in order to manage deployments from within Cider/Clojure.
14:56jballancdysfun: yeah but are you using clj+cljs *simultaneously*? I might still use Lein for a cljc library
14:56jonathanjthat seems like a good reason?
14:56jballancsdegutis: that's exactly what we use it for
14:56ben_vulpes> deployments
14:56ben_vulpes> from emacs
14:56ben_vulpesyou people are on crack
14:56dysfunjballanc: my most common workflow is (watch) (speak) (test) (test-cljs)
14:56jballancI have boot tasks that update CloudFormation stacks, managed CodeDeploy deployments, build jars and copy to S3, etc.
14:56sdegutisThat said, shutting down the app locally and running a small shell script isn't that bad.
14:57ben_vulpesdo all of your devs use emacs?
14:57sdegutisben_vulpes: mayhaps
14:57sdegutisben_vulpes: who are you asking?
14:57ben_vulpeseveryone deploying from Cider
14:57sdegutis(mayhaps was re: crack)
14:57sdegutisben_vulpes: we only have one dev
14:57jonathanjwhy do you all think that boot hasn't totally replaced lein?
14:57sdegutis(me)
14:57sdegutisjonathanj: i use lein happily
14:57ben_vulpesoh well
14:57dysfunbecause it's got a confusing and horrible api
14:57dysfunand because lein is really quite nice for the 90% case
14:58tolstoylein + actual shell scripts = not too bad
14:58sdegutisdysfun: boot does?
14:58sdegutisyeah we're easily in the 90% case
14:58tolstoyNot cross platform, I guess.
14:58dysfunyes, boot's api is terrible and confusing
14:58jonathanjwhy do you say boot's api is horrible?
14:59sdegutisjonathanj: are you involved in boot?
14:59dysfunbecause i've used it?
14:59jonathanj*in*?
14:59jonathanjdysfun: well, what API are you talking about?
14:59sdegutisjonathanj: involved in the boot project
14:59jonathanjsdegutis: no
14:59sdegutisjonathanj: then im really confused why you're getting so defensive about boot criticism
14:59jonathanjdefensive?
14:59jonathanji'm just asking questions
14:59dysfunjonathanj: boot isn't configured with an edn file like clojure, you write clojure to do the build
14:59sdegutiswell not very defensive
14:59sdegutisdysfun: thats the point of it tho
15:00jonathanji have zero investment in lein or boot, so there's really nothing for me to be defensive about, i think you're misinterpreting me
15:00dysfunand the way it forces you to work leads to a lot of confusion even once you've gotten the basic principles
15:00jballancboot isn't so bad once you realize it's just ring for filesets ;-)
15:00dysfunit's very powerful and shiny and everything, but it fails the "can i come back to it after not doing clojure for a few months?" test
15:02jballanclein is definitely better at the "set-it-and-forget-it" approach
15:02dysfunboot is fine *once it is working*
15:03dysfungetting to that point can be an exercise in frustration
15:04dysfunall sorts of oddness too like the 'speak' task causes bizarre sound related errors on my release manager's machine
15:04tolstoyDoes boot still have that thing where the files it generates are hidden away in a temp directory?
15:04dysfunno
15:04ben_vulpes> why do you all think that boot hasn't totally replaced lein << because toolchain migrations are expensive, people don't like using new software in production, because the clojure world does not jump willy nilly to the latest and greatest, a million billion reasons
15:05dysfuntolstoy: it does have a new and annoying feature, however
15:05dysfunyou have to use the (target) task at some point or nothing gets added to your build
15:06dysfunexcept only once you've put something in boot.properties. when you start up in a new project, it will pester you on every run to tell you to set this property at which point your build will fail!
15:07dysfunwell i say fail, it will pass, it's just when you try and build a jar from it, you'll find it's mysteriously empty
15:07sdegutiswelp
15:07dysfunthe tl;dr is "use leiningen unless you have a good reason to use boot, then use boot"
15:07sdegutisdysfun, jballanc: also boot has a steep-ish learning curve
15:07jonathanjben_vulpes: do you really have to use lein or boot in production?
15:07sdegutisi can get a lein project working in 2 minutes flat, but with boot itll be an hour or two
15:08ben_vulpesi consider the dev toolchain production jonathanj .
15:08jonathanji mean all my clojure deployments consist of running something to build an uberjar which both boot and lein do equally as well
15:08dysfunsdegutis: yes, but once you're up and running, you just copy and paste old files and hope for the best
15:08jonathanji also wasn't talking about jumping willy nilly
15:09jonathanjhaving used boot for dev, i think it's better than lein because you can compose tasks together instead of having every plugin reimplement stuff like file watchin
15:09dysfunnot that lein couldn't do that itself, of course
15:09hiredmanwhen I look at boot, what I see is not the latest and greatest, I see another tire on the fire. which is not to say that lein is great
15:09jonathanjcouldn't do what?
15:09ben_vulpesi personally prefer toolchain stability over more or less anything.
15:10ben_vulpesthe last thing i need is to waste a day fucking with the dev or build toolchain.
15:10ben_vulpeswell
15:10ben_vulpesabove a new hole in my head possibly
15:10dysfuni'm inclined to think something inspired by both boot and lein will take us by surprise in the next couple of years
15:10sdegutisdysfun: haha so grue
15:10dysfunbut i think it will mostly cut into boot's market share, not lein's
15:10sdegutis/treu/
15:10hiredmanpeople create terrible build processes, and instead of fixing the people creating terrible builds, the quick technical fix is to create a new build tool and use that, but eventually people are going to make terrible builds with that new tool
15:10tolstoyben_vulpes Which is why I think "build" should just build, not deploy, create docker images, manage AWS deployments ....
15:10sdegutishiredman: life is complicated
15:11ben_vulpestolstoy: yeah, i lein uberjar and then my custom deployment stack handles it from there.
15:11tolstoyhiredman Amen.
15:11tolstoyben_vulpes That means if I had to come in to maintain your stuff, I might actually be able to do it. ;)
15:11ben_vulpestolstoy: that is the goal
15:11dysfunhiredman: i think the flexibility boot gives me serves an actual need
15:12ben_vulpestolstoy: it's ALL BASH even.
15:12dysfuneven if it's just having something workable in the meantime til we fix it in leiningen
15:12tolstoyben_vulpes It's not even the implementation, it's the separation. ;)
15:13ben_vulpesright
15:13hiredmanthe js world is particular bad and requiring these heinous build processes
15:14hiredmanand somehow convicing people to do that
15:14hiredmanand because there is a js component to so many projects now, you see these terrible things getting introduced everywhere
15:14dysfunand the rise of ruby projects that require grunt to build...
15:14ben_vulpesi excised ruby from a django project recently
15:14ben_vulpesit shelled out
15:15ben_vulpesto compile scss
15:15tolstoyThe ghost of Make.
15:15ben_vulpesso i walked the django compressor version back to be compatible with the fork of django that was in production
15:15ben_vulpesso that i could call python libsass
15:16ben_vulpesaaaaa
15:21jballancboot does benefit from one very distinct advantage: code is more composable than config is
15:21dysfunlein benefits from one very distinct benefit: config is much more trustworthy than code
15:22jballancvery true
15:22tolstoyI think of them as enablers: what's the worst thing lein enables? or boot?
15:23dysfunor the best thing they enable
15:23dysfunboot gives me something lein never did: even if my tests don't compile, it'll still watch and reload them until they do
15:23jballancbut with boot I've made projects where the developer types "boot dev" and it: downloads and installs datomic, starts a datomic transactor, starts middleman building, starts cljs building, builds and serves a clj server, and restarts the whole thing whenever files change
15:24jballancwith lein you'd need at least 4 terminal windows open to do the same
15:24tolstoyI mean that boot allows you to write programs, so you can have an arbitrarily complex build. Lein doesn't encourage that.
15:24jballanc...but then another developer on our team pointed out: that means I have 4 terminals worth of log in one terminal
15:25tolstoyjballanc That's what I'm scared of. If I have to maintain your project, and one of those things goes wrong....
15:25hiredmanlein also limits what people learn about clojure and the jvm, so when things break, they cannot fix them
15:26hiredmanhttps://www.youtube.com/watch?v=ShEez0JkOFw
15:26jballanctolstoy: we try to keep it well factored, so that the definition of the "dev" task is literally "(deftask dev (comp install-datomic run-transactor middleman..." etc.
15:27jballancso if some part breaks, you can literally just remove it from the task def
15:27jballancthat's part of what I meant about code being more composable than config
15:27dysfunyes, but if the install-datomic step breaks, how will you run-transactor ?
15:27jballancmanually install datomic
15:27tolstoyjballanc You may have written a super clean, wonderful thing: but that has nothing to do with boot. So, my fear is other developers. ;)
15:28jballanctolstoy: other developers are always the problem ;-)
15:28dysfunthe truth is as a user the build tool is supposed to get out of your way. so your README should contain the commands people need to use to do things like generate docs or run tests
15:28tolstoyIndeed. ;) In both directions.
15:28dysfunand if you get a lot of reports of your build failing then stop being an idiot and sort your build out
15:34hiredmanI've worked on large clojure projects, and we used lein, and had, if I say so my self, a very nice build, and we used lein
15:35hiredmanso, while boot may be great, the rhetoric about it being better in some way, and some how enabling you to generate value faster, or easier, or whatever, just doesn't scan for me
15:36hiredmanso in some ways, my response is reflexive, I seeboot being talked up, based on an stance that is, in my experience, incorrect
15:37dysfunand how much effort did you put into getting your nice build?
15:38hiredmansome of that is also just different ways of doing things, booting a datomic transactor in a boot task, I've done stuff similar, but typically as a clojure.test fixture, not a task in a build system
15:39hiredmanthere are basically a million ways to skin that cat, and to point at boot and say it is good because you can do one of them, is just laziness
15:41hiredmanwhich is not to say boot is not great, this is not a rant against boot
15:41ridcullyisn't lazyness the trait of the developer?
15:42hiredmannot laziness in thought at least, and maybe not other kinds of laziness
15:42ridcullyas in shortest route
15:44hiredmanwhen you work with tools, a tool can have two (hopefully) complementary kinds of beauty that attract you to it, and make you want to use it
15:44hiredman\
15:45ben_vulpesREADME++
15:45hiredmantype 1 is the beauty of the tool, the tool itself is well made, feels good in the hand, has good vibes
15:46hiredmantype 2 is the beauty of the results, the tool produces good results
15:47hiredmantype 1 is subjective, type 2 tends to be more objective (but really it depends on the subjectivity or objectivity of the judgement of the results)
15:51hiredmanlost my train of thought, but if discussions about tools center on type 1, then that is mostly noise
15:51ridcullyin the end only type2 counts - unless it's from bizarro-type-1 world (incredible ugly and hard to use)
15:53dysfuntype 1 does matter. tools that make you feel good make you want to use them more
15:53dysfunand that can be the difference between getting a thing done and not when you're having a bad day
15:56jballancanother way to look at boot vs lein I've used is: lein is a build tool, boot is a task runner
15:56jballancbuilding code is *a* task that boot can run, but it can run other stuff too
15:57jballancfor example, you could use boot to stand-up an entire ETL workflow, and you'd only have to write the T
15:57jballancbut since lein is more focused on *just* building, it does a better job at building
15:58dysfundoes it? i think they're all much of a muchness as far as building is concerned
15:58jballancdoing the equivalent of `lein uberjar` in boot is still somewhat of an exercise in frustration
15:58jballanc(at least the first time)
15:58dysfun'boot uber jar' is hardly much different
15:58hiredmanso why couldn't you do the etl thing (whatever your conception of it is) in lein?
15:59hiredmanI tend to not using lein for a lot of things either, and just write clojure shebang scripts
15:59jballanchiredman: how do you tell lein to slurp up a directory's worth of files and run some code against them?
15:59jballancthat's boot's bread-n-butter
16:00hiredmanjballanc: exactly, that to me, is obviously something my application should be doing
16:00jballancdysfun: until you try to pre-compile some ns and include some resources...
16:00jballanchiredman: right, which is what I mean when I say that boot is a task runner
16:00dysfuni don't use aot. that's asking for trouble regardless of your build tool
16:00jballancit becomes one with your application
16:01jballanclein always stands alone as "the tool"
16:01jballancbut boot is much more open to melding with app code
16:01hiredmanthat sounds terrible :)
16:01ridcullyi was just pulling some philosophical legs. lein has ~(...) and run/alias which makes it also somewhat "imperativeish". after all it's a darn fine tool, but i am glad we have both to pick from
16:01dysfunit probably *is* terrible, but it's quite handy :)
16:02jballanchiredman: it's really not much different from the attitude of "it's just a library" that pervades the clojure mindset
16:02TimMcystael: Haha, not your fault -- I'm actually filing a bug on tower to make that default setting more obvious.
16:03jballanchalf the time I'm invoking boot tasks from the REPL...that's not something I've ever done with lein
16:04jballanc(not something I think you *can* do with lein)
16:04hiredmanjballanc: I think there are afew things to saw there, but I think the biggest is one is I think you have your arrows reversed, an all singing library sounds more like a framework to me
16:04hiredmanyou could
16:04dysfun'half the time'? wow, you've got quite a dynamic workflow
16:04jballancyou have no idea
16:04hiredmanI fiddled around with it, writing an nrepl middleware
16:05dysfuni can recommend having a release manager who will tell you to stop being an idiot if you fuck the build
16:05hiredmandidn't care for it enough to actually complete it
16:05jballancboot definitely sits near, if not on, the border between framework and library...really comes down to how you use it
16:06jballancwe tend to view it as "the thing that manages files and classloaders"
16:06jballancwhich, btw, even if you don't use boot as boot, you owe it to yourself to check out Pods
16:06jballanca-maz-ing
16:06dysfunpods are the killer feature of boot
16:07dysfunthey're why i can still have autotest-like functionality even when i've not compiled my code in half an hour
16:07hiredman*shrug* I have fiddled with classloader sandboxing
16:07ben_vulpes> pods
16:07ben_vulpestriggered
16:10hiredmanback in the dawn of time, there was a library called fnparse, which was released, but tied to an old version of clojure (or clojure-contrib)
16:11hiredmanI used fnparse for some parsing inside clojurebot, so clojurebot had to stay on that old version of clojure
16:12hiredmanat the time clojurebot evaluated code in the same clojure runtime as it ran
16:13hiredmanso I started looking for alternatives, including jboss module sandboxing type things
16:14hiredmanfor complete isolation, you end up needing to serialize stuff that gets passed across the boundary anyway, so you may as well just run things as services
16:14hiredmanwhich is what I ended up doing
16:15hiredmanhttps://github.com/hiredman/polycosm
16:19jballancI hear ya, and for more complicated things I definitely agree
16:19jballancwith boot it's nice to be able to do simple stuff (like run JRuby alongside a cljs build) without worrying
16:20jballancI've tempted fate to even use Pods to run multiple compojure apps in the same JVM...but haven't actually finished that little project
16:20jballancI might have a different oppinion of pods if I do
16:23hiredmanso, to me, that sounds pretty typical of what I hear from people pushing boot, completely ignoring the fact that exists an entire java ecosystem dedicated to being able to take a bunch of webapps and run them together in the same process
16:24hiredmanin fact, pods are built on a project called shimdandy, which is from project odd, which is a jboss project, which is a big part of that ecosystem
16:25hiredmanlike, stop building whatever, just deploy wars to immutant, and you are done
16:26dysfuni'm so very very unconvinced that war files are the right solution
16:35sdegutisHonestly though, I felt like this was the most accurate Spider-Man yet.
16:35justin_smithaccurate spiderman: boy gets bit by radioactive spider, cancer, death.
16:36ridcullyit's pronounced "hired"
16:36dysfunboy doesn't get bitten by radioactive spider because that sort of dose of radiation would kill the spider
16:36sdegutisboy gets "hired" by a radioactive spider?
16:41domgetterIs it possible to memoize a recursive function after it's been written?
16:42hiredmanyes
16:42sdegutisdomgetter: sure
16:42sdegutis,((fn foo [] foo)) ;; /cc domgetter
16:42clojurebot#object[sandbox$eval25$foo__26 0x3ddb547d "sandbox$eval25$foo__26@3ddb547d"]
16:42sdegutisdomgetter: that's how you name a function within itself
16:43hiredmanit is sort of complicated by certain optimizations the compiler may try to do
16:43hiredmanand that assumes you defing a function
16:44sdegutis,(let [f (memoize (fn foo [x] (prn x) (if (pos? x) (foo (dec x)) x)))] (f 5) (f 5))
16:44clojurebot5\n4\n3\n2\n1\n0\n0
16:44sdegutisdomgetter: boom done
16:44justin_smithbut is it calling the memoized function or the original?
16:44domgetterThat doesn't memoize the inner calls
16:45sdegutisjustin_smith: there's only one 5
16:45domgetter,(let [f (memoize (fn foo [x] (prn x) (if (pos? x) (foo (dec x)) x)))] (f 5) (f 6))
16:45clojurebot5\n4\n3\n2\n1\n0\n6\n5\n4\n3\n2\n1\n0\n0
16:45hiredmanin the past defn macro would insert the functions name as a local binding in the scope of the function body, which means any self recursive calls would not go through the var, which means even if you altered the function in the var to me memoized, recursive calls wouldn't be memoized
16:45sdegutisdomgetter: wait, you want to rewrite it? wha?
16:45hiredmanyeah
16:45hiredmanexactly the thing you are doing
16:45hiredmanmemoize doesn't change a function, it returns a new function
16:46hiredmanfoo is bound to the function you create there
16:46sdegutisdomgetter: ooh I see now
16:46domgetterThat's why my question was "after it's been written"
16:46domgetter:P
16:46sdegutisyou want to memoize calls to (foo) within (fn foo ...)
16:46sdegutisI see
16:46hiredmanwell it is slightly more complicated than that, because global functions with mutable vars will be slightly different
16:47hiredmanwithout some mount of mutablility between the binding and the function, the answer is no
16:47domgetterThat makes sense.
16:54makufiruClojure just feels like the hardest language to get started with. :/ I mostly think it's the burden of trying to learn emacs alongside it. Also not knowing Java doesn't help, those stack traces.
16:55dysfunmakufiru: if it helps, i've been learning lfe recently and i found it harder going in the beginning than clojure
16:55domgettermakufiru: Have you tried going through Clojure for the Brave and True?
16:55makufiru@domgetter I haven't yet. I'll look into that, thank you
16:56makufirudysfun: yeah I don't envy you on that one. haha
16:56domgettermakufiru: http://www.braveclojure.com/introduction/
16:56hiredmandon't dismiss the stacktraces, they are fantastically useful, you should learn to read them
16:57makufiruOh really? I thought it was just a bunch of junk being spit out as a result of running on the JVM haha
16:57dysfunor at least to scan through them enough to recognise what is talking about your code
16:57CStormi will second the book for the brave and true, really good
16:57CStormwill setup you up with both emacs and clojure
16:58CStormand will learn you enough to get going
16:58hiredmanpeople who complain about stacktraces don't read them, and spend their time in chatrooms asking for help from people that do
16:58dysfunthat's not necessarily true. i complain about stacktraces precisely because i read them
16:59dysfunand i can't help but notice that it's often quite hard to find your code in amongst all the other frames
17:00makufiruI'm used to the excellent error messages of Elm/Rust haha. So the stacktraces feel like trying to intuit ancient scrolls
17:00CStormhaha
17:00dysfunelm has a repository for confusing error messages so they can work on improvements
17:00dysfunthey take it very seriously
17:00makufiruIt goes a long way. I can personally vouch for how awesome it is
17:01hiredmanstacktraces and error messages are not the same thing though
17:01dysfuni'm not with you on the rust error messages though. way too many bad ones in there
17:01makufiruI haven't had very many bad ones yet
17:01makufiruadmittedly just doing a lot of basic stuff with it
17:02dysfunyou don't tend to deal with stacktraces much in either elm or rust, however
17:02hiredmana stacktrace shows you the call the callstack that produced an error, which is useful information aside from an error message
17:02ridcullyif you are used to some "seven things went wrong here" of e.g. python the trillion lines of java can be quite daunting
17:03ridcullyit's a skill to hone, to "interprete" the actual error
17:06clyfehttps://github.com/AvisoNovate/pretty makes stacktraces a bit more bearable
17:06momerath_there's some tradeoffs between usefulness (to some), friendliness (to beginners and the common case), and performance in stack traces, but there's also a lot of work to do before you really run up hard against those tradeoffs. Clojure could use some work, but the stack traces are plenty useful, especially if you capture them as objects.
17:08dysfunthere aren't really performance implications. hotspot will happily optimise out exceptions in hot paths
17:09dysfun(and with it your debuggability... c'est la vie)
17:10momerath_keeping the trace data is overhead, even if you can avoid affecting the performance characteristics of the app on a not-overloaded machine
17:11dysfunhotspot will simply optimise out traces in hot code paths
17:11momerath_and indeed, in some cases, they throw out your production debugability - i'd call that a tradeoff
17:11hiredmanactually, the jit will throw the stacktrace away in some cases, and you'll get an exception without a stacktrace
17:12hiredmaneveryone pretty much hates that and turns it off, because they wan't the stacktrace
17:12hiredman(the jvm jit, it is a jvm setting)
17:12momerath_we know
19:12tolstoyI kinda wish stack traces would print the error at the top AND bottom of the trace. :)
19:14tolstoyMost of the time, all I need is the error message, but having to search backwards for it tempts me into JUST printing the error message.
21:12jumanjihi fellas I'm new to clojure can I please get some help http://stackoverflow.com/questions/37357895/how-to-group-collection-of-datoms-tuples-and-get-total-sum-of-its-attribute-v
21:16patham9_https://gist.github.com/patham9/e85e18b390c70221614133d6a87be31e <- how can this be explained?
21:16patham9_these should be equal collections but for some reason it isnt consistent here
21:18tolstoyMaybe (prn ...) that last one to see if there's no an errant string in there where you don't expect it?
21:19patham9_there is no string involved in the comparison check
21:19patham9_just clojure data structure
21:20patham9_as the gist shows
21:20tolstoyI was thinking about that case where when you print something, the strings aren't quoted, but you're right, that doesn't seem to be an issue here.
21:21tolstoyMaybe do a (type ...) to see? I don't know.
21:21patham9_clojure claims that datastructures are the same if they have the equal entries. this is the case here. however the equality check fails
21:21patham9_will try
21:23patham9_1 is a clojure.lang.Symbol oh ^^
21:23domgetterwhat does quoting a vector do?
21:23patham9_while the other 1 is a Long ^^
21:24tolstoyI think quoting a vector quotes all the things in the vector?
21:25tolstoy,(map type [1 2 *])
21:25clojurebot(java.lang.Long java.lang.Long clojure.core$_STAR_)
21:25tolstoy,(map type '[1 2 *])
21:25clojurebot(java.lang.Long java.lang.Long clojure.lang.Symbol)
21:26domgetteroh, interesting
21:27tolstoyAnyway, I was thinging that patham9_'s issue was that not all the values in each vector were the same, even if they printed as if they were.
21:27patham9_yes, as I said, type mismatch between Symbol and Long
21:27patham9_thanks a lot for showing me the type comand
21:27patham9_*command
21:28patham9_made a quoting mistake
21:28patham9_inside of my functions
21:37patham9_hm its very interesting that a number was able to become a symbol
21:37patham9_i wonder how I can do this on purpose
21:37patham9_ah (symbol (str 10)) of course