#clojure log - Feb 26 2016

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

0:15 seanirby: is there a way i can associate an nrepl server with a clojure app

0:18 wait nvm, i may be confused

3:44 akonring: \list

7:48 freddy_: hi friends

9:04 kungi: Can I limit the number of threads to 1 while running my tests on the JVM?

9:58 nicola1: did cider-refresh stop working for anyone else here in the past couple of days?

9:59 i can't seem to load any module in the repl anymore more than once

10:11 kwladyka: nicola1 maybe you need a licence?

10:11 nicola1 trial end?

10:13 nicola1 restart intellij? update?

10:14 nicola1: this cider https://github.com/clojure-emacs/cider

10:17 i think upgrading the package broke something, but pinning (from cask) the git version of cider won't work at all (cider fails to load some "cider-test" file, even if i specify cider's latest commit on which melpa's version is based on)

10:20 hexa: anyone ever tried to cider-jack-in with a lein-exec script ?

10:37 kwladyka: nicola1 i use cider with intellij, so i don't know situation in eamcs

10:55 sdegutis: Isn't this sufficient for turning Clojure rows into a CSV string? https://gist.github.com/sdegutis/55febb1065df0a85208e

10:56 Of course, the two "," instances could be replaced with an optional variable as well as the "\n" instance. But even then, it's, like, complete. Right?

11:00 TimMc: kungi: You mean limit the total number of threads in the JVM, or change whether your tests are multi-threaded?

11:05 kungi: TimMc: I was asking the wrong question

11:05 TimMc: I found my bug an d have to think about it for the weekend

11:11 TimMc: :-)

11:18 justin_smith: nicola1: CIDER emacs upgrading in place *always* breaks

11:19 nicola1: the two things that typically fix it are deleting all .elc files related to clojure stuff (including things like clojure mode that aren't strictly CIDER), and deleting everything clojure related entirely then installing the version you want

11:20 personally I opted out of using a tool that breaks when upgraded, but that's a personal decision of course

11:24 nicola1: justin_smith: i've had it break a few times but it's usually resolved quickly; i'd be happy using an older version (that's why in my cask setup i specify the git commit to pull from) but in that case it fails to even start

11:24 justin_smith: nicola1: no it's not about using an older version

11:24 nicola1: btw i'm erasing the whole .cask directory when reinstalling, no success though

11:25 justin_smith: it's that updating without deleting first breaks it

11:25 sdegutis: justin_smith: I have not had problems upgrading CIDER

11:25 justin_smith: oh

11:25 sdegutis: congratulations

11:25 sdegutis: justin_smith: I've had to find the right version numbers but that's about it

11:25 justin_smith: how often do you upgrade?

11:25 sdegutis: Like twice a year at this rate

11:25 That's about how often Cider comes out with new versions tho

11:25 justin_smith: sdegutis: that's why it is OK, it breaks when you upgrade

11:25 sdegutis: what breaks?

11:25 justin_smith: CIDER

11:25 random crap

11:25 everywhere

11:26 sdegutis: normally, in emacs, when a package has a new version you can just pull it in

11:26 sdegutis: ok

11:26 justin_smith: sorry you've had bad experiences with it :(

11:26 justin_smith: i normally delete the old version and pull in the new version for upgrades

11:27 justin_smith: sdegutis: I had a coworker who would turn .cljc files into clj / cljs files because he did not have a CIDER new enough to work with cljc properly and refused to update because it would break :(

11:27 sdegutis: justin_smith: that would be frustrating indeed

11:29 TimMc: justin_smith: o_o

11:29 I feel like as long as you have paredit, further editor support is not really all that necessary.

11:30 sdegutis: so, unrelated: i'm getting closer this week to finally using component in our whole app!

11:30 I'm still trying to figure out how to make the router be able to be a component.

11:30 justin_smith: TimMc: that's my take as well - though auto-indent that behaves properly is also very nice

11:30 sdegutis: I like the idea of the router and the route-handler being separate components. That's how duct does it right?

11:31 justin_smith: sdegutis: the way I would do that next time is passing a hash-map containing all the handlers in the system (each component adding to it as needed) and then finally having the router pull out the functions and middlewares it uses from that map

11:32 I don't know duct though

11:32 sdegutis: justin_smith: hmmm interesting to have each component have its own handlers

11:32 justin_smith: or middlewares

11:33 each stateful thing probably has the ability to offer its state to another handler, or a handler that accesses its state (if not both)

11:33 sdegutis: justin_smith: ignore the duct comment, I just meant that's how weavejester's ring-component lib works, it allows the ring-jetty-adapter to be wrapped in a component which can take another component as the handler

11:33 justin_smith: got it

11:34 yeah, you could make one component that contains the http-adaptor and another that constructs the handler, or combine them. The former would be a small thing without the handler / middlware definitions.

11:37 sdegutis: hmm

11:37 man, so many options

11:37 arg

11:38 justin_smith: sdegutis: clearly we need to get 1250 people to try each option, and then tabulate the total complexity and error rate of each resulting codebase and then we can calculate the objective best choice

11:39 sdegutis: agreed

11:40 justin_smith: sdegutis: my analog watch only allows setting in the forward direction, and is 15 seconds fast, and this makes me angy

11:40 *angry

11:40 sdegutis: *hangry?

11:40 justin_smith: I need to spin it almost 12 whole times to get it right and even then what are the chances I get it perfect that time

11:41 sdegutis: also I am permanently hangry, because I decided to lose weight. This is a seperate topic and completely off topic.

11:42 sdegutis: justin_smith: why does your time need to be so accurate? are you a train conductor for a living?

11:43 justin_smith: sdegutis: wait I thought I was an engineer

11:43 sdegutis: hahahaha i get your joke

11:43 justin_smith: OK different kind of engineer my bad and maybe I should not even use that term because we are not certified and I did not go to engineering school

11:43 well, that's a load of my mind, thanks

11:44 sdegutis: realistically my watch could be 10 minutes off and nobody at work would never notice

11:45 sdegutis: justin_smith: all the clocks in our house are off from each other by many minutes and seconds

11:45 justin_smith: I'm gonna get a watch that just blinks 12:00 all the time

11:46 sdegutis: well its always 12:00 somewhere!

11:48 justin_smith: sdegutis: blinking 12:00 is a totem, capturing the spiritual energy of all misconfigured devices and software everywhere.

11:53 sdegutis: :D

11:53 hi

11:55 TIL you shouldn't use anonymous functions for things so much because they don't have metadata

11:55 ,(meta (fn []))

11:55 clojurebot: nil

11:55 sdegutis: Literally impossible to determine its arglists.

11:55 justin_smith: but hey you could put meta on it

11:55 sdegutis: Oh right lol

11:59 justin_smith: ,(defn has-arity [f n] (try (apply f (repeat n nil)) true (catch clojure.lang.ArityException _ nil) (catch Throwable t true)))

11:59 clojurebot: justin_smith: Excuse me?

11:59 justin_smith: haha

11:59 sdegutis: the above thing is an abomination, but it correctly tells you whether a function has a given arity

11:59 I probably should have named it has-arity?-lol-don't-use-this

12:00 sdegutis: Actually

12:00 got an idea brb

12:00 justin_smith: oh no I gave sdegutis an idea I'm scared

12:01 sdegutis: you will regret it

12:03 Bronsa: sdegutis: no function has arglist metadata

12:03 it's been that way since 1.3.0

12:04 sdegutis: IT WORKS

12:05 justin_smith: sdegutis: how about a fn-with-arglists macro?

12:05 sdegutis: https://gist.github.com/sdegutis/62f0b4177f01cf331218

12:05 justin_smith: even better

12:05 justin_smith: oh, man...

12:06 sdegutis: it's like pretty legit kinda!

12:06 Bronsa: there's with-local-vars for that

12:06 justin_smith: sdegutis: instead of the let / gensym you could just do (let [v# (defn x# ~@stuff ...)] ...)

12:06 Bronsa: with-local-vars attaches the kind of metadata defn would?

12:06 sdegutis: justin_smith: oh right!

12:07 I forgot x# does gensym for me

12:07 Bronsa: justin_smith: no, right


12:07 get it together, man

12:08 sdegutis: updated

12:08 https://gist.github.com/sdegutis/62f0b4177f01cf331218

12:09 this is probably the cleverst thing ill ever accomplish in clojure

12:10 justin_smith: sdegutis: (defmacro fn+ [& stuff] `(doto (defn n# ~@stuff) (partial ns-unmap *ns*)))

12:10 sdegutis: tested in my repl, works

12:10 sdegutis: oh man

12:10 I was just about to type "i kinda wanna find out how to use doto on this thing)

12:10 justin_smith: now you know!

12:11 TimMc: That partial doesn't need an extra set of parens?

12:11 justin_smith: TimMc: nope

12:11 err...

12:11 TimMc: you sure?

12:11 justin_smith: TimMc: you are correct!

12:12 TimMc: the ns-unmap silently misbehaved

12:12 sdegutis: justin_smith: wait doesnt that require comp meta :name too?

12:12 or are you able to just give that a var?

12:12 cuz it says 'sym' in the docstring

12:12 (doc ns-unmap)

12:12 clojurebot: "([ns sym]); Removes the mappings for the symbol from the namespace."

12:12 justin_smith: sdegutis: I think it does

12:12 sdegutis: yes, fixing

12:12 sdegutis: yeah so that shuldnt work and doesnt work here

12:13 i trieda comp version but i think i got it wrong cuz it no worky

12:14 dang this tricky

12:15 justin_smith: defmacro fn+ [& stuff] `(doto (defn n# ~@stuff) (->> meta :name (ns-unmap *ns*)))) ; TimMc sdegutis fixed

12:16 thanks for the quality QA

12:16 sdegutis: oh man so smart

12:16 justin_smith: wins

12:18 justin_smith: https://gist.github.com/sdegutis/62f0b4177f01cf331218

12:18 this is just terrible

12:18 why would you contribute to such a terrible invention justin_smith

12:18 and TimMc

12:18 how terrible of a macro

12:18 my goodness

12:19 so awesome

12:21 justin_smith: sdegutis: it would be nice if instead the thing that attached metadata was a separate composible function

12:21 so instead of making a var just for the side effect of getting the metadata we want, we could pull that metadata-generator in

12:21 kind of like how destructure is just a function you can call in your macro if you want it

12:22 sdegutis: justin_smith: that would be impossible tho unless your fn was quoted

12:22 unless..

12:22 * sdegutis experiments some more lol

12:23 justin_smith: sdegutis: look at the source to defn, most of the code is just building the metadata map

12:23 sdegutis: if that happened in a separate function, we could use it

12:23 TimMc: open a jira ;-)

12:23 justin_smith: TimMc: seriously considering it!

12:24 * justin_smith is off to fork clojure.core, and open the doors to a world of frustration.

12:24 sdegutis: justin_smith: i feel 100% confident everyone will be against the idea

12:24 justin_smith: sdegutis: oh I know it, but it's the principle of the thing!

12:25 sdegutis: justin_smith: ok well if you post it then link me ill +1 it

12:25 although itll probably be canceled out by amalloy's -1'ing it

12:26 justin_smith: sdegutis: he has a bot that just -1s anything you +1

12:29 Bronsa: caveat is that it'll only do that on bad ideas

12:32 sdegutis: Bronsa: like he said

12:39 I like how nicely assoc works with defrecord.

12:39 Nice job guys.

12:47 Why is this?

12:47 ,(do (definterface Bar) (defrecord Foo [quux] Bar) ((juxt identity type) (dissoc (Foo. 2) :quux)))

12:47 clojurebot: [{} clojure.lang.PersistentArrayMap]

12:47 sdegutis: That's unexpected to me. I'd assume it would try to retain the type.

12:48 Even this:

12:48 ,(do (definterface Bar) (defrecord Foo [quux zappa] Bar) ((juxt identity type) (dissoc (Foo. 2 3) :quux)))

12:48 clojurebot: [{:zappa 3} clojure.lang.PersistentArrayMap]

12:48 TimMc: When you remove a basis key on a record, it stops being a record.

12:49 justin_smith: sdegutis: yeah, that's been the expected behavior for a while now - I'm thinking at least since 1.5? maybe before that even?

12:49 sdegutis: Is that desired behavior?

12:49 TimMc: "expected"

12:49 justin_smith: definitely explicit - I remember it changing

12:49 Bronsa: Bar is completely useless to your example

12:49 sdegutis: Yeah I carefully avoided using the word "expected" in my last question.

12:49 It has disparity with assoc:

12:50 Bronsa: justin_smith: I think that's actually always been the case, not a 1.5 change

12:50 sdegutis: ,(do (definterface Bar) (defrecord Foo [quux] Bar) ((juxt identity type) (assoc (Foo. 2) :quux nil)))

12:50 clojurebot: [#sandbox.Foo{:quux nil} sandbox.Foo]

12:50 Bronsa: sdegutis: rationale is that by being X + something else you're still X, by being X - parts of X you're no longer X

12:50 sdegutis: Bronsa: hmm I can see that

12:51 still, it feels wrong

12:51 Bronsa: some would argue not behaving this way feels wrong

12:51 TimMc: Where it gets gross is when you want to break apart a map and reconstruct it.

12:51 (into (empty m) (for [[k v] m] ...)) works great to preserve type for most maps, but not for records

12:51 Bronsa: where it gets gross is when (empty some-record) throws but (dissoc some-record record-key) doesn't

12:52 justin_smith: (assoc instance :field :temporarily/removed)

12:52 haha

12:52 TimMc: Aw man, empty throws on records? Didn't know that.

12:52 Bronsa: yeah

12:52 TimMc: yuck yuck yuck

12:52 Bronsa: it feels really wrong that empty doesn't behave like reduce dissoc (keys record)

12:52 sdegutis: TimMc: that makes more sense though, because you're reconstructing a map from only the fields of a record, without "re-attaching" the metadata

12:53 TimMc: whereas dissoc seems more like removing a field while preserving the rest of the thing

12:53 Bronsa: I'd rather have either both dissoc/empty throw or have them both fallback on normal maps

12:53 there's no good reason why (defrecord X []) (empty (X.)) shouldn't work

12:53 sdegutis: naturally its far too late to make any changes like that since it would break every clojure app ever

12:54 Bronsa: Don't think so

12:54 if something hasn't worked, making it work shouldn't break anything

12:55 and if you're depending on (f x) throwing an UnsupportedOperationException, your code deserves to be broken

12:55 justin_smith: Bronsa: unless someone was intentionally throwing errors as flow control, and if they did that, they deserve broken code.

12:55 right, right

12:55 Bronsa: justin_smith: they deserve more than that

12:55 unless they're doing that as an optimization :P

12:56 but in that case, you're still not going to throw an UOE

12:56 justin_smith: IIRC core.match uses exceptions as flow control for non-local returns

12:57 justin_smith: ick

12:57 sdegutis: Bronsa: you planning to file a jira ticket?

12:57 Bronsa: no

12:57 sdegutis: ok i might then

12:57 Bronsa: justin_smith: it's surprisingly fast

12:57 justin_smith: Bronsa: I'm sure it was a perf improvement over the sane option, but still, ick

12:58 Bronsa: justin_smith: you're either going to use recursion or exceptions if you want to backtrack in clojure

12:58 since there's no goto

12:58 or explicit return

12:58 (both or which exist in java)

12:59 (both of which are incredibly useful for this kind of stuff)

12:59 justin_smith: that's true

13:00 and also sad, it would be nice to have a cleaner thing like continuations

13:00 Bronsa: ¯_(ツ)_/¯

13:00 I honestly don't think continuations are much cleaner thatn gotos

13:00 than*

13:01 justin_smith: well, they are first class, but I guess it's not so hard to make a goto first class and juggle lexical environments to go with them...

13:03 sdegutis: Bronsa: what about the continuation monad?

13:19 gfredericks: if you were using test.check's recursive generator

13:20 (gen/recursive-gen some-collection-generator-fn some-scalar-generator)

13:20 would you expect it to ever generate pure scalars, or only collections of varying depths?

13:23 also does anybody use freenode from erc and how can I get past that weird auth thing it does now.

13:25 hiredman: gfredericks: well, only generating collections of various depths would make it weird that you passed in a scalar generator

13:25 gfredericks: hiredman: I mean for (gen/recursive-gen gen/vector gen/boolean), it could generate [true [false false]] but never true or false

13:25 hiredman: right

13:25 gfredericks: so the scalar generator does get used either way

13:26 hiredman: if you are have a tree generator, would you ever generate just a leaf

13:26 gfredericks: yeah, same question

13:27 I'm hoping there'll be a compelling example of some sort :)

13:27 I think it's relatively easier to get one from the other

13:27 s/easier/easy/

13:28 http://dev.clojure.org/jira/browse/TCHECK-83

13:28 I think I created this when I was making a json generator and got surprised when it didn't generate any scalars; but on the other hand in some json contexts pure scalars are considered invalid I think

13:29 hiredman: if you where testing some kind of recursive tree traversal, depending on the traversal code, you might want to test hitting a leaf

13:32 although, if you are thinking of it as a tree kind of data structure, a lot of those have lots of rules associated with their structure, so you can't just generate them recursively willy nilly

13:33 gfredericks: rules that are only valid at the root in particular?

13:34 it might make sense to restrict this to use cases where you can generate things recursively willy nilly

13:34 given the signature of the function

13:36 hiredman: a tree structure I might want to test would be, I dunno, a red black tree, but those have rules about what nodes can be children of other nodes, and are restricture to two children per node

13:36 yeah, only things willy nilly

13:36 gfredericks: yeah, I think that would require something more general/customizable

13:36 hiredman: so like json or edn

13:36 gfredericks: right

13:37 speaking of trees it is Bronsa

13:37 hiredman: an edn generator I would definitely expect to hit leaves

13:38 gfredericks: you could also argue that including leaves is better for test.check uses in particular to avoid accidentally undertesting

13:38 I think adapting it to not do leaves is as simple as calling (collection-gen-fn (gen/recursive-gen collection-gen-fn scalar-gen))

13:42 okay I'm convinced

13:42 everybody brace for minor breaking changes

13:42 hiredman: a clojure code generator that did included generating type hints would be nice

13:42 gfredericks: is that related?

13:43 hiredman: not really

13:43 gfredericks: okay cool just checking

13:43 thought I was missing something

13:43 has somebody written a general code generator somewhere?

13:47 amalloy: justin_smith: never fear, your has-arity? is in fact not correct

13:47 justin_smith: amalloy: awesome, what's the mistake?

13:48 amalloy: try it on (fn [] (inc 1 2 3 4))

13:48 it'll claim not to have arity 0, but of course the problem is that in lacks arity 4

13:48 justin_smith: oh, of course

13:48 cool, I feel much better now

13:49 sdegutis: Some aspects of Component really confuse me. Is this normal?

13:49 amalloy: it's the same reason you get bogus errors for stuff like (defmacro fo [] (inc 1 2 3 4))

13:49 ,(defmacro foo [] (inc 1 2 3 4))

13:49 clojurebot: #error {\n :cause "Wrong number of args (4) passed to: core/inc--inliner--4489"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "clojure.lang.ArityException: Wrong number of args (4) passed to: core/inc--inliner--4489, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type clojure.lang.ArityException\n :message "Wrong numb...

13:50 amalloy: well, apparently inc is smarter now

13:50 ,(defmacro foo [] (seq 1 2 3 4))

13:50 clojurebot: #'sandbox/foo

13:50 amalloy: ,(foo)

13:50 clojurebot: #error {\n :cause "Wrong number of args (2) passed to: core/seq--4357"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (2) passed to: core/seq--4357"\n :at [clojure.lang.Compiler macroexpand1 "Compiler.java" 6781]}]\n :trace\n [[clojure.lang.Compiler macroexpand1 "Compiler.java" 6781]\n [clojure.lang.Compiler macroexpand "Compiler.java" 6837]\n [clojure.lang.Com...

13:50 justin_smith: haha

13:50 amalloy: ,(defmacro foo [] (seq))

13:50 clojurebot: #'sandbox/foo

13:50 amalloy: ,(foo)

13:50 clojurebot: #error {\n :cause "Wrong number of args (-2) passed to: core/seq--4357"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (-2) passed to: core/seq--4357"\n :at [clojure.lang.Compiler macroexpand1 "Compiler.java" 6781]}]\n :trace\n [[clojure.lang.Compiler macroexpand1 "Compiler.java" 6781]\n [clojure.lang.Compiler macroexpand "Compiler.java" 6837]\n [clojure.lang.C...

13:52 gfredericks: I got to write a function called random-psuedofactoring: https://www.refheap.com/115236

13:53 cfleming: {blake} TEttinger3: Sorry for the problems. I haven't had time to reproduce with that project.clj yet, but generally you have to add the deps to the project.clj, and then use the Refresh Leiningen Projects action, which you can either search for or use the lein toolwindow.

13:54 amalloy: gfredericks: returns, not generates? that makes it sound to me like it just keeps one collection lying around forever, and always gives that one

13:54 {blake}: cfleming: I did not know there was a lein toolwindow! Cool!

13:54 gfredericks: amalloy: well it's in the context of test.check generators, so hopefully that means the more natural interpretation is that it doesn't return a generator

13:54 but that there might be a better wording

13:55 I think a lot of docstrings for functions that return generators just say "Generates ..."

13:55 amalloy: it seems like this could be a generator if you wanted it to, right? am i wrong, or is there a reason not to do that?

13:56 gfredericks: amalloy: yeah it could be one that's just not what I needed it for

13:57 sdegutis: im back

13:57 amalloy: i understand you owe me a link to something so i can downvote it, sdegutis

13:57 sdegutis: amalloy: oh yeah hold on

13:57 amalloy: https://gist.github.com/sdegutis/62f0b4177f01cf331218

13:58 amalloy: its not yet turned into a mailing list discussion but justin_smith had toyed around with the idea of extracting the metadata-generating code from defn and turning it into a stand-alone function (which defn then uses) so it can be used independently similar to how 'destructure' works

13:58 amalloy: anyway please downvote my gist

13:59 amalloy: oh. you mean like clojure.tools.macro.name)with-attributes?

13:59 sdegutis: amalloy: justin_smith /cc

13:59 amalloy: not quite, cuz fn+ here generates :arglists for you

14:00 amalloy: that was the main reason i invented fn+ today

14:01 amalloy: well, it's a cute trick anyway

14:02 sdegutis: thanks!

14:02 amalloy: github doesn't have downvotes, so i forked and deleted it

14:02 sdegutis: amalloy: haha or yu could comment with -1

14:02 :-1: technically

14:03 wow u wasnt kiddin https://gist.github.com/amalloy/05b64a9418fd318b7916/revisions

14:04 amalloy: actually your revision should just contain `(meta (fn [x] (inc x)))` so its made clear that your fork results in less functionality than the thing you forked

14:04 :D

14:06 justin_smith: amalloy: my thought was that it would be nice to be able to generate the same metadata properties that defn would, or that def would, without having to call def/defn, so the specific metadata generation could be refactored into a function - name-with-attributes is nice but doesn't do all the metadata defn does, and would need to be manually updated for each change to core's defn

14:08 sdegutis: justin_smith: what would such an api look like in action?

14:09 justin_smith: (let [f (fn [])] (generate-metadata f)) ?

14:09 justin_smith: or (generate-metadata (fn [])) ?

14:11 justin_smith: sdegutis: maybe something like (defmacro fn+ [& body] `(with-meta (fn ~@body) ~(gen-meta body)))

14:11 sdegutis: but I realized the annoying thing about making a function that defn would use to generate its macro - you can't use defn to define that helper :)

14:13 amalloy: or syntax-quote

14:13 justin_smith: amalloy: oh yes, of course

14:14 that would also be an annoyance

14:16 {blake}: I have a vector of vectors I'm using to make my web-page, and now (using React) I have to update a value in that vector of vectors.

14:17 [[{stuff}{stuff}{stuff :control {:cell-name "target" :value "changethis"}}][next row...]]

14:18 justin_smith: {blake}: are you using react directly or with some clojurescript wrapper?

14:18 {blake}: justin_smith: reagent

14:18 amalloy: don't use vectors to store stuff you want to look up indexed by some key

14:18 justin_smith: {blake}: don't change the vector, use a function call to generate the vector

14:18 {blake}: amalloy: Well, I didn't know I was going to have to.

14:18 amalloy: instead of searching through a bunch of vectors, wouldn't it be lovely to have a map? {"target" ...}

14:19 justin_smith: amalloy: this is hiccup

14:19 so generate the hiccup, instead of using a literal

14:19 amalloy: if it were hiccup you would have a seq of vectors, perhaps. never a vector of vectors

14:19 justin_smith: {blake}: or do you mean some source data? if so, yeah do what amalloy says

14:19 {blake}: OK, so, yeah, I've thought of "change it to a map" and "regenerate the vector". Just seems like a lot of work.

14:20 justin_smith: {blake}: less work than arbitrary updates in a vector I'd think

14:21 {blake}: So, the deal is, my server sends me data that I used to make an entry page for the user, including pre-populating some of those values.

14:21 (At the user's request.)

14:21 I'd been putting those in "defaultValue".

14:21 Only to discover that reagent only uses defaultValue first time out.

14:21 When the component is first rendered. So I put it in value.

14:22 But if I put it in value, all my components gotta be "controlled".

14:22 And to make them "controlled", I gotta be able to update that structure the server sends.

14:22 So.

14:22 Crap.

14:24 justin_smith: {blake}: send the data from the server in a form you can easily access, and generate the structure you need on the frontend from that

14:25 so yeah, a map instead of vector, like amalloy said

14:25 {blake}: Or...

14:25 Maybe send two structures. Since the only thing that's going to change is a small subset of controls->values, keep one for the structure of the whole page, and a little part for the react stuff.

14:26 justin_smith: but it's easier to generate the right vector from a map than it is to update a vector correctly

14:26 if you need a vector, make it out of maps

14:28 rhg135: Juxt is useful for that

14:28 justin_smith: indeed!

14:31 gfredericks: ~juxt

14:31 clojurebot: juxt is usually the right answer

14:31 gfredericks: ~juxt

14:31 clojurebot: juxt is a little hard to grok but it's the best thing ever

14:31 gfredericks: ~juxt

14:31 clojurebot: juxt is usually the right answer

14:32 {blake}: Lotta juxt propaganda goin' on.

14:32 tcrayford_____: juxt shut up already

14:34 {blake}: I have a nice thing on the server where it's going through the cells of the spreadsheet and creating a vector.

14:35 A vector of vectors. Rows and columns. Then I just go through this on the client side, same way.

14:35 I guess I could key it as [col row] and make a flat map.

14:35 sdegutis: just and comp are cool

14:36 just don't expect them to notice rebound vars unless you explicitly pass vars

14:36 (comp foo/bar foo/quux) ;; redefine #'foo/bar or #'foo/quux and it will never notice

14:36 (comp #'foo/bar #'foo/quux) ;; this will though

14:36 This works because you can call vars as functions if you try hard enough.

15:04 Hello.

15:04 What's your recommended way of sharing many common immutable parameters between a group of functions?

15:05 The way I'm currently using is to have each of them take a map as its first parameter with each of these values at common keys.

15:50 rhg135: But then you can't compose them elegantly, I guess it's not as bad

16:25 justin_smith: clearly what we need is some crazy hack using metadata to imitate monads

16:25 (that was in response to rhg135 but it's universally true as well, of course)

16:56 {blake}: Who doesn't love crazy hacks?

16:56 justin_smith: in fact I sometimes suspect I *am* a crazy hack

16:58 amalloy: isn't using metadata to imitate monads like using...noodle soup to imitate 4chan? they are just totally disjoint separate things

16:59 CaptainLex_: Well that's what makes the hack /crazy/

17:00 justin_smith: amalloy: in the sense that a monad can track a separate immutable value implicitly carried forward in each call, which could hackily be a metadata passed along on values

17:00 or maybe I'm just talking nonsense again

17:15 rhg135: justin_smith: I just pass everything in one mega map, maybe a magic monad is better

17:21 gfredericks: oh man; I have a memory perf test in test.check that runs fine on the jvm but blows the stack (?) in cljs

17:21 #object[RangeError RangeError: Maximum call stack size exceeded]

17:22 I guess either nodejs has a smaller default stack than the jvm or cljs uses more stack frames than clj or both?

17:27 CaptainLex_: gfredericks: The former wouldn't surprise me one bit

17:28 gfredericks: this shouldn't even be a particularly stacky usage :/

17:28 still trying to get a proper stack trace

17:30 the internet says that e.stack is something useful but for me it's undefined :/

17:30 so I'm not sure how to figure out what's so stacky about this

18:04 rhg135: that would be the reader monad now that I think it

18:45 srruby: I want to do something like: lein ring server -env=testing To indicate that the server is running in a testing environment. Thanks, John

18:46 CaptainLex_: srruby: I don't know about any special ring stuff, but can't you just pass environment variables to the JVM like normal?

18:46 Which I don't have any real experience with either

18:53 srruby: CaptainLex_ : I guess I'll use (export FOO=bar; lein ring server)

18:54 CaptainLex_: Or you could ($FOO=bar lein ring server) if you didn't want to mess with your normal environment

18:54 Or you could even write a shell script to launch lein with the variables set according to arguments, if the syntax annoyed you

19:17 srruby: How can I change a string into a "reader" object ?

19:19 CaptainLex_: srruby: What are you trying to do?

19:20 srruby: CaptainLex: I have some code that reads from a file and processes the data. I want to test the code with a string.

19:21 amalloy: with-in-str

19:21 srruby: Something like new Reader(new stringBuffer("test data")

19:21 amalloy: Thanks

19:25 O

19:44 OK. This is what I came up with.

19:44 (defn reader-from-string[s]

19:44 (new java.io.BufferedReader (new java.io.InputStreamReader (new java.io.ByteArrayInputStream (.getBytes s)))))

19:44 (slurp (reader-from-string "a,b,c,d"))

19:45 seems clumsy

19:46 rhg135: StringReader exists

19:50 srruby: OK. This works. (with-in-str "hello" (parse-data (clojure.java.io/reader *in*)))

19:50 That is what I was looking for.

19:53 (parse-data (new java.io.StringReader "a,b,c,d")))

19:54 rhg135: Thanks. (new java.io.StringReader "foo") was what I was looking for.

19:54 rhg135: np

19:55 amalloy: was there something wrong with (with-in-str "a,b,c,d" (parse-data *in*))?

19:56 rhg135: ,(class *in*)

19:56 clojurebot: clojure.lang.LineNumberingPushbackReader

19:56 rhg135: oh

19:57 amalloy: ,(with-in-str "a,b,c,d" (class *in*))

19:57 clojurebot: clojure.lang.LineNumberingPushbackReader

19:58 rhg135: I assumed it'd be a inputstream given his code

20:01 amalloy: ,(class System/in)

20:01 clojurebot: java.io.BufferedInputStream

20:01 rhg135: hmm

20:45 n0n3such: hey

22:22 hodwik: Are LISPs hard to read because I'm not used to them, or are they just harder to read?

22:23 tolstoy: I find them easier to read, but I suspect Clojure's use of brackets, and syntax highlighting improve that significantly.

22:25 hodwik: I guess I find it easier to get a sense of what the code is doing at a fine-grained level

22:25 but I'm having a hard time stepping back and seeing the big picture

22:25 because all of the pieces are so low-level logically

22:26 tolstoy: Coming from Java?

22:26 hodwik: Python & Java

22:28 tolstoy: A friend just went through a similar thing. For him, realizing that the functions were verbs seems to have helped a lot (his words not mine).

22:30 hodwik: Hmm, I'm not sure I follow.

22:31 tolstoy: Clojure functions, generally, take data as parameters and transform it into another form of data.

22:31 So, map, reduce, filter, etc.

22:31 So, just read the function names and get a sense of what they're doing.

22:33 hodwik: I've gotten that far

22:33 I'm just not sure how to skim code, so to speak

22:33 to get the big ideas

22:33 Everything looks equally important, in a way

22:34 TEttinger: ah, yeah. an interesting thing is that what would be a few lines in java, with a for loop for instance, is typically a one-line call in clojure to a collection-based fn

22:35 hodwik: So then maybe skimming code is not the right strategy to read code in clojure?

22:35 TEttinger: like map vs. creating a new ArrayList and appending to it in a for(Thing thing : myList) {} way

22:35 tolstoy: That's what I do.

22:35 TEttinger: clojure code tends to be slightly wider and much less vertically stretched

22:35 tolstoy: But I skim by first reading the names and then maybe glancing at the function body to see if there's filter, reduce, map, or something.

22:36 TEttinger: yeah, similar here

22:36 tolstoy: Like this: https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/middleware/params.clj

22:36 I start at the bottom and go up.

22:37 hodwik: Interesting, why read from the bottom?

22:37 tolstoy: That's usually where the "main" function is, with all the ones above it in support position.

22:38 TEttinger: it is a big benefit to know if you're dealing with a many-to-many fn (map and mapcat are commonly used like this, filter usually), a many-to-one (usually reduce, not always), a one-to-many (iterate, certain uses of loop, for can be used something like this), etc.

22:38 tolstoy: Then I quickly scan up and see, assoc-query-params, where I can see he's parsing the querystring from the request (:query-string this or that).

22:39 I can see that he's parsing the query string into a key/value and associating it to the request as two keys. The rest the functions: *shrug*.

22:40 Keywords are pretty nice because you can kinda trace the transformation of data by scanning for them.

22:40 hodwik: Oh, that

22:41 's an interesting strategy.

22:41 tolstoy: I didn't know I had that strategy until looking at that code. ;)

22:44 hodwik: Do you find yourself using other people

22:44 's code/libs less when writing in Clojure?

22:45 tolstoy: Sort of.

22:45 For me, the biggest difference between Clojure and your avg Java/Python/C# approaches is the separation of data from functions.

22:46 For instance, with that "ring" web stuff, you realize that it's just a wide variety of functions that take a "request" map and produce a "response" map (mainly).

22:47 Once you get that, you can skim the code if, say, you wonder how it handles cookies, or query strings, or a response with a body of type "stream".

22:47 So, the "big idea" you mentioned is getting that main idea, the request map.

22:49 And given that the vast bulk of Clojure code is just maps and lists, you don't need to look for type names (like domain objects).

22:50 So, you don't look for things like User, but, instead, for functions that seem to operate on users, like, (auth? user) or (valid? db-conn email password) and so on.

22:50 So, yeah, from the point of view of OO, it can seem like undifferentiated soup. ;)

22:53 hodwik: So with Python and Java, I find Python much more expressive. However, I also find it much more difficult to read my code 6 months later than with Java. As if, all that boilerplate just acts as a visual cue.

22:53 My concern is that Clojure is going to go farther in that direction.

22:54 I take it that you do not experience that relationship between expressiveness and readibility, if you find clojure to be more readable?

22:56 tolstoy: Clojure's the first language where, when I didn't understand a docstring, I clicked the "show source" link and that actually helped.

22:57 I do find it more readable, I think, because everything's in one place. With Java, I have to use Intellij so I can bop around because any given thing seems to involve dozens of objects.

23:02 hodwik: I was thinking it'd be pretty cool to have syntax highlighting that does every pair of parens a different color. Does such a thing exist?

23:03 tolstoy: rainbox delimiters

23:03 rainbow, sorry.

23:03 hodwik: Awesome. Is it useful/popular?

23:04 tolstoy: I think it's reasonably popular. What's your editor?

23:05 hodwik: Well, I've got Emacs setup, but I wouldn't call it my editor, but that's where I'm working on Clojure right now.

23:06 tolstoy: https://github.com/Fanael/rainbow-delimiters

23:06 Alas, no pictures on that page.

23:07 hodwik: Thanks

23:07 I'm checking out some screenshots, it looks a bit more distracting than I thought it would

23:08 tolstoy: I find it so.

23:08 amalloy: hodwik: ideally you should be paying attention to the indentation, not the parens

23:08 hodwik: Is focusing on the parens the wrong way to go about it. That is, do you read the "verbs" more than the parens?

23:08 tolstoy: Yeah, I dim my parens, actually.

23:08 And use paredit to manage them.

23:08 amalloy: parens are for the computer

23:09 tolstoy: Anyone happen to know how to query specific network adapters via command line on windows?

23:09 hodwik: Ah, I think stanislav datskovskiy told me that

23:09 I had forgotten

23:24 macrolicious: I'm getting a FileNotFoundException: Could not locate seesaw/core__init.class or seesaw/core.clj on classpath in spite of having :dependencies [[org.clojure/clojure "1.5.1"]

23:25 hiredman: seesaw is not part of clojure

23:25 so saying you depend on clojure doesn't mean you get seesaw

23:51 totalnes`: hiredman: oops, I meant to say I had: :dependencies [[org.clojure/clojure "1.5.1"] [seesaw "1.4.4"]])

23:51 last line didn't paste

23:51 in my src directory I have seesaw.

23:58 hiredman: totalnes`: what do you mean by "in my src directory I have seesaw." ?

23:59 in the interest of short circuiting this, you likely added the dep to project.clj and didn't restart your repl

Logging service provided by n01se.net