Fork me on GitHub
#clojure
<
2016-08-31
>
didibus01:08:46

Question: What's the best way in Clojure to make a namespace use configurable. Mostly, I have a function that acquires a java object, and I'd like to be able to like override that function, but from another namespace. Should I put the function in an Atom, or can I just re-def the function from the other namespace?

bcbradley01:08:59

Does anyone here use light table? I'm having issues with the instarepl

bcbradley01:08:32

I created a default play-clj project on the command line using lein new play-clj hello-world

bcbradley01:08:49

then brought that into light table

bcbradley01:08:23

but my instarepl doesn't recognize the namesplaces of the project

bcbradley01:08:36

for instance, it doesn't recognize hello-world.core.desktop-launcher

gfredericks01:08:36

@didibus: the clean way to do it is to just pass everything in as arguments; the semidirty way to do it is with a dynamic var

didibus01:08:22

@gfredericks Ya, I think a dynamic var in my case might be better. But I'm experimenting with using (intern). My use case doesn't need many different override, just a single universal one.

gfredericks01:08:17

what would you do with intern?

didibus01:08:46

I have a (get-java-object_ function in the namespace, which other functions in the namespace use to get that particular java object. So I'm thinking I could call (intern 'ns 'get-java-object (fn [] "alternate getter"))

didibus01:08:11

To actually re-def the function itself

didibus01:08:19

to a different implementation

gfredericks01:08:46

alter-var-root is a more straightforward way to change a var's value

gfredericks01:08:05

but that's a global change, so that can be weird if your program is multithreaded

gfredericks01:08:16

thus dynamic vars

didibus01:08:37

Hum, what would the threads have issue with? In my use case, I need it to be global, like I won't want different caller to each have their own different getter. So I need to override it for the whole application

gfredericks01:08:01

okay, I'd use alter-var-root then

gfredericks01:08:34

you could also set the var to the object directly instead of a function that returns it

didibus01:08:38

That's true, but its some weird java object that does a bunch of side effect which fail on build, so if I have it as a var directly, it tries to instantiate the java object at build time and fails my build, because the object is looking for a config file

gfredericks01:08:52

gotdang java objects

didibus02:08:26

Never liked them, never will, hehe

amacdougall02:08:31

Huh. clojure.string/join is [separator coll], but clojure.string/split is [string pattern].

amacdougall02:08:00

Reminds me of constantly looking up the argument order of similar PHP functions.

gfredericks02:08:13

collections are often the last arg

hiredman02:08:58

having written clojure since before the clojure.string namespace existed, I conveniently avoid this problem by using the .split method on String, and interpose and apply str instead of the functions from clojure.string

akiroz04:08:09

When using the ring wrap-reload middleware, it is possible to get notified when a reload occurs?

seancorfield05:08:33

@amacdougall clojure.string/join is [coll] or [separator coll], which is why @gfredericks said collections usually come last... whereas clojure.string/split is a function on a string (with a regex and an optional limit as additional arguments). It's more consistent than you might initially think.

slipset06:08:13

@seancorfield one could argue that a string is a collection of chars...

Alex Miller (Clojure team)07:08:02

@amacdougall if you read the clojure.string docstring you’ll see that the string in most functions is treated as a collection and thus is the first argument. join is an intentional exception to that to be more amenable to use with partial

slipset07:08:15

@alexmiller: on a semi-irregular basis I start wondering about the order of arguments to functions in core, and I guess this is such a moment. Normally, I like to think that one passes the thing to be acted upon as the first argument, much like this often is an implicit first argument in OO languages, explicit in eg Perl. But map, filter, and reduce don’t follow this pattern. Is there any reason for this?

Alex Miller (Clojure team)07:08:53

functions that work on data structures take the data structure first (get, assoc, conj, merge, etc)

Alex Miller (Clojure team)07:08:04

and work well in chains of ->

Alex Miller (Clojure team)07:08:22

functions that work on sequences take the sequence last and work well with ->>

Alex Miller (Clojure team)07:08:52

map, filter, and reduce are sequence functions so take the sequence last

Alex Miller (Clojure team)07:08:34

with collections or other data structures the idea is that you invoking a function to act upon that structure so it comes first (like an object in Java)

Alex Miller (Clojure team)07:08:26

with sequences you are chaining lazy calls and building a nested pipeline so the sequence goes last

Alex Miller (Clojure team)07:08:10

clojure.string/join is a rare exception to these rules

Alex Miller (Clojure team)07:08:19

nth is kind of a weird case too as it works on both colls and seqs

slipset07:08:18

But, if I have a pipeline of things working on a datastructure and then on collections, something like (contrived) (-> {:foo :bar} (assoc :baz :qix) (group-by key)) (which doesn’t work, since group-by expects the sequence to go last), am I doing something I shouldn’t?

iku00088808:08:14

You can do (-> {:foo :bar} (assoc :baz :qix) (->> (group-by key)))

urbanslug08:08:07

Can I have an ordered map? All my attempts fail. Where br is a map

(into {} (sort-by first (br)))

urbanslug08:08:18

the into unorders it again

slipset08:08:21

@iku000888 yes, but it’s starting to dawn upon me that I’m working at different levels of something in the same thing

urbanslug08:08:59

but (sort-by first (br)) gives me an ordered list of vectors

slipset08:08:16

@urbanslug (sorted-map (sort-by first (br))

urbanslug08:08:18

I wonder whether I can concat into a map

urbanslug08:08:31

slipset Thanks

iku00088808:08:08

@slipset I guess I got too used to doing it and stopped thinking rich

urbanslug08:08:48

Maybe silly question but can I pipe the result of a side-effecty function like pprint into a file? trying (spit “file.txt” (pprint …)) but it obviously writes nil.

urbanslug08:08:58

truncates file to zero

slipset08:08:01

@urbanslug could you rebind *out* to an outputstream that you control?

slipset08:08:13

I guess you’d need to use something else than spit like https://clojuredocs.org/clojure.java.io/writer

Rachel Westmacott08:08:05

(spit “file.txt” (with-out-str (pprint …)))?

urbanslug08:08:48

Thanks guy(s)/girl(s)

abdullahibra11:08:11

what is the best way to do this in clojure: find <dir> -type d ?

abdullahibra11:08:31

return all depth dirs from <dir>

squiddle11:08:28

@abdullahibra something like (->> (file-seq <dir>) (filter #(.isDirectory %)))

mschmele13:08:13

Is anybody able to help me with a clojure.spec issue I’m having?

dominicm13:08:13

@mschmele You might want to try #clojure-spec Also "don't ask to ask, just ask"

mschmele13:08:02

ooh, thank you!

karbak17:08:15

Is $& legal Clojure? I find references to it on SO and in a 4Clojure solution, but not in any documentation I can search.

jr17:08:09

you mean %& ?

karbak17:08:27

That’d certainly make sense .. I wonder if those were typos.

kosecki17:08:07

Hi, does anyone heard about similar lib for Clojure https://github.com/App-vNext/Polly ?

kosecki17:08:09

…used in for e.g when dealing with unreliable services by setting retry policy, so when call to ws fails it gets repeated etc

shuaibiyy18:08:23

Hi folks.. what are some options for building microservices in clojure other than hystrix and finagle?

kosecki18:08:44

@shuaibiyy …diehard as mentioned by @dorab, circuit breaker is a important imho

kosecki18:08:15

@shuaibiyy it’s not purely for ‘building’ ms

tanzoniteblack18:08:49

never looked into diehard (though I’m going to now that I’ve heard of it), always used https://github.com/josephwilk/circuit-breaker to do circuitbreakers around microservices

ag19:08:22

how do I retrieve a value of specific key from multiple maps? Why this is not working?

(def mp1 [{:foo 1} {:foo 2}])

(def mp2 [{:foo 3} {:foo 4}])

((juxt (partial map :foo)) mp1 mp2)

jr19:08:21

(map :foo [mp1 mp2]) ?

ag19:08:53

(nil nil)

dpsutton19:08:27

mp1 is a vector of two maps is the reason

jr19:08:15

(mapcat (partial map :foo) [mp1 mp2])

ag19:08:16

so that’s why I need I need to map trough both vectors and grab :foo from every map

dpsutton19:08:40

jr's got it it seems. You have to "descend" into a sequence twice

danboykis19:08:38

@ag you could also do (map :foo (concat mp1 mp2))

ag19:08:51

now I wonder which is slower

andrepnh19:08:59

@ag you could check that with criterium

ag19:08:04

why not clojure.core/time?

andrepnh19:08:09

if you want just a quick comparison you could that

andrepnh19:08:43

but then if performance is not that important I would just pick option 2 because it looks cleaner

dpsutton19:08:20

my guess would be the version without concat

andrepnh19:08:31

benchmarking, however, is tricky, specially because the JVM does a bunch of optimizations as code runs

andrepnh19:08:35

(and criterium takes care of that)

hlolli20:08:22

If I understand core.async correctly, then it's impossible to define go-loop that can be closed or killed after it is started?

richiardiandrea20:08:01

@hlolli you have to roll your own way of controlling that yes, for instance when you receive a nil on the channel, which means the channel is closed, you don't call recur

hlolli20:08:06

ah makes sense, thanks @richiardiandrea

hlolli20:08:19

Could I make a controller like that in core.async. So on every recursion, take a boolean value from channel, if one exists, and proceed to recur if the bool returns true. It would mean many blocking takes I guess, and would quickly fill the que if Im not feeding the channel as quickly a bool as the channel wants to read, hope my question makes sense.

jr20:08:04

(go-loop [] (when (<! ch) (recur)))

hlolli21:08:23

ok, this makes me reconsider how Im solveing my problem. In my case (which is probably bad design), I have a (metronome) clock (go-loop [cnt 0] (when (not= (clock-value-from-external-app) cnt) (recur (clock-value-from-external-app))) something like that. Well, I could always use clojure.core loop and send it into a go loop and from there make callbacks in core.async land. Just thinking out loud.

Chris O’Donnell21:08:36

@hlolli: could you use clojure.core.async/timeout?

hlolli21:08:23

maybe 🙂 I've only used core.async very little, if I knew more low-level about it I would be happy. Wouldn't timeout create quickly thousands of waiting background threads?

jr21:08:35

what are you trying to achieve?

hlolli21:08:17

@codonnell this is a possible solution, what I'm trying to achive, (if I want to achieve that). I better explain it with a sample that fails, but maybe you see if my "heart" is at the right place:

(def engine-start? (atom false))
(go-loop[]
  (when (and (true? @engine-start?)
                            (new-clock-value... elided...))
   (recur))
(reset! engine-start? true)
your short snippet @jr solves it, or never has this problem in the firstplace. But I'd be curious to know if this engine-start? can be a value from a channel rather than atom (which doesnt work, except if @engine-start? returns true initially).

Chris O’Donnell21:08:52

@hlolli: what does new-clock-value do?

hlolli21:08:06

to be perfectly percise, it returns 0 if a audio signal was iterated (44,1k per second), and needs to be in a recursive loop to iterate trough audio files/signals.

Chris O’Donnell21:08:46

so do you just want to start reading once the engine has started?

hlolli21:08:06

yes, and stop, on command.

Chris O’Donnell21:08:42

I edited my snippet above

Chris O’Donnell21:08:29

engine-start is a channel, and once it received a message, you're ready to start processing. Also, clock-chan is a channel receiving clock values. f-chan is a channel, and once it receives a message you will stop processing.

hlolli21:08:16

ok, thanks for now, I will need to give this a try, cant see in this code how the loop can be terminated after it is started.

Chris O’Donnell21:08:46

alts!! reads from the first channel which receives message, clock-chan or f-chan. If clock-chan receives a message, the when condition is satisfied and recur is called. If f-chan receives a message, the when condition is not satisfied and it will drop out of the loop. Does that make sense?

hlolli21:08:33

yes, it does, I think this will be very clear when I start coding. This is the behaviour Im looking for in the end.

Chris O’Donnell21:08:20

I found tim baldridge's core.async videos to be a huge help in understanding how core.async can and should be used. They're a bit out of date (no transducers), but most of the insight is still very useful.

hlolli21:08:55

Yes core async seems to want different parts of the brain. I find atoms, agents, refs much easier to understand, even tough it could be that core.async is evens simpler, just new for me.

gfredericks22:08:22

I made a quine that doesn't eval to itself but eval'd 1000 times it does: https://gist.github.com/gfredericks/2369143507f032f4190d37e0185e9908

didibus23:08:33

I have a clojure gen-class, and I'm wirting a clojure test that tries to call it as a java method, its defined static, so: (com.bla.bla/myStaticGenMethod) but I always get NoClassDef

gfredericks23:08:35

gen-class is so weird that it's worth asking why you need to use it :)