Fork me on GitHub
#clojure
<
2017-06-21
>
Alex Miller (Clojure team)02:06:03

a null in a map shouldn't cause an NPE

Alex Miller (Clojure team)02:06:33

so I'd say that's a bug in potemkin, but would need to see more to know for sure

dpsutton03:06:03

@csm what defrecord stuff are you using? i'll look at it

dpsutton03:06:55

(hashCode [this]
    (reduce
      (fn [acc [k v]]
        (unchecked-add acc (bit-xor (.hashCode k) (.hashCode v))))
      0
      (seq this)))

dpsutton03:06:58

that looks like it

csm04:06:56

it does seem like it is a bug in potemkin, I wrote up https://github.com/ztellman/potemkin/issues/52

csm04:06:46

my use case would have been better served using identityHashCode, too, so I just wrapped the object in another holder object

benny04:06:33

I'm really struggling how best to test with Clojure, specifically when I start having to mock interactions with a database etc. Looks like mock frameworks aren't super popular in clojure and I'm assuming there's a good reason that I'm missing

benny04:06:40

Any tips?

benny04:06:40

looks like maybe with-redefs* might be what I'm looking for

csm04:06:28

I, for one, prefer testing against a “real” database if possible; we test our app against a in-memory datomic DB, and against a H2 database (we use datomic and a SQL database)

dpsutton04:06:11

@csm what do you mean on that pull request?

dpsutton04:06:32

you're making sure we don't hash false? but isn't that fine?

csm04:06:27

making sure you are hashing false?

dpsutton04:06:55

is there a reason to use (if some? v) vs (if (instance? Object k)?

csm04:06:04

some? might perform better than instance?, I guess

dpsutton04:06:07

i wouldn't have thought to use some? like that on a single value. that's clever

dpsutton04:06:17

instance? (fn instance? [^Class c x] (. c (isInstance x))))

dpsutton04:06:30

yeah looks like it

dpsutton04:06:33

good thought

dpsutton04:06:56

didn't know some? was just a nil check

dpsutton05:06:50

thanks 👍

csm05:06:13

good find, too, I didn’t bother digging through potemkin

dpsutton05:06:33

i've read the source a little while ago so kinda knew where to root around.

qqq06:06:37

@darwin:

(def ocall #?(:cljs oops.core/ocall
              :clj (not-implemented "ocall")))

(def oget #?(:cljs oops.core/oget
             :clj (not-implemented "oget")))

(def oset! #?(:cljs oops.core/oset!
              :clj (not-implemented "oset!")))

(def gcall #?(:cljs oops.core/gcall
              :clj (not-implemented "gcall")))

doesn't work since ocall oset oget are macros I'm trying to push the #_ (:cljs :clj) into lower level libraries. Is this possible?

kah0ona07:06:24

is there a way to list the functions that are currently ‘under instrumentation’ (clojure.spec)?

kah0ona07:06:31

of a running program that is

darwin08:06:27

@qqq wrap macros with macros… because turtles

qqq09:06:43

@darwin: is there no way to write these as functions if we pass all args as strings ?

darwin09:06:00

@qqq macros are expanded at compile time, functions are called at runtime, once you are in runtime, you cannot “go back” and do compile-time stuff (except for using eval, which is a different story)

qqq09:06:10

no, I meant implemenatikn of oget

qqq09:06:17

why does it have to be a macro instead of a function ?

darwin09:06:18

the question is, why do you need those to be functions?

qqq09:06:30

then I wrap a base layer in cljc

qqq09:06:37

and get rid of the #?(:cljs ...) everywhere

darwin09:06:31

cljs-oops (e.g. oget) is writing code for you you would otherwise write by hand, that is why is implemented as macros

darwin09:06:19

if it was a function, it would at runtime dynamically perform some code, but not rewrite your existing code

darwin09:06:35

again, why you cannot wrap oops macros with your own macros? where do you see a problem in that approach?

darwin09:06:12

and btw. we are off-topic here, we should be discussing this in #clojurescript instead, have to go anyways

carocad13:06:47

just in case a developer of clojars is around. The GSoC link in the github README is broken 😞 https://github.com/clojars/clojure-gsoc-2017

stathissideris13:06:49

how do people feel about the idea of EDN files that have an (aliases) header at the top to enable shorter keywords in the rest of the document:

(aliases [[monitor.reporter :as r]])
{:r/foo 1
 :r/bar 2}

stathissideris13:06:17

not proposing for this to be part of Clojure, just asking what you think of it as a practice

tcrawley13:06:22

@carocad can you file an issue or PR on that repo?

carocad13:06:21

I guess so. I just thought it would be faster if any of them was here 😄

tcrawley13:06:50

I'm here, just focused on other things ATM :)

carocad13:06:00

ah ok, well … done

carocad13:06:13

the fix is quite simple so no op 😉

carocad13:06:56

@tcrawley I just created another pr for some other small markdown problems that I found. Hope it helps

tcrawley13:06:49

thanks! I'll let @sattvik review those changes, he's the primary on the GSoC stuff

michaellindon14:06:23

I am constructing a nested datastructure, similar to a binary tree, recursively using

(defn make-tree [{in :in out :out left :left right :right :as tree} indices]
  (cond
    (empty? indices) tree
    :else (assoc
           tree
           :left (make-tree {:in (conj in (first indices)) :out out} (rest indices))
           :right (make-tree {:in in :out (conj out (first indices))} (rest indices)))))

schmee15:06:41

I haven’t tried it myself but it seems to do what you want

schmee15:06:02

otherwise, you’ll have to implement something like that yourself with delay and force

michaellindon15:06:03

I have come up with this, i think it is inelegant

michaellindon15:06:12

(defn make-lazy-tree [{in :in out :out left :left right :right :as tree} indices]
  (cond
    (empty? indices) tree
    :else (assoc
           tree
           :left (fn [] (make-lazy-tree {:in (conj in (first indices)) :out out} (rest indices)))
           :right (fn [] (make-lazy-tree {:in in :out (conj out (first indices))} (rest indices))))))

michaellindon15:06:04

so instead of returning the next subtree it returns a function to the next subtree, which can be called like this

michaellindon15:06:18

(defn my-left [t] ((:left t)))
(defn my-right [t] ((:right t)))

(-> foo
    my-right
    my-right
    my-left)

michaellindon15:06:14

giving:

=> {:in #{2},
       :out #{0 1},
       :left #function[bab.core/make-lazy-tree/fn--20560],
       :right #function[bab.core/make-lazy-tree/fn--20562]}

michaellindon15:06:39

I guess delay is kind of doing the same thing?

michaellindon15:06:53

just tried it, delay works nicely too

michaellindon14:06:10

however the recursion will run quite deep and cause stack overflow. Is there a lazy way I can define this tree? I will not actually visit all of the tree

michaellindon14:06:20

In short it sets up a deeply nested map, but I want to do this in a lazy way so that the values mapped to by keys are not evaluated until accessed

jeff.engebretsen15:06:18

You can do tail recursion for the stack overflow but that won’t help with the lazy part.

noisesmith16:06:24

you can’t tail call that code though

noisesmith16:06:35

not without a radical design shift to move stack data into the heap

michaellindon16:06:48

agreed. As per @schmee s suggestion i wrapped the calls with delay

michaellindon16:06:53

(defn make-delay-tree [{in :in out :out left :left right :right :as tree} indices]
  (cond
    (empty? indices) tree
    :else (assoc
           tree
           :left (delay (make-delay-tree {:in (conj in (first indices)) :out out} (rest indices)))
           :right (delay (make-delay-tree {:in in :out (conj out (first indices))} (rest indices))))))

michaellindon16:06:09

writing

(defn my-left [t] @(:left t))
(defn my-right [t] @(:right t))

michaellindon16:06:25

I can traverse the tree to the leaf nodes that I want, without creating the others

michaellindon16:06:38

I like this, but I'm wondering if anyone else can see any pitfalls

noisesmith16:06:52

delay is under-utilized imho

noisesmith16:06:15

a fun fact - force is an alternative for deref on delays, and is identity on non-delay values

joshjones16:06:01

will still blow the stack, no?

noisesmith16:06:16

only if you eagerly call it recursively

noisesmith16:06:33

but it is easy to make a non-stack-consuming recursion that goes into deeper delays as far as you like

joshjones16:06:52

like with a continuation

noisesmith16:06:05

right, a delay is a zero arg continuation, effectively

noisesmith16:06:21

thunk? maybe that’s the word

noisesmith16:06:52

anyway, that overloaded behavior of force makes it convenient to write code that may or may not hit a delayed value

michaellindon16:06:05

you've lost me now 🙂

noisesmith16:06:29

thunks / continuations are how lazy seqs are implemented

noisesmith16:06:35

and delays do the same thing

noisesmith16:06:47

it’s a function that stands in for a value we might access later

noisesmith16:06:02

@joshjones that article mentions a continuation being a one arg function, which is why I was particular about argument count - these being zero arg

michaellindon16:06:16

so actually my first attempt was to change

:left (make-lazy-tree {:in (conj in (first indices)) :out out} (rest indices))
to
:left (fn [] (make-lazy-tree {:in (conj in (first indices)) :out out} (rest indices)))
and then I could traverse the tree by calling the function returned by :left. Is this what is meant by continuation?

noisesmith16:06:42

that’s what’s meant by thunk

michaellindon16:06:10

ah ok, cool, im happy to be learning this

joshjones16:06:44

yeah, it's cool stuff, and more common in the FP world

michaellindon16:06:47

thanks for your help

joshjones16:06:40

@noisesmith what would be the pros/cons of delay vs a fn in this case?

noisesmith16:06:35

a delay is a way of making a function that gets called only once when forced, whereas a function could get called more than once and would not cache the prior result (unless you memoized…)

noisesmith16:06:10

delays are a more specific feature for this purpose so they eliminate some gotchas and boilerplate that come up in usage

noisesmith16:06:26

apologies for linking to my fork but that file is unmodified

noisesmith16:06:50

another usage of delay I’m fond of is replacing nested lets inside conditionals with a let containing delays with conditionals that force certain delays as apropriate in a cond block

bronsa16:06:04

noisesmith: ew :P

bronsa16:06:36

that sounds very.. imperative

noisesmith16:06:00

it’s something I only need for very imperative tasks

noisesmith16:06:40

where I’m maybe getting a resource, maybe retrying, maybe cleaning up and bailing, etc. and it doesn’t fit a with-open or try/catch/finally well

noisesmith16:06:19

eg. trying to use zookeeper in clojure where every operation potentially requires me to re-try or fail

noisesmith16:06:57

(not coincidentally I am moving away from using zookeeper so I can avoid having to write code like this)

noisesmith16:06:25

additionally, the delays can force another let bound delay inside their body, which simplifies tricky side effect tracking

yannvahalewyn17:06:18

Hey guys, building the first production clj/cljs app for my company. I'm looking for a best practice tip for using Stuart Sierra's component with a (postgres) database connection.

(ns my-app.components.db
  (:require [com.stuartsierra.component :as c]
            [clojure.java.jdbc :as jdbc]))

(defrecord Db [spec connection]
  c/Lifecycle
  (start [this]
    (let [conn (or connection (jdbc/get-connection spec))]
      (assoc this :connection conn)))
  (stop [this]
    (if connection (.close connection))
    (assoc this :connection nil)))
It happened once in development that after a postgres io error, the connection would close and would render the app db-less. How do you guys handle this / what's a typical db component past the simple examples found online?

hiredman17:06:00

use a connection pool library instead using the database connection directly

hiredman17:06:10

c3p0 is a popular choice

yannvahalewyn17:06:22

was thinking about that. Thanks!

spieden17:06:00

should clean up any defunct connections for you, with more and less aggressive options

fabrao17:06:19

Hello all, how can I use something like this:

'([:command "upper"] [:command "reverse"] [:command "remove-vogal"]) ;; this is the commands that I have to apply to collection
I thougth doing defmulti like: 
(defmulti command (fn [[_ command] _] command))
(defmethod command "upper" [command string] (upper string)) ...
["string nubmer 1" "string nubmer 2" "string nubmer 3"] ;; is the collection
and I want to have the results in the end. I coudn´t figure out how to do this with threading macro, Is there possible?

ordnungswidrig17:06:47

The defmulti and defmethod look ok. And threading is possible in general. Maybe you can past an example invokation?

fabrao17:06:55

well, that´s the problem how to apply the rules to collection and get the result : ["1 RBMN GNRTS" ... ]

fabrao17:06:53

(reduce #(conj %1 (command %2 collection) [] '([:command "upper"] [:command "reverse"] [:command "remove-vogal"]))?

fabrao17:06:52

I think this doesn´t pass the result to another, correct?

captainlexington17:06:55

@fabrao It sounds like you want a reduce over the seq of commands. seq of strings is the initial value; each pass maps command over the seq of strings

fabrao18:06:36

In this case I´m runing each command to a collection

fabrao18:06:05

my needs is run all command to each element

fabrao18:06:47

how can I use dynamic transform for each element? something like (-> element (commands ?))

captainlexington18:06:27

That is what a reduce would do, if I understand you correctly

captainlexington18:06:28

(reduce 
  #(map
      (command %1)
      %2)
   [seq-of-commands]
   [seq-of-string])

captainlexington18:06:24

Only I think I got the order of the args passed to the reducer wrong

captainlexington18:06:38

Also I am not sure the dispatch syntax is correct, but that's the basic idea

captainlexington18:06:52

Whoa that's actually what you wrote above and I guess I wasn't paying close enough attention.

captainlexington18:06:04

@fabrao What didn't work about the snippet you sent earlier?

fabrao18:06:29

@captainlexington I think you trick is correct, I´ll give a try, thank you

lxsameer20:06:21

hey guys, I'm looking forward to design an extensible library. but I'm not sure which is the best approach to it, do you know any reading matterial about this ?

eriktjacobsen20:06:04

What's the library's purpose?

lxsameer20:06:44

a web framework

zilti20:06:32

hides behind corner Frameworks are evil.

lxsameer20:06:44

@zilti what do you mean ?

tanzoniteblack20:06:23

@lxsameer if you haven’t already, you should give lispcast’s recent article series on clojure webframeworks a read: http://www.lispcast.com/why-web-frameworks , http://www.lispcast.com/arguments-against-frameworks , & http://www.lispcast.com/clojure-web-framework

hcarvalhoaves20:06:23

@lxsameer best library possible is a bunch of little functions that compose correctly (e.g. a domain-specific algebra)

lxsameer20:06:54

@tanzoniteblack thanks, I'll watch them

hcarvalhoaves20:06:37

maybe one practical example is something like XPath vs. Lenses for traversing data structures

hcarvalhoaves20:06:21

if you design w/ XPath in mind, the API will look one way, w/ Lenses probably another

hcarvalhoaves20:06:25

and will compose differently

hcarvalhoaves20:06:33

(or not at all)

lxsameer22:06:12

@tanzoniteblack are you the author ?

lxsameer22:06:24

it's a good material, but i'm not agree with some of those ideas

Alex Miller (Clojure team)22:06:47

If one thing is clear, it's that we have both too many and not enough frameworks

lxsameer22:06:48

@alexmiller yeah that's true, At the end of the day frameworks are just tools, there are lots of good and bad tools around

lxsameer22:06:56

I don't think that not using a framework makes you an expert. It might makes you a fool because your trying to go to a war with a water pistol

spieden23:06:16

my experience with frameworks is that you trade potentially getting boxed in by constraints later for a quicker start on a project

mobileink23:06:01

define "framework". to me, something that works, until it doesn't. massive pain ensues.

spieden23:06:01

good trade if the project doesn’t grow and change i guess

spieden23:06:24

yeah seems like there’s a list of qualifications to me

spieden23:06:58

big one is the framework code implements your -main and controls initialization and lifecycle stuff

spieden23:06:20

maybe baked in libraries for handling each task (data mapping, routing, caching, rendering, etc) that’re hard to change out would be another

mobileink23:06:19

fwiw, when i hear "framework", i think monolithic, non-compositional blob-o-stuff.

spieden23:06:29

yeah. more up front pain to compose/integrate a bunch of single purpose libraries but tends to pay off

mobileink23:06:16

composing libs (components) - way better, in general. problem tends to be docs.

mobileink23:06:57

you can't be expected to doc every possible use of your lib.