#clojure logs

2015-07-05

00:06justin_smithrhg135: does the server start asynchronously? if so you may be sending the message before the server is ready to read it...
00:07rhg135it might be but I doubt it. Even so this hangs indefinetely after the client connects
00:10Bronsajustin_smith: do you ever sleep? I feel like you're ever-present here
00:11justin_smithhaha
00:11justin_smithI sleep very reasonable hours actually, I just wake up earlier and turn in earlier than most
00:12justin_smithalso I don't have much of a life
00:13BronsaI must sleep on such an odd schedule that probably mine matches your timezone then
00:39irctcIf I have a long-running function that calls lots of other functions and has side effects (io, db, http requests) what is the best way to handle that? In this case I'll never need to track the results in the main program thread. I tried looking at future but the code never seems to execute.
00:41amalloythe code in a future runs as soon as the future is created, so you must have had some other problem that you are ascribing to future
00:46justin_smithirctc: remember that you won't see errors inside a failed future until you attempt to deref
00:46justin_smithirctc: see stuartsierra's blog post of threads and error handling
00:47justin_smithirctc: http://stuartsierra.com/2015/05/27/clojure-uncaught-exceptions
00:50irctcI did check it for errors by running it all without future. The situation is that I'm using lein test to make sure it's running ok. I thought maybe the tests stopped before the thread stopped (I wasn't seeing the DB update I was expecting). So I put a Thread/sleep in for several minutes (twice as long as it normally seems to take) but no luck.
00:51irctc(let [arg "argument"] (future (long-running-func arg)) (println "Check database later!"))
00:51irctcI assume it's ok to just leave it without being assigned a var for later dereferencing? I won't need that information.
00:53justin_smithif you never deref the future, its body should be wrapped in try/catch
00:53justin_smithotherwise all failures will be totally silent
00:54justin_smithand of course the try/catch should do something verbose in the catch part
00:56irctcgood idea
00:57justin_smithirctc: eg. try (do (future (/ 1 0)) nil)
00:57justin_smithin your repl
00:57justin_smithdoesn't work with the bots here, since they don't let you create futures
00:58justin_smithirctc: the do/nil is because even if you don't deref the future, you can see the error state in the printed form, at least as of clj 1.7
01:00irctcok
01:00irctcthanks
01:03zactsclojure is so etymologically complicatedly symbolicmolationally awesome
01:03justin_smithcomplicatedly?
01:03zactsthere I've said something on this channel that has never been said, probably anywhere on earth, in history
01:03justin_smithhaha
01:03justin_smith,(java.util.UUID/randomUUID)
01:04zactsI'm just trying to do that proof of george carlin
01:04clojurebot#uuid "7b94c77b-1b3f-4143-b5fa-7f1f7b45fc31"
01:04zactsthat the saying "everything has been said before already"
01:04zactsis logically false
01:04zacts(I'm just being silly)
01:04zactsa proof by contradiction
01:04justin_smithzacts: clojurebot just said something that probably won't ever be said again (unless it's being quoted), and probably wasn't said before
01:04zactsoops
01:04zactsproof by counterexample
01:04justin_smithsure
01:06zactsoh and what was that TV show... ugh...
01:06zactshe did borat
01:06zactsbut also he did this other one
01:06zactshe would say technologically like technomologically
01:06zactsI think I just saw a youtube clip of it recently, and it was in my subconcious
01:06zactsoh well.
01:06zacts:-)
01:06zactslaters
02:05jefelanteis there an alternative to the page object model for using selenium webdriver w/ clojure?
05:47rritochHi, whats the best way to make a "hybrid" uberjar which only includes select dependencies in the jar?
05:48rritochIs there some profile that is only applied during uberjar, or something similar I can use.
05:49rritochSome dependencies are needed during compilation, but not needed in the generated uberjar.
05:57rritochNevermind, I figured it out, if I put my compile time dependencies which aren't needed in the uberjar into the dev profile they're excluded from the uberjar.
06:22retrogradeorbithi everyone. I hope someone can point me in the right direction
06:23retrogradeorbitIm looking for the right mutable type to use. atom vs ref vs var
06:23retrogradeorbitI have two threads
06:23retrogradeorbitone is polling some data every 5 seconds and (swap! myatom assoc mytime data)
06:24retrogradeorbitthe other thread I want to poll occasionally and look at the size of myatom
06:24retrogradeorbitamd when it goes over a certain amount
06:24retrogradeorbitI want it to swap! the atom with {} and write the old atom to a file
06:24retrogradeorbitso I did that, and it works great, but now im thinking
06:24retrogradeorbitis an atom right here?
06:25retrogradeorbitThe swap! fn that writes the file may be called more than once, is that right?
06:25retrogradeorbitand if so, the second call may blat the first?
06:25retrogradeorbitshould I be using refs and dosync here to make sure the file only writes once?
06:26retrogradeorbitor is there some nice way to do in an uncorordinated way with atoms?
06:27rritochretrogradeorbit: To start with, if you use an atom or a ref you'll typically keep them in a var either way unless your entire functionality is contained within a single form.
06:28retrogradeorbitok. yeah I have it in a var
06:28retrogradeorbitan atom at the moment
06:29retrogradeorbitis the atom semantics Compare And Swap?
06:29rritochretrogradeoribit: Your operations on atoms should not have any side effects (Such as writing to files) because they can run multiple times. Considering you just want to perform some action based on your stored value, I suggest you use an atom to get into the habbit of thread safety, even though in this case you only need on thread.
06:29rritochretrogradeorbit: The reason you only need one thread is that you should be using add-watch, https://clojuredocs.org/clojure.core/add-watch
06:30retrogradeorbitaaaaaawwww
06:30retrogradeorbityeah right!
06:30retrogradeorbitI didnt think of that
06:30retrogradeorbitso I can add a watch to the atom, and do my size comparison in that?
06:30retrogradeorbitso the add-watch fn can have side effects?
06:31retrogradeorbitis it only run when the swap succeeds?
06:31rritochretrogradeorbit: Let me recheck the atom source code, but I believe the watches are only called when the transaction is successful.
06:32rritochretrogradeorbit: Yes, the watches are only called when the state of the atom has been successfully updated, so your watches can have side-effects.
06:39rritochretrogradeorbit: One thing of note based on this code, it looks like watches will block your update until after the watch operation completes. If your watch logic is going to take a long time to run, you may want to use a "future"
06:40rritochretrogradeorbit: One thing of note based on this code, it looks like watches will block your update until after the watch operation completes. If your watch logic is going to take a long time to run, you may want to use a "future"
06:42retrogradeorbithmm. Im worried about the watcher updating the atom
06:42retrogradeorbitit shouldnt take long, and blocking would be fine
06:42rritochretrogradeorbit: Why would the watcher update the atom?
06:42retrogradeorbitIm trying to archive off the hashmap when its over a size, and reset it to empty
06:42retrogradeorbitso the atom builds and builds
06:43retrogradeorbitsitting in ram
06:43retrogradeorbitand at a certain size, it gets serialised to disk, and reset to empty to continue
06:43rritochretrogradeorbit: I see, a watch + future would be perfect than
06:43rritochBut the re-update is a problem
06:44retrogradeorbityeah. another update to the atom could happen at any time
06:44retrogradeorbitmaybe I need coordination with refs?
06:44rritochHere is what I would suggest, and it is mildly complicated.
06:44retrogradeorbitIm all ears
06:45FarzadBekranguys has anyone been able to get https://github.com/raph-amiard/clojurescript-lua running?
06:45rritochHave your watcher launch a future ONLY when the size of the atom == the max size, because you don't want it running more than once.
06:46rritochNow, when your future runs, have it only strip off the max number, leaving any others behind, using your typical swap! syntax.
06:46retrogradeorbitah ok. will that free up all the memory?
06:46retrogradeorbitif I dissoc a bunch of keys?
06:47rritochretrogradeorbit: If your data is indexed, than the process would be simple, you just deref your atom, grab the last X keys, and then swap! dissoc the keys your archiving.
06:48retrogradeorbityeah its indexed by timestamp
06:48rritochretrogradeorbit: You will probably also want to add a "shutdown" hook to save any remaining data in the atom when your application closes normally.
06:49retrogradeorbitThat sounds good. How would I go about adding a shutdown hook?
06:49retrogradeorbitI suppose I should go read up on clojure and signals
06:50retrogradeorbitcatch a SIGTERM
06:50rritochretrogradeorbit: Good question, I'm not sure what the clojure way is.
06:50retrogradeorbitcool. np.
06:50rritochIt's basically the same as the Java way
06:50rritochSee: http://stackoverflow.com/questions/11709639/how-to-catch-ctrlc-in-clojure
06:51retrogradeorbitlet me try the watcher method first, and then I'll add the shutdown hook
06:51retrogradeorbitat the moment Im running it all in cider in emacs anyway
06:51retrogradeorbitso when I wrap it into an actual application I'll work on the shutdown
06:52retrogradeorbitthanks heaps rritoch. You've been most helpful
07:05rritochretrogradeorbit: One more thing that came to mind, in your future task, be sure to include a loop that repeats for as long as the number of keys is greater than your maximum, otherwise you have a potential bug if it takes longer to write the max entries than it takes to collect the max entries.
07:06rritochretrogradeorbit: It seems to be a rare case, but it could happen if it's running on a heavily loaded server.
07:14rritochretrogradeorbit: If you remove the values before you save, it won't be a problem, because a second thread will handle it, but if you remove them after, than you'll need to run again while number is > max.
08:19crocketIs there a decent gitlab/github alternative written in clojure?
08:20crocketI found an alternative written in scala.
08:20crocketGitBucket in scala
08:52deadghostI kind of feel like learning another language
08:52deadghostwhat's something that will complement my clojure?
08:55justin_smithdeadghost: there's a lot to learn in haskell (whether that's a good thing is up to you of course)
08:57crocketOk, I decided to replace GitLab with GitBucket for easier maintenance.
08:58deadghostcrocket, if it doesn't have to be clojure
08:58deadghostI quite like gogs
08:58deadghostmuch much lower memory footprint than gitlab
08:59deadghostmy needs are simple though
08:59crocketdeadghost, Gogs vs GitBucket
08:59crocketGitBucket is also simple.
08:59deadghostI just need a git webui that lets me have push to deploy scripts
09:00crocketBut, GitBucket is not exactly light. It consumes 610MB.
09:00crocketWhile Go is not a terrible language, I think Go is not a good language.
09:01crocketIt feels mediocre.
09:01crocketScala manages to be barely better than mediocre, but clojure is elegant.
09:03crocketdeadghost, Its low memory footprint is definitely desirable.
09:04crocketGitLab is complex, slow, and greedy of memory.
09:04deadghostyes
09:04deadghostvery much yes
09:04deadghostI used gitlab previously
09:05crocketMaintaining GitLab natively on ArchLinux is a nightmare.
09:05crocketEvery upgrade of ruby in ArchLinux breaks GitLab.
09:05crocketGitLab is fragile.
09:07rritochDoes anyone know if *use-context-classloader* is true or false by default, and if it's not true, whats the best way to set it to true from Java?
09:07crocketdeadghost, Do you run gogs in a docker container?
09:07deadghostnope
09:07justin_smithrritoch: it's true in my repl.
09:08justin_smith1.7
09:09kitallisI'm trying to split my defroutes (compojure-api) into multiple files because it's getting large. I now reconcile them in a single file under (defapi) and (swaggered), this seems to want to re-require all the files that each defroutes macro required internally outside as well – is there a way to get around this?
09:09deadghostcrocket, my gogs shows 23348kb
09:09crocketdeadghost, If I replace GitLab with either GitBucket or Gogs, I'll be freed of maintenance nightmares.
09:09deadghost0.6% server mem usage
09:09crocketDo you use SQLite3?
09:10deadghostwas that an option for gogs?
09:10deadghostI think I went with a sql
09:10rritochjustin_smith: Thanks, I hope that's the default. My loggs say that when the OSGI activator ran the contextClassloader was the system classloader, so hopefuly that's the source of this bug.
09:10deadghostyeah I went with postgresql
09:11justin_smithkitallis: what do you mean by "this seems to want to re-require" ?
09:11Deraenkitallis: You need to use new version (where swaggered is deprecated) and defroutes*
09:13crocketdeadghost, SQLite3 is the default in gogs.
09:13crocketYou don't need a database server to run gogs.
09:13crocketEven simpler if you don't need performance.
09:14deadghostcrocket, I heard they tend to have issues crop up for sqlite in the past
09:14kitallisjustin_smith, a.clj has dep x and (defroutes* a); b.clj has dep y and (defroutes* b); i refer to both of these in handler.clj as dep a and dep b –– this fails handler.clj as it wants dep x and y as well
09:14Deraenkitallis: justin_smith: In old versions swaggered didn't do namespace resolution so if some code referred some var using alias, the route file had to have the same alias even if route was included from other namespace
09:14kitallisI'm sorry if that's confusing
09:15kitallisDeraen, I had no idea this was the case
09:15Deraenkitallis: What version of compojure-api are you using?
09:15justin_smithDeraen: oh, that's a terrible design
09:16kitallisI just checked the docs, it is indeed gone, I'm using 0.15.0
09:16deadghostcrocket, I'm generally satisfied with gogs
09:16Deraenkitallis: this was changed in 0.20, that's why docs don't warn about this anymore
09:16deadghostuntil recently development consistently ticked along
09:16deadghostbut it's still missing some niceties like deploy keys
09:17kitallisI wish compojure-api was just regular functions
09:17Deraenjustin_smith: Yeah compojure is not exactly designed to be extended, that's by compojure-api does loads of complicated macro magic
09:18Deraenkitallis: Unfortunately it isn't possible without rewriting compojure completely
09:18Deraenkitallis: But we are thinking about writing a bidi adapter for ring-swagger
09:19crocketdeadghost, It seems GitBucket is easier to set up and upgrade than gogs.
09:19crocketI can't figure out how to configure gogs.
09:20deadghostgogs config was one file
09:20deadghostI don't have xp with gitbucket but w/e works
09:20Deraenkitallis: Yada (http://yada.juxt.pro/index.html) already combines bidis data based routing with swagger docs
09:21deadghostI used to be on a 2gb mem server so I prioritized mem consumption
09:21kitallisyeah, I remember specifically picking compojure-api over bidi last year because of swagger integration
09:22kitallisthis should be good.
09:25crocketdeadghost, Oh, I was just confused at first.
09:25crocketGogs generates config files for me.
09:26crocketAnd, it uses SQLite3 by default.
09:30crocketdeadghost, One advantage of GitBucket is it has an intergrated SSH server so that you don't have to set up a system user account for ssh access as you have to do with gogs.
09:32crocketdeadghost, Why don't you use SQLite3 for even less memory footprint?
09:32deadghostbecause I heard there were previous problems that cropped up with sqlite3 w/ gogs
09:32deadghostmight be resolved now idk
09:32deadghostand 0.3% server mem usage is satisfactory for me
09:33deadghostI don't even remember how much gitlab used
09:33deadghostbut it was a lot
09:33deadghost0.5gb-1gb
09:34deadghostcrocket, at this point I'd have more memory savings optimizing for my clojure programs
09:34crocketdeadghost, When did the issue occur? Can you refer me to the issues so that I can check if they are closed by now?
09:35crocketdeadghost, clojure runs on JVM, so you can't save a lot of memory as you do on other natively compiled languages.
09:35deadghostcrocket, https://github.com/gogits/gogs/issues/805
09:35deadghost>Hmm, SQLite is always the troublemaker.
09:35deadghostthat's enough for me to sidestep the issue entirely
09:36rritochIs there any way to get lein uberjar to use the dev profile during the compilation phase? I'm getting errors if I try to "lein uberjar" without running "lein javac" first.
09:36deadghostcrocket, see I have no idea how jvm memory stuff works
09:37crocketdeadghost, JVM simply doesn't return memory to OS.
09:37deadghostuntil recently I just let my programs start the jvm with the default
09:37deadghostwhich iirc is 0.5gb
09:37crocketGarbage collection happens in JVM, and JVM doesn't return unused memory space to OS.
09:37crocketThis is a problem if you're optimizing for memory usage.
09:37deadghostcrocket, right but you can start the jvm to grab less memory initially yeah?
09:38crocketdeadghost, The best options that I know of are -Xms and -Xmx.
09:38deadghostright now I'm also running multiple sites with the same deps in separate jvms
09:39deadghostI suspect I can just dump them in one jvm or something
09:39crocketdeadghost, Do you mean a servlet container?
09:39crocketForget about application servers.
09:39crocketThey are too complex
09:39deadghostI was actually going to use wildfly
09:39deadghostsince I'm on immutant
09:40deadghostand yes the xml config is complex
09:40crocketThe true complexity lies in managing classpaths of multiple applications in a single JVM instance.
09:40crocketThis is a mess.
09:41crocketInstead, you want to make each web application as light as possible.
09:44crocketdeadghost, Is SQLite a trouble in other situations?
09:45deadghostcrocket, don't know
09:45deadghostbut that comment suggests that at some point it was
09:53rritochAnyhow, I'm nearly at "proof of concept" with the clj-osgi-namespaces project. It successfully bundles clojure with an OSGI activator and a bundleListener which facilitates swapping of clojure namespaces. I still need to test it against a real clojure bundle, but it looks like this may work based on my logs.
10:03jefelantedoes anyone have any experience with clj-webdriver and could help with this question? https://groups.google.com/forum/#!topic/clj-webdriver/xJL0fsJG6o0
10:06crocketWhat a pain...
10:12dstocktonjust to get an idea, how many people are using component library to organise their applications?
10:42crocketWhat is a component library?
11:08justin_smithcrocket: stuartsierra/component
11:08justin_smithdstockton: I use it and try to spread the good news
11:14sveri+1 on component
11:14sverior a similar library
11:23dstocktonthanks justin_smith and sveri
11:34digiorgiI am learning STM and in some point appeared the "write skew" problem, but i can't find in google a text explaining what is that? Did you have some link?
11:35digiorgido*
11:36weebzdigiorgi: I don't have an answer to your question, but do you have any resources on STM in Clojure or a language other than Haskell? I would like to learn about it, but every resource I've seen explains in Haskell which I'm still not comfortable in
11:39justin_smithdigiorgi: this ppt explains it pretty well I think https://blog.itu.dk/ET20-F2013/files/2013/04/a5b-relaxed-db-kap-5-countermeasures-against-isolation-anomalies-130330.ppt (opens OK in libreoffice)
11:40justin_smithdigiorgi: tl;dr most relevant slide "The write skew anomaly is a situation where two transactions both read two different related records. Next, the two transactions each update one of the two related records. Finally, both transactions commit. If a constraint has existed between the two related records, it might have been violated."
11:41justin_smithdigiorgi: clojure STM transactions handle this by marking not just the data you write in a transaction, but also the data you read, and there is a retry if any of it changes before commit
11:42justin_smithclassic write skew: "the gift of the magi" by o henry
11:52digiorgijustin_smith: thanks!!
12:22dnolenBronsa: ping
12:22Bronsadnolen: pong
12:22dnolenBronsa: in read* why do you use trampoline instead of recur?
12:23Bronsadnolen: we need to recur to target https://github.com/clojure/tools.reader/blob/master/src/main/cljs/cljs/tools/reader.cljs#L832, recur would jump to https://github.com/clojure/tools.reader/blob/master/src/main/cljs/cljs/tools/reader.cljs#L834
12:38dnolenBronsa: k, makes sense, thanks. Thanks doing some more serious profiling of tools.reader via Chrome DevTools and going through the hot spots.
12:41Bronsadnolen: in the jvm version we don't need the trampoline since we use a macro for log-source rather than a function. I guess now that cljs supports macros we could do that aswell?
12:42dnolenBronsa: not sure I understand, why can't use a macro in this case in ClojureScript
12:44Bronsadnolen: IUC using defmacro wasn't an option when andrewmcveigh ported t.r since it couldn't be loaded in cljs
12:44Bronsabut I might be wrong
12:45dnolenhrm ok I'll take a look at that
12:45dnolenBronsa: is it because this is a macro that needs to be done at runtime or something?
12:50Bronsadnolen: no, it's just a regular macro https://github.com/clojure/tools.reader/blob/master/src/main/clojure/clojure/tools/reader/reader_types.clj#L344-L351
12:50Bronsadnolen: if bootstrapped cljs can do that, then there's no point in using a function
12:51dnolenBronsa: but I don't understand bootstrapped even matters in this context
12:51dnolencurious as to why the macro was moved into a macro ns as usual
12:51dnolens/was/was not
12:52Bronsadnolen: probably just a misunderstanding by both me and and andrewmcveigh
12:52dnolenBronsa: bootstrapped ClojureScript isn't going to support putting macros inline anyway
12:52dnolenthey always need to be in a macro ns
12:52Bronsadnolen: does it need to be a cljc or something 1.7-only?
12:53dnolenBronsa: it's simpler than that, macro resolution happens by changing the ns
12:54dnolencljs.core -> cljs.core$macros
12:54dnolenso any ns that wasn't loaded via require-macros will never be used to resolve macros
12:55Bronsadnolen: if changing log-source to be a macro like in the jvm version doesn't *require* 1.7 then I don't see why it couldn't be done
12:56dnolenBronsa: yeah doesn't require 1.7 at all, just a ClojureScript .clj macro file as always
12:57Bronsadnolen: if you're currently hacking on t.r I won't bother changing that myself -- otherwise let me know and I can do it
12:58dnolenBronsa: currently hacking on it
12:59Bronsadnolen: cool then, there should be just two instances where log-source is used, should just need to unwrap the fn & replace the trampoline with a recur
14:05dnolenBronsa: approaching an order of magnitude faster than master https://github.com/swannodette/tools.reader/commits/cljs-bootstrap
15:44murddTrying to port an old java application that was using deprecated internal clojure apis to invoke clojure code.
15:44murddOne of the things it had to do was change the class loader clojure, as it runs within a class loader itself.
15:45murddI can't see how to do this with the new api though.
16:55xzilendHi there, I'm trying to use ring-mock to test a file-upload POST to an API. Does anyone have any examples of how to write this kind of test?
19:11Matachinesjoin #clojurescript
19:11Matachineslol tahts embarassing
19:52fredfeFor anyone using Jenkins on deployment, how do you handle uberjar deployment? How do you send a jar to a server, start it; later, send the next version over, shut down old, start up new?
20:03justin_smithfredfe: when I used jenkins we had a shell script to do the restart, and used scp or s3 upload
20:03justin_smith(for s3 you then need to ask the server to do the download)
20:04justin_smithfredfe: also, jsvc can be used with clojure, and can simplify some of the startup / shutdown / restart stuff
21:13monstaHow can I flip arguments in clojure?
21:16justin_smithmonsta: I don't know of a lib that does it, but this gist looks good https://gist.github.com/micmarsh/bcbe19c9de8bb7a471bf
21:20amalloyjustin_smith: if you are looking for a laugh, check out one of the first clojure libraries i wrote: https://github.com/amalloy/hot-potato
21:21justin_smith;; warning warning unhygenic macro.
21:27monstaOne more question, how can I use a thread macro inside another thread macro?
21:27amalloymonsta: the answer is like...you just use a thread macro inside another thread macro. unless you have a more specific question it's hard to provide a userful answer
21:29justin_smith,(-> 1 list (-> (map inc)))
21:29clojurebot#<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.core$inc>
21:29monstaOk, how a make work something like (->> 3 (-> (/ 4)))?
21:29justin_smithoops
21:29justin_smith,(-> 1 list (->> (map inc)))
21:29clojurebot(2)
21:29justin_smithmonsta: you can only do the opposite
21:29monstaok, thanks for the help
21:30justin_smithmonsta: for obvious reasons, ->> can be inside -> but not visa-versa
21:31justin_smith(well, without some other trickery at least)
21:31Surgoyeah it's important to remember that macros aren't necessarily composable
22:55clojer`lein new reagent app` with advanced optimisation produces a 446Kb file. Are there other settings, gzip aside, which will reduce the size? I notice the file includes a minified React 13.3 but the Reagent code doesn't seem to be minified.
23:05TimMcjustin_smith: I've been using as-> quite a bit recently.
23:05justin_smithyeah, that's a handy one
23:05TimMcThe only thing I don't like is (let [d ...] (as-> d d ...))
23:06justin_smithTimMc: that syntax is like that so nesting inside -> works smoothly
23:07TimMcSure, the part I don't like is the repeated symbol.
23:07TimMcI could use a different symbol as in (let [d ...] (as-> d r ...)) but that feels weird too.
23:08justin_smithgiven how as-> macroexpands, you could just use (as-> ... d ...)
23:08TimMc(This comes up when the thing is bound, then I do some conditionals, and then I process it with as-> (so it's not appropriate to inline the initial computation as the first arg to as->)
23:08TimMc)
23:08justin_smithahh
23:10justin_smithI don't know your criteria of propriety, but as-> just expands to a big let where every clause is bound to the same symbol
23:10justin_smithso depending on your conditionals it might still work
23:11TimMcNah, I usually don't want to execute the as-> at all when the guards fail.
23:12TimMcThis might just be my coding style.
23:12justin_smith(some-> .... (as-> d ...)) ?
23:12justin_smithhaha
23:12justin_smithyeah, this is clearly a style thing
23:12TimMc~guards
23:12clojurebotSEIZE HIM!
23:13justin_smithbut who watches the add-watch?