Fork me on GitHub
#clojure
<
2017-02-21
>
damionjunk00:02:07

Is there a way to generally control the number of threads that could possibly be created by calls to (future) etc? I'm running into some OOME's, unable to create new native thread, and the machine I'm stuck running on has a hard ulimit for the number of user processes.

gfredericks00:02:46

@damionjunk I've never tried this but it looks like you could (set! clojure.lang.Agent/soloExecutor ...)

gfredericks00:02:58

or whatever is the correct syntax for setting a static field

damionjunk00:02:12

Ah yes.. I just found these functions:

damionjunk00:02:16

(set-agent-send-off-executor!
    (java.util.concurrent.Executors/newFixedThreadPool 5))

damionjunk00:02:02

Seems to be getting the job done!

gfredericks00:02:20

oh hey look at that

damionjunk00:02:42

(defn set-agent-send-off-executor!
  "Sets the ExecutorService to be used by send-off"
  {:added "1.5"}
  [executor]
  (set! clojure.lang.Agent/soloExecutor executor))

gfredericks00:02:46

clojure.core: there's always something else you didn't know was there

damionjunk00:02:33

Totally! I remember stumbling across as-> and being like WAT!

sophiago00:02:04

can anyone explain the behavior of this to me: (clojure.walk/postwalk #(if (vector? %) (println %)) {0 [1 2 3], 1 [4 5 6], 2 [7 8 9]})? the contents of the vectors are printed as nil and additionally there are three extra vectors containing two nil elements i'm not sure why are there...

gfredericks00:02:51

nil is the return value of println

gfredericks00:02:13

and the extra vectors are probably map entries

gfredericks00:02:33

the fact that a map entry is a vector is also relevant here

sophiago00:02:39

on the latter issues, i believe i tried testing (not (map-entry? %))

sophiago00:02:12

yeah, i get the exact same output if i try: (clojure.walk/postwalk #(doall (if (and (not (map-entry? %)) (vector? %)) (println %))) {0 [1 2 3], 1 [4 5 6], 2 [7 8 9]})

damionjunk00:02:42

(clojure.walk/postwalk #(if (vector? %) % (type %)) {0 [1 2 3], 1 [4 5 6], 2 [7 8 9]}) <- a clue

gfredericks00:02:56

@sophiago and that is (I believe) because the intermediate representation of map entries in the context of postwalk is a vector that's not a map entry, just for extra confusion

gfredericks00:02:54

a two-element vector can pretend to be a map entry sometimes

sophiago00:02:19

@gfredericks huh. i tried prewalk as well, but it wasn't outputing anything. how would you recommend getting just the values that are vectors?

gfredericks00:02:54

if you want a list of vectors at every level I'd use tree-seq

gfredericks00:02:12

(->> coll (tree-seq coll? seq) (filter vector?))

sophiago00:02:28

oh, interesting. the actual implementation is to filter for only vectors of nested vectors (i.e. (vector? (first %))) and call swap to mutate them. not sure if i could use tree-seq like that

gfredericks00:02:22

call swap on a vector...?

sophiago00:02:31

on an atomic hash-map

sophiago00:02:48

where all the values are vectors of vectors

gfredericks00:02:32

is the atomic hash-map your top-level collection or are there lots of them sprinkled around something else?

sophiago00:02:37

the map is highly nested

gfredericks00:02:51

but there's just one of them?

sophiago00:02:59

yes. and only atomic on the top-level

gfredericks00:02:12

okay so you can find that with tree-seq

gfredericks00:02:27

(->> coll (tree-seq coll? seq) (filter atomic-hash-map?) first)

gfredericks00:02:40

or just pull it out directly if you know the path to it

gfredericks00:02:56

and then treat it like a mutable data structure instead of trying to do functional things with it

gfredericks00:02:38

what's an atomic hash-map?

gfredericks00:02:49

an atom with a map in it?

gfredericks00:02:26

okay, I got confused because I thought you were talking about ConcurrentHashMap

sophiago00:02:38

oh no. i didn't know that existed...

gfredericks01:02:18

in either case, because you have that stateful part you can't do it all as a functional algorithm, you have to transition between the two worlds

gfredericks01:02:17

postwalk, prewalk, and tree-seq are functional things, so they can only get you halfway there

sophiago01:02:22

i don't see how that's the issue. it's easy to mutate parts of an atom using swap. for example, how i was trying to do this with postwalk: (defn map-map [m f] (swap! m (partial clojure.walk/postwalk (fn [value] (if (and (not (map-entry? value)) (vector? (first value))) (f value) value)))))

sophiago01:02:00

the only issue with that is it doesn't seem to be possible to filter postwalk for solely values that are vectors

gfredericks01:02:09

you just want to call f on each element at the second level down in the vector of vectors?

gfredericks01:02:26

if so I'd just call mapv in a nested way rather than using postwalk

gfredericks01:02:10

post/pre-walk and tree-seq really fit best with recursive data structures

sophiago01:02:10

mapv on a hash-map?

gfredericks01:02:28

Oh forgot about the map; map-vals + mapv + mapv then

sophiago01:02:02

map-vals? i wasn't aware that existed

gfredericks01:02:12

Where map-vals is the function that's been defined in a million utility libraries but never in clojure.core

gfredericks01:02:31

It's a one liner

sophiago01:02:00

yeah, that's what i'm looking for here

sophiago01:02:11

i'll do some research

gfredericks01:02:51

(defn map-vals [f m] (into {} (for [[k v] m] [k (f v)])))

sophiago01:02:10

yup. that's the one i found from algo.generic

sophiago01:02:58

this is not quite right: (defn map-map [m f] (swap! m (for [[k v] m :when (vector? (first v))] [k (f v)])))

sophiago01:02:13

i need something like partial with the list comprehension

gfredericks01:02:42

you're not passing a function to swap! is one problem

gfredericks01:02:04

I was imagining you'd call (swap! m (partial map-vals (fn [vv] (mapv #(mapv f %) vv))))

gfredericks01:02:15

but it depends on what level f is supposed to operate at

sophiago01:02:10

this works, except not on nested maps: (defn map-map [m f] (swap! m #(for [[k v] % :when (vector? (first v))] [k (f v)])))

sophiago01:02:25

that's why i was trying to use postwalk

sophiago01:02:33

these are nonessential functions for this library...might be time to put them aside if there's no elegant solution

sophiago01:02:34

@gfredericks thanks for your help anyway! infinitely nested fmap doesn't seem possible, but it was really helpful to have clojure.walk explained a bit

joshjones02:02:43

sophiago: sorry if i missed important details, but basically you're trying to recursively apply a function to a map, but only if the first element of the value is a vector?

sophiago02:02:27

Yup. That's p much it. Although it's the least important part of what I'm finishing up now so I've pretty much decided to ditch those functions unless you have a flash of insight. I suppose I would like to know for the future, anyway.

joshjones02:02:47

doesn't this do what you want?

(defn fmap
  [f m]
  (into {} (for [[k v] m
                 :when (vector? (first v))]
             [k (f v)])))

(defn fmap-recursive
  [f m]
  (fmap #(if (map? %)
           (fmap-recursive f %)
           (f %))
        m))

joshjones02:02:03

call fmap-recursive with your function and data

sophiago02:02:19

Oh, that might. Lemme give it a shot

joshjones02:02:15

it's not TCO so it will blow the stack if you have a super large input, but i think it does what you want. i'm assuming here that if the first element is not a vector, that you don't even want to include it in the result (at least that's how you wrote your version that you said works)

sophiago02:02:30

that's not an issue, but they are atoms that need to be mutated

joshjones02:02:33

specifically, what is "they" ?

sophiago02:02:25

you know i appreciate the help, but i've already decided to nix these functions and am short on time with this

sudodoki07:02:19

question did anyone have experience with setting up drift with reagent-template folder structure / project.clj? Have some issues with generated migrations namespace, would appreciate hints/pointers in how to debug / fix the issue. https://gist.github.com/sudodoki/98b422931a79301ed0f543df29306fb7

negaduck10:02:41

hello. I have a function that just inserts averages between values of a list. It’s pretty simple, but rewritten in python with just going through indices looks much simpler. Is there a way to rewrite this function in clojure to make it a bit more readable?

;; insert-beats-between-beats [0 1 2 3 4 5])   => [0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5]
(defn insert-beats-between-beats [coll]
 (let [average #(/ (+ %1 %2) 2)]
       (loop [[x & xs] coll
              result []]
        (if (nil? x)
         result
         (recur xs (apply conj result
                    (if xs
                     [x (average x (first xs))]
                     [x])))))))

larhat10:02:14

@negaduck it’s usually better to use pre-made recursion schemes, like reduce than write your own recur: (reduce (fn [acc [a b]] (concat acc [a (/ (+ a b) 2) b])) [] (partition 2 1 inp)) or, with bindings:

(defn insert-beats-between-beats [coll]
   (let [average #(/ (+ %1 %2) 2)
         pairs (partition 2 1 coll)
         reduce-step (fn [acc [a b]] (concat acc [a (average a b) b]))]
      (reduce reduce-step [] pairs)))

negaduck10:02:21

@larhat, I like the partition part, thank you

residentsummer10:02:25

(interleave coll (map #(/ (+ %1 %2) 2) coll (drop 1 coll)))
edit: sorry, it’s wrong - loses the last element of a coll

seantempesta10:02:08

Okay. I’m tired of feeling dumb. If you were trying to recreate these lines of java in clojure, what would they be?

import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;

private PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
phoneUtil.format(number, PhoneNumberFormat.INTERNATIONAL)

benh10:02:28

(.format (PhoneNumberUtil/getInstance) number PhoneNUmberFormat.INTERNATIONAL)

seantempesta10:02:43

I can’t even get the packages to import.

mrchance10:02:21

(ns foo
 (:import com.google.i18n.phonenumbers.PhoneNumberUtil
                 com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat))
should work...?

mrchance10:02:07

Ah, not if it's a nested class, might have to put a $ in there for the second line

seantempesta10:02:40

The INTERNATIONAL part is an enum, which means it get’s turned into a class?

mrchance10:02:26

I would expect it to be PhoneNumberFormat/INTERNATIONAL in the example above

mrchance10:02:40

not .INTERNATIONAL

benh10:02:53

yeah my bad

seantempesta10:02:25

CompilerException java.lang.RuntimeException: No such namespace: PhoneNumberFormat, compiling:(/tmp/form-init562821416926576309.clj:1:1)

mrchance10:02:30

@seantempesta maybe you wrote (import ...) instead of (:import ...) ?

residentsummer10:02:45

@mrchance no, it should be keyword version inside the ns form

mrchance10:02:12

yes, I was suggesting that he might have gotten it wrong, might have been badly worded πŸ˜‰

seantempesta10:02:24

(ns kidlink.specs
  (:import (com.google.i18n.phonenumbers PhoneNumberUtil)
           (com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat)))

(.format (PhoneNumberUtil/getInstance) "" PhoneNumberFormat/INTERNATIONAL)

borkdude11:02:00

Is :foo.bar/baza valid keyword or should we expect problems when we start using them this way?

mrchance11:02:02

well, like I said, if the NumberFormat is a nested class, you need ...Util$PhoneNumberFormat

borkdude11:02:06

According to this spec keywords should not contain dots: https://clojure.org/reference/reader

borkdude11:02:35

But namespaced keywords usually contain dots in the namespace part

seantempesta11:02:38

Sorry, I’m still not getting it. (.format (PhoneNumberUtil/getInstance) "" PhoneNumberUtil$PhoneNumberFormat/INTERNATIONAL) also gives an No such namespace: PhoneNumberUtil$PhoneNumberFormat error.

borkdude11:02:52

So the spec seems to be a bit ambiguous there?

mrchance11:02:57

@seantempesta You have to change the import line too

mrchance11:02:41

@borkdude No, I think they mean the non-namespace part of the keyword can't contain dots

borkdude11:02:04

I think that is what they mean too, but the spec could be clearer

mrchance11:02:05

::foo expands to :my.ns/foo, so that needs to be allowed

mrchance11:02:42

@seantempesta Maybe you are better off using https://github.com/vlobanov/libphonenumber altogether? πŸ˜‰

mrchance11:02:33

Unless the goal is to learn about interfacing with all the kinks and corners of Java πŸ˜‰

seantempesta11:02:42

Oh hell yeah. I’ve wasted 2 hours on this. I just didn’t think java interop could be that hard. But then again, I don’t really know java...

mrchance11:02:37

Yeah, it's a lot easier with well designed libraries, but several things like needing to implement an actual subclass, accessing nested classes and the need for singletons require some more acrobatics

seantempesta11:02:38

Well thanks for your help @mrchance and @benha.

mrchance11:02:54

Incidentally, this also shows the right way to do it, in case you are wondering πŸ˜‰

mrchance11:02:00

Sure, happy to!

maxxcan11:02:11

do anyone to use luminus + hoplon?

residentsummer11:02:47

@negaduck nailed it

(defn interleave-all [s & seqs]
  (lazy-seq
   (if-let [s (seq s)]
     (cons (first s) (apply interleave-all (concat seqs [(rest s)])))
     (when seqs (apply interleave-all seqs)))))

(let [average #(/ (+ %1 %2) 2)
      coll (range 5)]
  (interleave-all coll (map average coll (drop 1 coll))))

residentsummer11:02:22

btw, there is partition-all in core (regular version failed me once)

negaduck11:02:41

@residentsummer, thank you. Isn’t it easier to add the last element to the one liner above?

residentsummer11:02:13

well, it’s easier, but 1. looks suspicious 2. appending to an end is expensive for many collections (except for e.g. vectors)

residentsummer11:02:49

and 3. you can reuse interleave-all later… sometime… let it just hang on in (ns util…for a while πŸ˜„

negaduck11:02:23

if I had a blog, I would post interleave-all to make it searchable

rauh11:02:25

@negaduck Just gist it, I frequently search github+gists first when i look for a function. ( + )

negaduck11:02:50

TIL, multiple times

benh11:02:45

@negaduck how about

(rest (into []
            (fn [rf]
              (let [p (atom 0)]
                (fn
                  ([] [])
                  ([acc] acc)
                  ([acc v]
                   (let [p0 @p]
                     (reset! p v)
                     (rf acc (/ (+ p0 v) 2))
                     (rf acc v)
                     )))))
            (range 6)))
=> (0 1/2 1 3/2 2 5/2 3 7/2 4 9/2 5)

residentsummer11:02:31

wrap it in triple backticks

rauh12:02:02

@benha I like it, probably much faster, though I'd do it like this:

(defn compute-between
  [f]
  (fn [rf]
    (let [rf ((drop 1) rf)
          p (volatile! 0)]
      (completing
        (fn [acc v]
          (let [p0 @p]
            (vreset! p v)
            (rf (rf acc (f p0 v)) v)))))))

(into [] (compute-between #(/ %2 2)) (range 6))

rauh12:02:56

@benha Btw, you can't bash the rf into place. Your code is lucky to work since conj! on vectors works while bashing.

rauh12:02:29

Change it to (into () ...) and it'll fail.

benh12:02:23

@rauh bash? I don't understand...

benh12:02:46

ah silly me; You mean

(-> acc
     (rf (/ (+ p0 v) 2))
     (rf v))
instead of
(rf acc (/ (+ p0 v) 2))
(rf acc v)

benh12:02:36

I was wondering why it didn't work when plugged in to (sequence

benh12:02:31

(into uses a mutable form internally, which is why it appeared to work

qqq12:02:06

x = () OR x = (1 2 3) I want to pattern match x via core.match into either () or (h & rst) so I try:

(match [x]
  [()] :foo
  [(h & rst)] :bar
)
^^ apparently the above is wrong; how do I fix it?

joshjones12:02:28

@seantempesta you were likely having issues due to inner classes. java interop is very simple, just have to do it once or twice and it becomes very straightforward. first, you import. I searched google for the class you mentioned, found the maven info, and put that in dependencies in project.clj:

[com.googlecode.libphonenumber/libphonenumber β€œ8.3.0”]
Next, import the classes you need:
(ns your.namespace
  (:import [com.google.i18n.phonenumbers
            PhoneNumberUtil
            PhoneNumberUtil$PhoneNumberFormat
            Phonenumber$PhoneNumber]))
next, just use standard java interop:
(def number (.setNationalNumber (Phonenumber$PhoneNumber.) 5553331212))
(.format (PhoneNumberUtil/getInstance)
         number
         PhoneNumberUtil$PhoneNumberFormat/INTERNATIONAL)

rauh12:02:34

@qqq Easiest to just do (match (vec x) ...)

qqq12:02:43

rauh: this is inside a loop-recur, I don't want recreating the vec on every processing

danielgrosse13:02:38

Is someone with mathematic knowledge here?

qqq13:02:45

what type of math?

danielgrosse13:02:13

Circle calculation, radians and such stuff

rootkat13:02:05

what's the question?

leov13:02:23

which ring middleware should I use, so that my javascripts would not be cached by the browser (chrome)?

leov13:02:35

etag? wrap-not-modified?

qqq13:02:01

@danielgrosse : what's youre question?

joshjones13:02:29

confucius say, better to ask question and receive no answer, than to ask question about asking question, receive question about question, answer question about question, receive answer, then leave question unasked πŸ˜‰

seantempesta13:02:41

@joshjones I see. I'll give it a shot. Thanks for digging into it.

joshjones13:02:00

@seantempesta no worries mate β€” at first i hated java interop because i could not remember when a β€œdot” went in front, at the end, when to use slashes, etc., it’s frustrating when you just want to get the darn thing to work.

sakalli14:02:32

hi. any pointers here? trying ^^ to use clojure.inspector. am I perhaps doing som n00b mistake here, something i haven't installed for instance or what do you think?

kirill.salykin14:02:54

Hi Is it possible (and how) to use if-let inside -> macro?

moxaj14:02:11

@kirill.salykin you need to be more specific, but the answer is probably 'no'

kirill.salykin14:02:45

I was thinking about something like this: ` (-> params validate (if-let [user (find-user)] … ... )) but I guess there it is no way to pass args to find-user

larhat14:02:45

there is some->

larhat14:02:35

user=> (some-> {} :key println)
nil
user=> (some-> {:key "2"} :key println)
2
nil

kirill.salykin14:02:50

this might work

kalekale15:02:40

Hey, does anyone have experience with using the new ring async handlers with compojure?

joshjones15:02:22

@kirill.salykin While some-> is probably what you want there, it may be helpful to know that you can use common macros such as if-let, if, and in a threading macro chain, but you have to wrap it in a function first. for example:

(-> params
    validate
    (#(if-let [user (find-user %)]
        (...))))

gfredericks15:02:57

an embedded as-> can also do that sort of thing

marioaquino18:02:14

One of my teammates is looking for a utility that can be used in a testing context to stub specific function invocations (based on supplied parameters) and either conditionally dispatch to the original function or return a value appropriate to the testing scenario. I believe that Midje offers something close to this, but the need is for application in clojure.test tests. It feels to me like something that core.match could be part of, but I wanted to ask on this list in case a utility already exists that I'm unaware of.

hiredman18:02:38

where I used to work we had this macro with-var-roots, which pre-dated with-redefs, and had a lot of overlapping functionality

hiredman18:02:07

one feature that with-var-roots had that with-redefs did not is, you could do something like (with-var-roots [^{:o original} some-function (fn [& args] ...)] ...) and it would bind the original value of the some-function var to original in the scope of the value

hiredman18:02:39

you can do the same thing with with-redefs, (with-redefs [some-function (let [original some-function] (fn [& args] ...))] ...) but that is so verbose and it is such a common thing

jeff.terrell18:02:05

@marioaquino - stubadub removes some of the pain of using with-redefs and adds a couple small features. You'd have to add the conditional dispatch logic yourself, but that'd get you halfway there maybe: https://github.com/magnars/stubadub

tbaldridge18:02:56

@marioaquino another option is to not stub (or mock) functions. IMO this tests the wrong thing. Most of the time you don't really care if a function was called with certain args or not...you really care about side effects.

tbaldridge18:02:59

Think of it this way: if the function is pure, test the function or test the output of the calling function. If that doesn't allow you to test what you want to test, then you're trying to assert something about side-effects. In that case you should try to test the effect of the function.

tbaldridge18:02:37

So for example: write a record to the DB then assert that the record is there. Write a IMessageQueue protocol, then use that via your DI system of choice to replace the actual queue.

tbaldridge18:02:50

All this with-redefs stuff is a fantastic way to introduce some really hard to find bugs.

Alex Miller (Clojure team)19:02:41

cough breaks in multithreading cough

hiredman19:02:37

well, it depends on what you are doing

marioaquino19:02:47

Thanks for the feedback and recommendations, @hiredman, @jeff.terrell, and @tbaldridge!!

hiredman19:02:51

e.g. if you have a test that spins up some multithreaded system, and does stuff, and then tears down the multithread system, and wrap the whole thing in with-redefs, then everything will see the redefs, which may or may not be broken depending on your intent

tbaldridge19:02:29

I don't like systems that "may or may not be broken" πŸ˜›

hiredman19:02:37

you should definitely never use with-redefs outside of tests

hiredman19:02:06

everything may or may not be broken depending on your intent, so it is a bound I am comfortable with

tbaldridge19:02:21

I just hate the idea of taking a language like Clojure that's designed to handle concurrency, and then ruining it by introducing global mutability. IMO we should be building code that could work just as well if clojure.test ran tests in parallel.

jeff.terrell19:02:08

@tbaldridge - I agree in general about avoiding stubbing, but sometimes you only want to test up to a certain boundary. I was recently testing an implementation of an OAuth client, and I wanted to be sure it was sending the requests I expected using clj-http/get etc. I didn't want to actually make network requests during my tests. Seems like stubbing is the right approach there, no? I'm definitely open if there's a better wayβ€”that code was not fun to write. :-)

tbaldridge19:02:39

so in that respect anything that introduces global mutability is straight out for the code I write.

tbaldridge19:02:20

assuming the URL for your requests is a parameter to the function (as it should be) you could also pass in a HTTP client instance. Or use some sort of functional DI system, like Component, or Integrant.

tbaldridge19:02:36

Or just test the code that constructs the request. If you could have a test against (construct-request "user-name") => {:url ... :params ...}

tbaldridge19:02:30

That's really what you're trying to test, right? That a call to your business logic resulted in the proper construction of the request structure.

jeff.terrell19:02:57

Yeah, that's true. Good point. I kinda don't want to introduce an "http client" abstraction, but weighing that against the pain of stubbing, stubbing is probably worse. And separating request generation from request sending is even better. Thanks! Will be thinking about this...

hiredman19:02:54

I very much like component, and I am using it with new stuff, and haven't missed with-var-root or with-redefs too much

danboykis19:02:23

@jeff.terrell in addition to what @tbaldridge said, you can also check out mount: and use mount/start-with to swap an implementation: https://www.dotkam.com/2016/01/17/swapping-alternate-implementations-with-mount/ during testing.

donaldball19:02:10

I have written and revised a bunch of clojure projects by this point and without question, the ones that have been easiest to modify have been those using component.

tbaldridge19:02:49

@danboykis does that work with multithreading?

tbaldridge19:02:20

Nope! It stores the state in the global atom. How is this better than with-redefs?

danboykis19:02:02

@tbaldridge this question needs more context. can application states be used by multiple threads? absolutely. can you run tests in the exact same REPL you develop? most likely, depending on your app, no. but I prefer not to do that. And I actually like that I am forced to run tests within a different REPL (with a watcher for example): it is much cleaner.

hiredman19:02:00

mount makes me 😟

tbaldridge19:02:10

Mount is just like with-redefs with another layer of indirection. If one thread is starting/stopping the system it will mess with other threads trying to do the same.

sveri19:02:51

Fun fact, if you test your code multithreaded and it works, it does not mean it works all the time...

tbaldridge19:02:23

@sveri that's when I hook it up to test.check and run stuff randomly in parallel until I find what two tests conflict πŸ˜‰

tbaldridge19:02:01

In practice though if this sort of stuff isn't threadsafe it's going to blow up pretty quickly.

sveri19:02:06

I agree, usually it does that, oh man, when I look at my work and see how much code, that can be run multithreaded is actually never tested multithreaded...

danboykis19:02:24

@tbaldridge > Mount is just like with-redefs with another layer of indirection this is you opinion, not a fact. I created at least 3 large apps + several small ones with Mount for the last year and a half. All of them are highly concurrent. I tested them without problems, some with lein, some with boot (i.e. in a different REPL: boot watch speak test). I used Component before that. It's a framework: "it calls me", I don't like that in Clojure, which is also an opinion.

tbaldridge19:02:48

@danboykis no, it's not my opinion, it's a fact. Mount stores its state in a private global atom. A call to mount state does a (:state @global-atom). with-redefs is exactly the same. All vars are stored in a global atom, when you with-redef a var you mutate the root of the atom that is inside the global atom (the Namespace).

hiredman19:02:56

are you trying to say mount doesn't call you?

tbaldridge19:02:26

I didn't make a judgement call on Mount. I said with-redefs mutates global data, which I find sub-par. And I stated that Mount does the same thing.

bja20:02:44

@tbaldridge does this stance on global state extend to the implementation of MultiFn too?

bja20:02:17

asking because I seem to remember doing some nasty reflecting to be able to clone MultiFns for the purposes of testing

tbaldridge20:02:25

@bja what was the cloning for?

thheller20:02:16

can someone recommend a good (and simple) screen recording software for mac?

rootkat20:02:49

I've been super happy with that one

zylox20:02:17

ive used OBS but its way overtooled for simple screen recording

tbaldridge20:02:24

@thheller use Quicktime. Go to File->New Screen Recording. Nice thing is, it comes with OSX

mobileink21:02:44

rgdelato: i'll add a plug for screenflow. amazing caps. not free, but at $99 pretty close.

thheller21:02:15

@tbaldridge wow that was indeed simple, thanks πŸ™‚

thheller21:02:51

the others look nice too but overkill for now

josh_tackett21:02:58

anyone know the best way to merge vectors and preserver order?

byron-woodfork21:02:39

Have an example of what you're trying to get to?

ejelome21:02:15

hello, any good suggestion how to deal with defs re-used on different namespaces, e.g. same db connection for source code and test code?

josh_tackett21:02:47

@ejelome ya make them ENV vars

jr21:02:05

delay the db connection and swap your config for test env

ejelome21:02:56

josh_tackett: hey, thanks, this is exactly what I'm looking for :thumbsup:

ejelome21:02:36

interesting

ejelome21:02:32

thanks @josh_tackett and @jr, will look into these, esp. the envs πŸ™‚

joshjones22:02:51

@josh_tackett "merge vectors" .... given [1 2 3] and [4 5 6], what does a merge look like?

rgdelato22:02:23

is there any way within a REPL to get the documentation for a reader macro? For example, I can (doc ->>), but not (doc ^)

Alex Miller (Clojure team)22:02:25

there is some special support for special forms, but nothing like that for reader macros

Alex Miller (Clojure team)22:02:42

doing that would be hard as the reader interprets them before you could invoke doc on it

arrdem22:02:36

Grimoire has support for looking up reader syntax πŸ˜›

arrdem22:02:52

But it just kicks you over to the right heading on http://clojure.org/reference/reader

rgdelato22:02:16

okay, thank you πŸ˜„

genec22:02:27

Does anyone have a suggestion for a clojure probability distribution library? Something similar to numpy or http://math.net would be great. I need to sample poisson, lognormal, etc distributions.

qqq22:02:35

@genec: there's hy + https://github.com/tobgu/pyrsistent if you want to stick with numpy

genec22:02:46

@qqq @donaldball @alexmiller Thanks very much for the links. I've played around with incanter, haven't heard of watershed - but it looks like it's just what I need. Not sure I understand how to use pyrsistent from clojure though.