Fork me on GitHub
#clojure
<
2018-06-15
>
waffletower03:06:03

Here is an example of an intended use for the macro I asked about above. I was looking for a way to evaluate an expression in-place once at compile time such that I didn’t need to bind it to a symbol with def. In this case, I didn’t want the extra overhead of calling .toString on several java objects everytime I performed a comparison. I also wanted to let the java api decide what constant to use:

(defmacro inline [form] (eval form))
(condp = status-string
  (inline (str QueryExecutionState/FAILED))
  (do-something :im-a-failure)

  (inline (str QueryExecutionState/CANCELLED))
  (do-something :my-show-was-cancelled)

  (inline (str QueryExecutionState/SUCCEEDED))
  (do-something :lottery-as-retirement-investment-succeeded))

waffletower03:06:25

macroexpansion of (inline (str QueryExecutionState/FAILED)) is:

(macroexpand '(inline (str QueryExecutionState/FAILED)))
"FAILED"

benzap20:06:01

It would be interesting if this could be profiled with and without the inline-compilation, and determine whether the Java compiler is smart enough to inline this automatically when it uses it at runtime. I might steal this idea!

dpsutton03:06:23

do those values not exist at runtime? or perhaps they change?

dpsutton03:06:33

i'm having trouble understanding when (inline (str QueryEx../FAILED)) wouldn't be just whatever value of QueryEx../FAILED

waffletower03:06:55

It would be, as the macroexpansion shows

waffletower03:06:41

The intent is to evaluate at compile time

dpsutton03:06:09

i have no idea what problem you're solving so i'm not saying its wrong. just curious

waffletower03:06:08

Yes, it’s just an optimization. Avoiding both the pointer chasing and any repeated execution of the form.

dpsutton03:06:03

i think you could get the same "memoization" from just putting them in a let above the defn of this and reusing them like that. and if you are optimizing pointer derefence of strings in clojure your life must be extremely hard

😀 4
dpsutton04:06:03

the emitter will put those in a variable anyways i bet, right? so you don't save a lookup anyways

dpsutton04:06:11

(pure guess there, but feels right)

waffletower04:06:11

optimizing the dereference isn’t what motivated me, but optimizing the arbitrary computation in the form did. And not wanting to have to name yet another thing

dpsutton04:06:19

(let [failed (expensive-computation)]
  (cond status
        failed (react-whatever)))
could something like this help you get the same?

dpsutton04:06:26

ahhh. i got you

OliverM09:06:11

Is there any way to supply a predefined vector of keys to a destructuring bind of a map? Something like:

(def test-keys [:one :two])
(let [{:keys test-keys} {:one 1 :two 2 :three 3}] (str one " " two))

OliverM09:06:58

That's a nonsense example, in reality I've a much larger vector of keys I'd like to supply

OliverM10:06:16

It fails the spec test in Clojure 1.9 which asserts the argument to keys has to be a vector

sundarj10:06:45

@oliver.mooney let is a macro, so the only ways to do what you want are either to write another macro wrapping it, or use eval

sundarj10:06:59

=> (eval `(let [{:keys ~test-keys} {:one 1 :two 2}] (str ~'one " " ~'two)))
"1 2"

👍 4
OliverM10:06:49

@sundarj thanks for the pointer, I was wondering if I'd have to write a macro and my macro-fu is... lacking 😅

sundarj10:06:17

yeah, eval is definitely the path of least resistance 😁

😁 4
OliverM10:06:14

Thanks, I've been looking at that and Riddley too, not the first time I've felt the need for macros but they never go quite how I expect

4
hkupty13:06:48

Anyone can recommend a good arcticle/tutorial on deps.edn? I'm struggling to get things working, so I might be missing something...

Alex Miller (Clojure team)14:06:07

but feel free to ask more specific question in #tools-deps

👍 4