Fork me on GitHub
#clojure
<
2016-06-15
>
bcbradley00:06:55

I have some sets that look like this: #{ {:name "sam" :age 7} {:name "sarah" :age 23 :job firefighter} }, #{ {:name "sam" :hobby "softball"} {:name "tom" :hobby "sewing"} }

bcbradley00:06:17

I want to merge these sets into a single set, so it would be #{ {:name "sam" :age 7 :hobby "softball"} {:name "sarah" :age 23 :job "firefighter"} {:name "tom" :hobby "sewing"} }

bcbradley00:06:32

there is a function called "merge" in clojure.core that merges two maps, but what is the most efficient way to find the maps that should be merged within the sets above?

bcbradley00:06:21

I've been thinking about this for a while, but I can't come up with a clean algorithm that isn't O(n^2)

cory01:06:07

@bcbradley: I am on mobile, but doesn’t a map e.g. {“sam” {:age 7} “sarah” {:age 23 :job “firefighter”}} seem mergeable in linear time? I think you should be able to convert to and from this map in O(n) time as well.

bcbradley01:06:40

I guess if names are unique then the set of relations could just be represented better as a set of functions from those names to the other stuffs (in other words a map, the way you suggest).

bcbradley01:06:06

I don't know if I can guarantee that the names are unique

bcbradley04:06:04

does anyone here know whether or not the function returned by juxt runs on multiple threads?

ajchemist05:06:18

Is there any reason that do-copy should be private in ?

ajchemist05:06:36

if do-copy would be public interface, It will be handy for extending custom io factory.

lmergen09:06:41

what would be an easy way to get a build date/timestamp or git checkout hash into clojure source code ?

lmergen09:06:47

is there a lein plugin that could handle this ?

mpenet09:06:39

at runtime? you can always drop down to shell and use something like this (clojure.java.shell/sh "git" "rev-parse" "HEAD")

mpenet09:06:30

in a project.clj it's probably possible to ~(...) the same expression

rauh09:06:44

Alternatively, use extension:clj to search. Also gives many results

lmergen09:06:56

@mpenet: no at build time

escherize11:06:38

{: 1}
;; => error
{:: 1}
;; => error
{(keyword ":") 1}
;; => {:: 1}

escherize11:06:00

So, I'm learning about Records. is there a good definition of record or associated with record that will help me understand?

hlolli11:06:35

The book Clojure applied covers records in a wonderful way. But don't se any connection to your code snippet and Records.

plexus11:06:27

@escherize: there's no perfect parity between the keywords you can create with keyword and the ones the reader will accept. This is a known issue. Some argue keyword should be more strict, not sure if there's a final decision on that

escherize11:06:53

@hlolli: oh no there is none. :0

escherize11:06:34

spec can solve that problem :]

escherize11:06:36

Would be cool to see a bunch of ??! clojure snippets

escherize11:06:20

Reporter: Zach Tellman

mateus.henrique.brum12:06:32

I have some question about dependency injection in clojure. What kind of DI do you use? I know the follow: Inject by argument. Inject by map. Inject by protocol. Inject by context. There are others kind ? What do you usually use ?

mateus.henrique.brum12:06:55

I have some idea what is component lib, it is nice useful, etc ..

meowy12:06:29

Both can be used for DI; flexibility's achieved in Component by letting you change the system map, and in Mount by letting you compose your app in your mount/start call.

mateus.henrique.brum12:06:54

But at raw level, what is the techniques do you use ? How to make functions more decoupled ?

escherize12:06:27

I think, in the small, higher order functions are king for that.

meowy12:06:37

Yup, was about to mention higher-order functions.

mateus.henrique.brum12:06:37

My question is more about design than about tools ...

escherize12:06:07

but those tools are designed to answer your question 🙂

meowy12:06:13

Pass in a function to another function. That's how map, reduce, filter and so on work. They only define a behavior (e.g. apply function to every item in a sequence, ...), the actual implementation's up to you.

escherize12:06:42

@mbrum can you define your use of decoupled? What do two coupled functions look like?

meowy12:06:57

Splitting up your functions and composing them afterwards also helps decoupling on a smaller scale. comp and the threading operators ->, ->> and their relatives are your tools there.

mateus.henrique.brum12:06:45

ok, I will study both libs and re-think about my question .. 🙂 thanks guys ...

mateus.henrique.brum12:06:17

@meowy So you usually use di as arguments ?

mateus.henrique.brum12:06:36

but if you have so many dependencies, how do you deal with it ?

mateus.henrique.brum12:06:06

(defn bla dependency1 dependency2 dependency3 dependency4 coll)

escherize12:06:46

probably defresource?

escherize12:06:35

It's kind of like closing over some dependencies: https://gist.github.com/Integralist/6ba8b3effc03aa47ab93

mateus.henrique.brum12:06:48

it is like a map of resource ?

escherize12:06:14

Yeah, and you can attach functions that use that map, with args if you wish to do stuff

mateus.henrique.brum12:06:53

but it stop to have a referential transparency, correct ?

mateus.henrique.brum12:06:12

creating a kind of state into function, correct ?

mateus.henrique.brum12:06:18

or a miss something ?

escherize12:06:41

not necessarily, that would depend if you have side effects.

escherize12:06:16

of course at some point we have to have side effects

wotbrew12:06:48

@mbrum Make sure you are seeking values in your domain that compose your dependencies together to reduce the number of args. e.g (defn person [first-name middle-name last-name address-line1 ...]) -> (defn person [name address])

wotbrew12:06:57

Kind of obvious but this actually scales up

mateus.henrique.brum12:06:08

(def map_of_dependencies {:dep1 fdep1}) ; (defn a [coll] ((:dep1 map_of_dependencies) coll))

mateus.henrique.brum12:06:21

it isn't a little bit strange ?

wotbrew12:06:42

Also at the very boundaries of your app (where effects live) you shouldn't seek to provide convenience, you should prefer more explicit let binding, multiple calls etc

escherize12:06:12

@mbrum: It's different than pure function calls for sure.

escherize12:06:45

but using the map_of_dependencies lets you easily test your app

escherize12:06:57

because you can swap in the test-db etc.

mateus.henrique.brum12:06:21

but a little bit indirect 😕

escherize12:06:32

yeah it is an abstraction.

escherize12:06:41

Where I work they are very into that kind of indirection.

mateus.henrique.brum12:06:43

by the way, you have to know the implementation ...

escherize12:06:54

In my previous projects we have been more direct.

escherize12:06:23

I think with that pattern, that there can be successful encapsulation.

mateus.henrique.brum12:06:31

I understand , but in your experience, what is better for large projects ?

escherize12:06:33

(def system (make-test-system))

escherize12:06:41

(upload-ftp system "file")

mateus.henrique.brum12:06:43

pass args or a map ?

escherize12:06:06

oh, I prefer maps.

mateus.henrique.brum12:06:23

it do not guide you to a poor design ?

escherize12:06:38

(defn person [{:keys [name number height...]} (do-stuff name)...)

mateus.henrique.brum12:06:39

because you can "by pass" things ?

mateus.henrique.brum12:06:57

I mean, you can fetch things freely ...

escherize12:06:25

well, the things you put into system are long-lived stateful things that are unlikely to change.

escherize12:06:47

So, like a db connection, or a web server process

mateus.henrique.brum12:06:47

pass by destructuring is better.

mateus.henrique.brum12:06:10

but still is a kind to pass by args .. 😕

escherize12:06:25

pass by args?

mateus.henrique.brum12:06:49

(defn a [arg1-dep coll] ...)

escherize12:06:17

no, whats passed by args

mateus.henrique.brum12:06:34

the function dependency ...

escherize12:06:32

okay, what's a better alternative?

escherize12:06:01

(def dep1 ....)
(defn f [x] (dep1 x))
?

mateus.henrique.brum12:06:41

In fact, I don't know

escherize12:06:56

(defprotocol Iadd (add [this] [a b]))
(extend-protocol Iadd
  Object (add [a b]))

(defrecord Scalar [a b]
  Iadd
  (add [this] (+ a b)))

(def my-scalar (->Scalar 1 2))

my-scalar
;; => #teal.db.customer.Scalar{:a 1, :b 2}


(add my-scalar)
;; => 3

mateus.henrique.brum12:06:35

inject by protocol ?

mateus.henrique.brum12:06:53

it is a alternative too ...

mateus.henrique.brum12:06:03

I have to study much more ... 😛

escherize12:06:33

Then you can fake the call like this:

(defrecord FakeScalar [a b]
  Iadd
  (add [this] 3)) ;;<- notice 3 not (+ a b)

(def fake-scalar (->Scalar 1 2))

(add fake-scalar)

escherize12:06:05

I'm not sure if it's great or not.

escherize12:06:21

I'm still learning too, @mbrum

mateus.henrique.brum12:06:15

I see that have some implicit ways to inject dependency ..

mateus.henrique.brum12:06:42

protocol, context, maps ... 😕

mateus.henrique.brum12:06:53

It look me weird ..

mateus.henrique.brum12:06:10

the explicit ways, pass by argument (with destructuring or not) appear me better, but if you have a lot of dependency it can be a problem ... 😕

lmergen13:06:43

is there a common pattern for this type of construct:

(if (:foo bar)
  (:foo bar)
  (something-else))
?

wotbrew13:06:19

@lmergen (or (:foo bar) (something-else))

lmergen13:06:35

yes that's it

wotbrew13:06:26

If you don't have something to evaluate in the else branch you can use the not-found clause as well

wotbrew13:06:48

e.g (:foo bar "something else")

wotbrew13:06:06

Though this is slightly different

wotbrew13:06:17

As it will return the value at :foo even if it is null/false. (e.g it does a presence check rather than a value truthyness check)

lmergen13:06:44

i think that's even more clear

wotbrew14:06:58

Just make sure you understand the difference in semantics before replacing (if x x y) calls with anything other than (or x y) 🙂

lmergen14:06:29

you mean that or is lazy ?

wotbrew14:06:36

that is one aspect

lmergen14:06:54

and the evaluation order is different

mariogintili14:06:29

are there any clojure peeps up for helping me with an interesting project? OSS 👼

jrychter14:06:52

Is there a way to use s/multi-spec multimethods with unqualified keywords? A multi-spec-un, or something?

martinklepsch14:06:15

Anyone here has some experience with Automat, particularly advice on this issue: https://github.com/ztellman/automat/issues/24 ?

ccann14:06:34

I’m trying to consolidate the usage of ! in my library’s function names, and I’m finding it difficult to find a coherent stance on the idiom. Does anyone have a good resource?

ccann15:06:03

specifically I have functions that create something external (e.g. a rabbitMQ queue) so I’ve named them create-queue but should it be create-queue!?

wotbrew15:06:08

The clojure.core usage seems to be 'something that is unsafe in a transaction (not pure/retry/rollback aware)' e.g swap! vs send

wotbrew15:06:39

Many side effects would fall in to the 'unsafe' camp, so typically impure functions will have a '!' on the end

ccann15:06:46

so if create-queue fails when called twice in a row, or has some other nefarious effect, then the ! is warranted?

wotbrew15:06:04

I would say so yes

wotbrew15:06:16

I always say "if unsure use a '!'". I like libraries that somehow mark these potentially dangerous fns. Honestly I don't use the STM much so its more about just seeing what is likely to harbour a potentially dangerous side effect.

ccann15:06:31

that’s interesting. So if I have a function that modifies an atom by assoc-ing it, that’s idempotent, so it doesn’t need the bang?

ccann15:06:39

even though it’s modifying state

wotbrew15:06:59

yes but consider other threads could also be swap'ing the atom

ccann15:06:30

right of course, good point

ccann15:06:19

so same goes for create-queue then. another thread could be deleting that queue

wotbrew15:06:55

I would need to think about it some more, but even idempotent actions given retries could potentially alter the possible histories of a set of concurrent threads. I've confused myself now 🙂

ccann15:06:30

okay, I appreciate the input @danstone

ccann15:06:44

I’m not sure what I’m going to do :thinking_face:

wotbrew15:06:25

I like create-queue! 🙂

ccann15:06:29

I think I’m going to err on the side of using the !

ccann15:06:41

:thumbsup:

wotbrew15:06:40

Ok I've thought about it, idempotency is not enough. Consider a rollback in the STM, caused by an exception. your swap! would still have happened. That is what is meant by 'unsafe in a transaction' - send is not like this, because sends are guaranteed to happen only on successful completion of (and as part of) the transaction.

wotbrew15:06:55

From a concurrency standpoint, other threads could be affected by a transaction that does not get committed, or is not yet committed. Which alters potential histories and could cause some really weird bugs

ghadi15:06:14

! ~= 'pay attention'

wotbrew15:06:49

@ghadi nice, so if its really dangerous, just add more bangs. 😄

ghadi15:06:55

pretty much 😉

ccann15:06:12

dump-db!!!!!

ccann15:06:30

so, what about clojure.core/flush

wotbrew15:06:04

I don't think clojure.core is entirely consistent with this convention - Otherwise of course you could argue about def!

mpenet15:06:26

danstone: you prolly mean "agent", not "actors"

mpenet15:06:00

or something else

wotbrew15:06:05

I meant in a generic way, probably could have used 'processes'

mpenet15:06:10

then there's actor and Actor 😆

wotbrew15:06:11

or 'agent'

wotbrew15:06:13

or 'thread'

wotbrew15:06:11

ta, edited

ccann15:06:33

I’m essentially wrapping java methods that operate on a java class that’s not thread safe, the onus is on the developer to manage concurrent access. So maybe then if you call a method like create-queue on that object multiple times you don’t run the risk of another thread calling delete-queue unbeknownst to you

ccann15:06:52

so maybe the bang is unnecessary

wotbrew15:06:59

create-queue is unsafe in a transaction. its a matter of whether you want to follow the convention or not. I understand the community as a whole doesn't follow this convention a lot of the time anyway. My impression is that its not widely advertised as a 'thing you must do' in clojure. I have my own set of naming rules, other people have theirs.

ccann15:06:02

fair enough, I think I’ve already spent too much time thinking about this 😕

ghadi15:06:18

sounds like the important part is superimposing safety on the stuff you're calling, not the naming

ghadi15:06:27

sorry that sounded glib

ghadi15:06:09

clojure does make it really nice to wrap unsafe api's

wotbrew15:06:17

You can always have create-queue dispatch its effect via an agent if you want to keep the name and adhere to the convention 🙂

pithyless16:06:37

It's not entirely obvious from the docs, but am I correct in thinking that s/def in clojure.spec can register keywords from non-existing namespaces? Would it be an anti-pattern to use something like (s/def :foo.bar.api/id) in order to distinguish it from (s/def :foo.bar/id) without creating said namespace?

pithyless16:06:10

Is it then just a question of making sure namespaces are loaded in an order to be able to resolve that in the registry correctly?

pithyless16:06:58

^ looking at the implementation, I answered my own question. 🙂

Alex Miller (Clojure team)17:06:35

Keyword namespaces don't have to exist as a Clojure namespace

Alex Miller (Clojure team)17:06:31

So feel free to make good namespaces independent from your code (but be aware that affects your ability to use aliases)

seancorfield17:06:39

As a heads up, re: keyword namespaces, I’ve added a :qualifier option to clojure.java.jdbc to make it easy to produce result sets with namespaced keywords — will be in 0.6.2. Since namespaced keywords are going to be "the thing" everywhere soon… (jdbc/get-by-id db-spec :user 42 {:qualifier "user"}) => {:user/id 42 :user/name "Sean" …}

malcolmsparks17:06:57

Don't leave us in suspense @alexmiller !

seancorfield17:06:29

Feedback on that ^ welcome, before it gets baked into a release.

malcolmsparks17:06:45

I'm considering moving #C0702A7SB's non-ns keywords to ns ones.

bfabry18:06:32

@seancorfield: a symbol qualifier rather than a string would make sure that it follows the naming rules for a ns

bfabry18:06:06

ie {:qualifier 'foo bar} compile error {:qualifier "foo bar"} runtime error

seylerius18:06:26

How does one most efficiently run a shell command as a separate process and give it some kind of stringIO type thing to stick its output in?

seylerius18:06:40

Or a separate thread?

bfabry18:06:17

@seylerius: I don't know if it's the "most efficient" but we just used the ProcessBuilder api directly:

(defn run-command-stream-output
  "Runs a shell command and streams the output.
  An exception is thrown if the exist status is non-zero."
  [command]
  (let [process (.start (ProcessBuilder. (into-array String command)))]
    (future (io/copy (.getInputStream process) (System/out)))
    (future (io/copy (.getErrorStream process) (System/err)))
    (if (not= (.waitFor process) 0)
      (throw (Exception. (str "Failed command '" (clojure.string/join " " command) "'"))))))

jannis18:06:24

When using (clojure.spec/fdef my-macro ...), any uses of the macro (at least during testing0 automatically include a validation of the macro arguments. How come this isn't the case when using fdef with functions?

bfabry18:06:09

@jannis: I believe performance. macros happen at macroexpansion time when performance is generally not a concern. functions get called in production. You can turn that validation on for all the functions in an ns using instrument-ns

jannis18:06:35

@bfabry: Ah, performance... that's a valid concern. I just found out about instrument while you replied. instrument-ns sounds useful too. Cool, so that way I can either wrap a function or a namespace to activate validation.

jannis18:06:41

What's the most elegant way to write simple automated, generated, random tests for functions with clojure.spec? (deftest my-func-conforms-to-its-spec (is (some-fspec my-func)))?

jannis18:06:38

One problem I see with that approach is that it doesn't report anything useful if it fails, since all a function spec created with fspec returns is true or false.

bfabry18:06:38

@jannis I believe the clojure.spec.test/check-fn fn is what you're looking for http://clojure.github.io/clojure/branch-master/clojure.spec-api.html#clojure.spec.test

Alex Miller (Clojure team)18:06:39

@malcolmsparks: we're considering allowing aliases for non-existent namespaces

Alex Miller (Clojure team)18:06:52

@jannis yeah, check the stuff in clojure.spec.test for more

jannis18:06:57

Nice, thanks.

jannis18:06:42

(is (nil? (s/explain my-fun-spec my-fun)) might've worked as a hack as well but I'll check out clojure.spec.test

Alex Miller (Clojure team)18:06:05

well s/valid? prob more useful there

jannis18:06:07

Except it doesn't explain what is wrong when things fail.

seancorfield18:06:47

With check-fn and check-var, is there a way to get a "nice" explanation of the failures, like explain produces?

seancorfield18:06:54

Hmm, this convo probably belongs in #clojure-spec ...

malcolmsparks19:06:23

@alexmiller: what would help would be some kind of tag literal that declares the default ns for any non-ns keyword keys in the following map literal. Well, that's one possible solution to the problem I'm facing: how to move to ns-keywords without giving users RSI.

seancorfield19:06:12

@malcolmsparks: There’s a JIRA ticket for namespaced maps… let me dig that up...

malcolmsparks19:06:56

@seancorfield: thanks. Would like to know what the tradeoffs are

seancorfield19:06:38

Targeted for 1.9 if the open questions can all be resolved.

malcolmsparks19:06:55

That would be terrific.

Alex Miller (Clojure team)20:06:56

1910 will be added for 1.9. Also CLJ-1919 for namespaced key destructuring.

jorgedfbranco20:06:02

guys, any way to improve this?

jorgedfbranco20:06:03

I would like to, if possible, define the random number generator inside of random-double

jorgedfbranco20:06:17

well, I could define random-double as a variable that returns a function

jorgedfbranco20:06:21

ok, problem solved

jorgedfbranco20:06:44

but then I can't have operator overloading

noonian21:06:16

jorgedfbranco: you can do operator overloading with anonymous functions also

donaldball21:06:44

The minor problem I need to fix now is that the timeout channel closes after an elapsed period of time, not at a specific point in time

donaldball21:06:23

Which is fine for e.g. cancel an operation if it takes too long scenarios, but not great for send a signal at a specific point in time scenarios

noonian21:06:14

@jorgedfbranco: e.g.

(import java.util.Random)

(def random-double
  (let [random (Random.)]
    (fn
      ([] (.nextDouble random))
      ([min max] (+ min (* (- max min) (random-double)))))))

donaldball21:06:57

Whoops, wrong room, sorry for that non sequitur

Tim23:06:48

will clojure 1.9 run on leiningen

Tim23:06:52

I’d like to try out spec

ghadi23:06:22

tmtwd: just require one of the 1.9.0-alpha6 releases in your project.clj

ghadi23:06:44

looks like they're up to alpha7

Tim23:06:44

I’m going to use mvn to install 1.9 in my .m2 repo

ghadi23:06:54

you don't need to do that if you use leiningen

Tim23:06:56

and then require it from project.clj

ghadi23:06:11

just refer to the version in leiningen, no need to touch mvn

Tim23:06:27

ah I got it

ghadi23:06:29

it will seamlessly download to your .m2 behind the scenes

seylerius23:06:12

Weird. Adding me.raynes/conch to the deps leads to cider completely failing to load.