Fork me on GitHub
#clojure
<
2022-09-04
>
didibus04:09:06

To avoid using potemkin, for functions I know I can just do:

(def foo impl/foo)
Does this work for macro as well?

didibus04:09:47

Can't take value of a macro

borkdude09:09:14

(def ^:macro foo @#'impl/foo)

☝️ 1
didibus20:09:39

I've noticed there's a few other annoying things with this approach, it doesn't copy the documentation, and then calling source at the REPL won't show it, etc. 😞 Right now I'm trying the odd approach of splitting the same namespace across many files, which has downsides in my linting 😛, but decluters my files. Maybe I'll end up moving the entry function all into one file and go with the _impl namespace approach once I'm done, but this also annoys me a bit, because if I need to work some more on them, I don't like having the entry function elsewhere when I modify the impl and I want to test things its more annoying to call into a different namespace.

borkdude20:09:32

You can copy the metadata to the new var as well

borkdude21:09:00

(alter-meta! #'foo (constantly (meta impl/foo))

didibus21:09:11

:thinking_face: that would solve the doc-string issue, would this also make clojure.repl/source work?

borkdude21:09:26

but yeah, this is a common problem. I usually prefer to have the docstrings in the API namespace and just refer to those when you want to read the docs

didibus21:09:28

I guess it's not the end of the world if people need one more hop to see the real source

borkdude21:09:49

I think it would work even, since source looks up stuff via metadata

didibus21:09:19

Cool, ya I'll try it, not sure which option I'll end up with in the end, but nice to know what all the options are

borkdude21:09:45

I tried this and it works:

(ns foo)

(defmacro foo [])

(ns bar (:require [foo]))

(def foom @#'foo/foo)

(alter-meta! #'foom (constantly (meta #'foo/foo)))

(prn (meta #'foom))

(require '[clojure.repl])

(clojure.repl/source foom)

borkdude21:09:10

Note that this only works in the JVM, but potemkin already doesn't work with CLJS anyway

borkdude21:09:53

it also works in bb, just tested it ;)

didibus21:09:37

Side question, since I have your attention. What do you do to walk a form and maintain meta, since clojure.walk doesn't? I'm using riddley instead, but ztellman doesn't maintain the repo actively anymore, I wonder if there's a small change I can make to my use of walk to add it back myself or some other lib

borkdude21:09:44

I wrote my own

borkdude21:09:00

I even have a patch for that issue in jira

didibus21:09:19

I see haha

didibus21:09:28

Ya, I saw your patch, hope it gets merged soon

didibus05:09:26

Hum, is there a workaround until this patch: https://clojure.atlassian.net/browse/CLJ-2568 ??

lilactown16:09:06

(defn nav'
  [x k]
  (nav x k (get x k)))

(defn nav-in
  [x path]
  (loop [x x
         path path]
    (if-some [k (first path)]
      (let [x (datafy x)]
        (recur (-> (nav x k (get x k)))
               (rest path)))
      x)))
I'm curious if anyone knows an example where these helpers wouldn't be useful?

❤️ 1
lilactown16:09:21

when using datafy & nav programmatically, I mean

lilactown16:09:04

used like

(-> (datafy foo)
    (nav' :bar)
    (datafy)
    (nav' :baz)
    (datafy)
    (nav-in [:asdf :jkl :qwerty :uiop])
    (datafy))

Rand_Om21:09:38

Hey there 👋. Is anyone aware of a package that allows me to register validators around functions that allow me to check for invariants. I want to be able to implement my domain functions without having to consider invalid state or bad input while still handling errors in a kind of robust way. Something like this:

(defn attack [game-state, attack-info] (...stuff...))
(defguard attack [game-state, attack-info] 
  (and
    (is-valid-game-state? game-state)
    (not (is-dead? game-state attacker-id)) 
    (not (is-dead? game-state defender-id)) 
    (is-turn-of? game-state attacker))

(attack game-state attack)         ;; new-game-state
(attack game-state invalid-attack) ;; !invalid-game-state!

(valid? attack game-state attack)         ;; true
(valid? attack game-state invalid-attack) ;; false

(guarded attack game-state attack)         ;; :ok new-game-state
(guarded attack game-state invalid-attack) ;; :err error

(guarded! attack game-state attack)         ;; new-game-state
(guarded! attack game-state invalid-attack) ;; throw Err

phronmophobic21:09:18

Additionally, functions have builtin support for pre and post conditions, https://clojure.org/reference/special_forms#_fn_name_param_condition_map_expr

plus_one 2
vemv16:09:53

Just in case, :pre and :post are not meant for production usage (which is presumably what is wanted by "domain invariants")

amithgeorge08:09:04

> Just in case, :pre and :post are not meant for production usage Why is this?