Fork me on GitHub
#clojure
<
2020-03-01
>
pinkfrog10:03:11

(Math/pow 2 1/2)

vemv10:03:00

Given:

(defn foo []
  (Math/pow 2 1/2))
...I can use clj-java-decompiler and get an answer:

vemv10:03:16

// Decompiling class: eastwood_warning$foo
import clojure.lang.*;

public final class eastwood_warning$foo extends AFunction
{
    public static final Object const__0;
    public static final Object const__1;
    
    public static Object invokeStatic() {
        return Math.pow(RT.doubleCast(const__0), RT.doubleCast(const__1));
    }
    
    @Override
    public Object invoke() {
        return invokeStatic();
    }
    
    static {
        const__0 = 2L;
        const__1 = RT.readString("1/2");
    }
}

pinkfrog10:03:22

how does clojure auto convert 1/2 from ratio to double ?

pinkfrog10:03:57

does that mean, we can write auto type conversion functions inside java ?

lmergen10:03:20

hey all, i'm trying to figure out a generic way to propagate dynamic bindings onto a defrecord's functions. in essence, what i would like to do is replace all functions in a defrecord with ones wrapped in bound-fn. does anyone know of a good example what the best approach for doing this is? it seems various mocking libraries don't work with protocols / defrecord, so it appears that it's tricky to do?

vemv11:03:25

This piqued my interest. However I'm not able to reproduce the issue as I undestand it - I do get 42 being printed:

(defprotocol P
  (do-it [this]))

(def ^:dynamic *dyn* nil)

(defrecord R []
  P
  (do-it [this]
    (println *dyn*)))

(binding [*dyn* 42]
  (-> (R.) (do-it)))

lmergen11:03:17

it doesn't work when you pass around the record as value, thus losing the dynamic thread bound variables

4
lmergen11:03:27

i.e. you pass the record to some asynchronous processing tool

lmergen11:03:54

usually one would wrap the callback functions using bound-fn, but with records/protocols this is a bit more tricky

vemv11:03:13

Interestingly, the following prints nil:

(let [record (R.)]
  (binding [*dyn* 42]
    (-> (Thread. #(-> record (do-it)))
        .start)))
...but if I change the Thread. for a future, I get 42 printed

vemv11:03:44

IOW: vanilla defrecord can work - maybe the problem is in the concurrent tool instead

vemv11:03:50

core.async loses bindings for sure

lmergen11:03:49

yes this is an issue "by design", dynamic bindings are not supposed to automatically propagate. this is why clojure provides functions bound-fn, bound-fn* and with-conveyed-bindings, and i'm now struggling to figure out how to use these in combination with records/protocols

vemv11:03:45

I'm not sure bound-fn will make arbitrary concurrent facilities work. Still, you may want to play with metadata extension:

(defprotocol P
  :extend-via-metadata true
  (do-it [this]))

(def ^:dynamic *dyn* nil)

(defn make-record []
  ^{`do-it (bound-fn [this]
             (println *dyn*))}
  {:id  42
   :age 60})

(binding [*dyn* 52] (-> (make-record) (do-it)))

lmergen11:03:48

:thinking_face:

lmergen11:03:02

this seems crazy enough that it might work

😂 4
lmergen10:03:49

one approach i'm thinking of is creating an entirely new type, and use extend-protocol for each function with the exact same signature

p-himik11:03:17

One common approach (albeit, it's probably based on different considerations) is to make all record functions "private" (start the names with -) and instead call them from regular functions in the same namespace.

lmergen11:03:59

hmmm but doesn't that mean that then the record itself don't contain the bindings anymore, thus losing the ability to just pass around the record as value ?

lmergen11:03:44

i'm almost inclined to implement a wrapper aorund the defrecord macro itself for this

p-himik11:03:14

Or maybe I misunderstand the question, given your response in the other thread. Sorry, I meant something like

(defprotocol P
  (-f [this]))

(defrecord R [a b c]
  P
  (-f [_] ...))

(defn f [r]
  (-f r))

p-himik11:03:38

And the dependants use the public f function.

lmergen11:03:50

right, but wouldn't it mean if i pass r through some async context / to another thread, it loses any dynamic bindings ?

lmergen11:03:29

what i am looking for is a way for r to automatically propagate these bindings

p-himik11:03:25

A, so you don't want to manually use bound-fn in f, you want just to say something like (with-all-bound-fn rec)?

lmergen11:03:06

exactly this

lmergen11:03:31

something like (with-conveyed-bindings (map->MyRecord {...}))

lmergen11:03:43

(defrecord WithConveyedBindings [bindings that]

  p/MyProtocol
  (start! [this]
    (with-bindings [bindings]
      (p/start! that))))


(defn with-conveyed-bindings [that]
  (let [bindings (get-thread-bindings)]
    (map->WithConveyedBindings {:bindings bindings
                                :that that})))
this shows at least how it could work, but it requires me to manually implement each protocol function

p-himik11:03:35

Sorry, no idea - even if what you want is possible, it definitely requires a deeper knowledge of Clojure than I have right now. :) The only thing I can add is that dynamic bindings are evil. :D

lmergen11:03:09

they are evil, but sometimes very convenient

lmergen11:03:34

in my case, i want to add dynamic metadata to the logs my application generates

lmergen11:03:11

which is pretty much the canonical use case for dynamic bindings

pinkfrog15:03:10

i don’t quite understand datomic. does it often latency guarantee when the app scales out?

pinkfrog15:03:02

seems like I need to run a datomic server process on some ec2 node, and let the client talk to that server process.

seancorfield17:03:02

@i There's a #datomic channel where folks can probably help you more.

tvalerio17:03:39

Has anyone worked with social logins with Clojure? Is there a framework to handle it easier? Found this one https://github.com/tiensonqin/clj-social but perhaps there’s another one better…

jsn18:03:34

I didn't, but I'd suggest googling for "clojure oauth"

👍 4
include23:03:25

Hi, http://conj.io is down. I don’t know who is maintaining it so if anyone knows him/her, pretty please ping them 🙂 kthx

seancorfield23:03:52

I thought http://conj.io went offline ages ago?

include23:03:09

@seancorfield I didn’t knew it 😛 I am reading Clojure for Finance book and one chapter mentioned it. menawhile web archive has some snippets of it

include23:03:12

@seancorfield ah ok then. I must find some alternative.

seancorfield23:03:16

I'll caution that most Packt books are terrible, by the way.

seancorfield23:03:45

(that book has three 1-star reviews on Amazon -- and most Packt books are similarly poorly edited)

include23:03:51

@seancorfield oh really? dam it… it was the only one I found on this subject (clojure + finance). Do you know any better?

seancorfield23:03:29

I don't know of any other finance-related Clojure book.

seancorfield23:03:59

That's kind of how Packt operates tho', by finding niche topics to release bad books in, where they have no competition 😞

include23:03:12

@seancorfield I was using oreilly library and it has few clojure books 😞

seancorfield23:03:47

If you're trying to learn Clojure, I'd recommend Clojure for the Brave and True (has a free online version), Getting Clojure, or Living Clojure.

include23:03:16

I have a copy of it 🙂 super good but quite advanced for me (the Brave one)

seancorfield23:03:04

Ah, well... those are the best books for beginners -- everything else will seem even more advanced.

seancorfield23:03:58

But if you have any questions, as you're learning, the #beginners channel here has a lot of people who've opted in to helping folks come up to speed on Clojure (this channel -- #clojure -- tends to lean more to established Clojure devs).

include23:03:38

ok I think I will give it a try on this finance one and then follow your advice.

include23:03:05

Ops sorry to start this http://conj.io thread here. I will sure move to #beginners 🙂 thanks again

seancorfield23:03:50

The only "downside" to Brave & True, in my opinion, is that it tries to teach you Emacs at the same time as teaching you Clojure -- which is a bit overwhelming, I think. If you are comfortable with an editor that already has a Clojure integration, it's probably easier to stick with that and ignore Emacs 🙂

include23:03:02

ahah true - I just jumped that chapter 🙂 I am playing with intelij+cursive