Fork me on GitHub
Lucas Félix01:04:54

Hey! I'm just curious about one thing... I was taking a look at the count code and I found a call to a method ret1 ( this method seems to be used just to make the value of arg null, by calling like this: ret1(blah, blah = null). Does anyone know the reason for the existence of this method? why not just make something like:

o = null;
Or even not change the value of  o because it’s local and it’s going to disappear when the method finishes its execution.

Alex Miller (Clojure team)01:04:46

it's how locals clearing works

👍 8
Lucas Félix10:04:26

Hi Alex! Sorry if I'm being annoying, but I'm just curious. Why is it necessary to make this clearing? The local variable will not just disappear anyway?

Alex Miller (Clojure team)13:04:50

it's pretty tricky. the big thing we want to avoid is a strong gc reference to the head of a seq, and locals are treated as strong gc reference. So the ret1 trick has two parts to it - calling with the value and returning it turns the local into a stack value, and the second arg is unused but gives a convenient place to drop the statement that nulls out the local

Alex Miller (Clojure team)13:04:53

some of this same work is also done by the compiler when it generates bytecode, but this is a handy tool to use for this problem in the Java code parts of Clojure


I got a little stuck with reagent with a cljs snippet below. Can someone explain this behavior? I am experimenting with (hello-world) vs [hello-world]. The document renders in both cases, but h1 is only updated if I use [hello-world]. According to documentation, the second parameter of render can be vector of hiccup syntax. That's why I planned to just simply encapsulate into a function, and return with the vector. I think this is what is called form-1. I have read 1. Yes I am using ratom through import reference. 2. I do deref with @number. 3. My state is global. 4. It is not inside a seq. So to my understanding (hello-world) should work. Tried with reagent 0.8.1 (slightly modified code do to import changes) and 0.10.0 too without success. What am I missing?

(ns ^:figwheel-hooks proba.core
   [goog.dom :as gdom]
   [reagent.dom :as rdom]
   [reagent.core :as reagent :refer [atom]]))

(defonce number (atom 0))

(defn hello-world []
   [:h1 @number]
   [:button {:on-click #(swap! number inc)} "inc"]])

 [hello-world] ; vs (hello-world)
 (gdom/getElement "app"))


I’m not sure how it works for [hello-world] (i’d be keen to know!) but when you use (hello-world) I imagine that expression is being evaluated first, at compile time, including the deref hence being stuck with your initial value.

☝️ 4

Thanks. That would explain indeed. Maybe the atom has some runtime initialization code that is prerequisite for linking the atom and the dom object together. Just the atom being global may not be enough.


I’m really keen to understand this - I started looking through the reagent source (for reagent.dom/render) and couldn’t see where this linking occurs as I had the same hunch


See the source here: Maybe hello-world will work? (without the parens)


I am in the same boat. Could not figure out what is happening in the source.


Without parens, it is not updating, but still rendering as the others


There is a #reagent channel. You might find better luck there.


There is also #clojurescript


Your question is very targeted and the #beginners channel might not have the right audience who can answer.


Right, thanks. I try those channels.


what can I use for neovim to format clojure code? I am using devcards, not a REPL

Michael J Dorian13:04:00

I use cljfmt, which can be activated manually with lein but also has a vim plugin. The plugin sometimes messes up my git diffs by changing it's mind on indentation for functions I haven't touched, but it's pretty good and I just run the proper lein version before I commit

👍 4

I checked it out but I ended up using parinfer-rust. Not because it's better, I really can't tell yet, I knew about parinfer and I like rust, I was curious. Also seemed like a more recent thing.


clojurescript* technically speaking


if you don't get a response here, you might try #vim

💚 4
Gabriel Saliev12:04:14

Hello, I'm having a problem with conversion from float to long (long (reduce + (map #(Math/pow % 17) (digits 21897142587612075)))) => 21897142587612072 this number is narcissistic so the output should be the same as the input, can somebody give me an idea whats happening?


user=> (long (Math/pow 9 17))
user=> (apply * (repeat 17 9))


the problem is you get into float territory which can represent larger numbers but at the cost to precision


maybe rely on double for double-precision float then?


Math/pow returns a float so that's not a great candidate here


oh sorry. it returns doubles. but still the same problem


Use math.numeric-tower or write your own exponentiation without floating point math. A simple (defn pow [a e] (reduce * (repeat e a))) should to the trick despite being linear-time.


an "off by three error," nice!

👍 4
Gabriel Saliev13:04:21

It converts all the digits of a number into a vector (defn digits [n] (if (pos? n) (conj (digits (quot n 10)) (mod n 10) ) []))


Nice! This works too:

(defn digits [n]
  (->> (iterate #(quot % 10) n)
       (take-while (complement zero?))
       (map #(rem % 10))
And this:
(defn digits [n]
  (map #(Character/digit % 10) (str n)))
Not for negative nums of course.


pretty implementation


yeah maybe just changing long to double will be enough?

Gabriel Saliev13:04:19

I'm not sure for which part about the code you are talking about, can you specify? thanks!

Gabriel Saliev13:04:02

I managed to narrow the problem to off by 1 😆 (long (reduce + (map #(long (Math/pow % 17)) (digits 21897142587612075))))


this is exactly your problem here:


user=> (long (Math/pow 9 17))
user=> (apply * (repeat 17 9))

👀 4

I think the solution here is don't use Math/pow ?

sova-soars-the-sora15:04:56 has many useful math functions (that won't munge in coercion) or you could just make your own iterative multiplier fn to exponentiate.


I think the solution here is don't use Math/pow ?

sova-soars-the-sora15:04:56 has many useful math functions (that won't munge in coercion) or you could just make your own iterative multiplier fn to exponentiate.

Jim Newton16:04:01

Is there a way to catch a certain error ONLY IF it satisfies some predicate other than the exception type?

Alex Miller (Clojure team)16:04:52

no, that's a constraint of the JVM

Alex Miller (Clojure team)16:04:19

there are some libraries like slingshot that provide more sugar around ExceptionInfos

Jim Newton16:04:45

In my application, I have a recursive functions, and in some cases an exceptional situation occurs which I can handle at the call site.

Jim Newton16:04:52

Other times the exception cannot be handled.


everyone who reads your code will understand an if statement inside a catch statement with a rethrow 🙂

Jim Newton16:04:45

I'm currently using ex-info , so at the call site I need to do a (try ... catch) and somehow detect the fixable one, otherwise don't catch.

Jim Newton16:04:15

is rethrow the thing? but then the stacktrace will be wrong. right?

Jim Newton16:04:42

Or should I create my own exception type and catch that?

Jim Newton16:04:02

can I create a subclass of ExceptionInfo and use that to distinguish the fixable case from the others?

Jim Newton16:04:00

Rather than throwing an exception, I could just call the handler function directly. I could dynamically bind the handler function at the call site.

Jim Newton16:04:25

This would have the handler called without unwinding the stack.

Alex Miller (Clojure team)16:04:18

you can rethrow with the original stack

Jim Newton16:04:02

how can I do that?

Alex Miller (Clojure team)16:04:12

just throw the thing you caught

Jim Newton16:04:30

ah ok. I'll give it a try.

Jim Newton17:04:16

in Scala in such a situation, I can tell the original throw NOT to create a stacktrace, because I know I'm going to handle it.

Jim Newton17:04:20

Can I do that in clojure?

Jim Newton17:04:52

It doesn't change the semantics, but it is faster, as the system doesn't have to bother building a stacktrace which is expensive in heavy recursion cases.

Alex Miller (Clojure team)17:04:35

you can construct an exception object without a stack trace (or even cache a static one - which I have totally abused when using exceptions as control flow)

Alex Miller (Clojure team)17:04:17

not really any difference here between Java/Scala/Clojure - they are all working from the same toolbox

Alex Miller (Clojure team)17:04:04

none of that stuff above is normal or the default, so more steps are required

Jim Newton17:04:01

I need to re-think how I want to handle this. It's getting complicated.

Alex Miller (Clojure team)17:04:58

I think to get the suppression, you have to subclass Throwable and have the constructor call the one Throwable constructor that takes the enableSuppression flag to avoid fill the stack trace. That's all a pain to create in Clojure (concrete derivation is intentionally not easy).

Jim Newton17:04:15

I think I need to screen share with a clojure expert to ask how to handle this situation. Or perhaps I need to sleep on it and come back tomorrow.

Jim Newton17:04:33

The situation is that I want to calculate a "derivative" with respect to some "foo". Does not matter what foo is for this example.

Jim Newton17:04:57

the derivative function is heavily recursive, and sometimes when it gets to a leaf level, it figures out that "foo" is too big and needs to be split. the leaf code which figure this out knows how to suggest splitting foo into two or three pieces, at which case the caller of derivative needs to retry with the two or three pieces.

Jim Newton17:04:21

I could figure out the splitting at the call site but it would end up being much more work.

Jim Newton17:04:26

Currently derivative is called within a call to (reduce (fn [...] ... (derivative x wrt)) [initval] all-wrt-values)


inside reduce, you can call reduced to short-circuit


if you need to stop consuming elements of all-wrt-values and exit the reduce early

Jim Newton17:04:09

@noisesmith. That is a really great feature, but does not apply to my situation now. I want continue reducing, it is just one call to derivative which needs to try again.

Jim Newton17:04:28

That Being Said, I will definitely use reduced in other situations!!!

Jim Newton17:04:35

Thanks for the great suggestion

Jim Newton17:04:44

Sorry that it doesn't help now though 😞

Jim Newton17:04:28

I think I'll sleep on it and try tomorrow ... it's time to cook supper.

Jim Newton17:04:43

and my cats are begging for their supper as well.


I don't think I understand what is being done to the stack trace by catching and rethrowing that concerns you


right, the re-throw is happening from inside the same stack, it won't be misleading


re-throwing from inside catch is a preferred idiom