Fork me on GitHub
#clojure
<
2023-08-04
>
didibus02:08:06

Looks like you can't destructure a key called :true ? Because you can't have a local called true? Is there a way in the destructure to call it different?

didibus02:08:44

Nevermind, answered my own question:

(let [{truek :true} {:true 10}]
  truek)

duckie 6
hifumi12303:08:13

yup… its easy to overlook that {:keys [foo bar baz …]} is syntax sugar over the original map destructuring syntax

Joshua Suskalo16:08:05

the trouble is that true isn't a symbol, which means that you cannot bind something to that name

Joshua Suskalo16:08:24

You can construct a symbol with the name true but it cannot be read as a symbol

onetom04:08:18

im looking an clojure.data.xml/parsed maps with namespaced tags and attribtues, like:

{"A-A" {:name "A-A",
        :sheetId "5",
        :xmlns.http%3A%2F%2Fschemas.openxmlformats.org%2FofficeDocument%2F2006%2Frelationships/id "rId5"},
is there a way to pretty-print such data with namespace aliases? like
{"A-A" {:name "A-A",
        :sheetId "5",
        ::rels/id "rId5"},
i'd be very happy to maintain some singleton with canonical namespace alias registry to achieve this...

Alex Miller (Clojure team)11:08:36

the registry exists as aliases in the current Namespace object already and you can see those via ns-aliases . the bigger problem is that the printer doesn't print keywords with those aliases

onetom11:08:01

this data comes from an XML file, so there are no NS aliases for it, that's why i mentioned that i'd be happy to maintain a mapping myself, just want a printer which can understand such a mapping 🙂

Alex Miller (Clojure team)11:08:53

I see, have you tried parsing with :namespace-aware set to false? not sure if that would give you something easier to work with

onetom11:08:37

i haven't tried that flag, because i've assuemed it would just drop the NS, but i DO need the NS, so i can roundtrip the XML data

rolt11:08:05

if it's for dev workflow you can adapt this:

(comment
  (defmethod print-method clojure.lang.Keyword [o ^java.io.Writer w]
    (if-let [k-ns (namespace o)]
      (if-let [k-ns-alias (some (fn [[alias the-ns]]
                                  (let [ns-str (str the-ns)]
                                    (when (= ns-str k-ns) alias)))
                                (ns-aliases *ns*))]
        (.write w (str "::" k-ns-alias "/" (name o)))
        (.write w (str o)))
      (.write w (str o)))))

🙏 2
Alex Miller (Clojure team)12:08:22

but note that this affects the printing of keywords everywhere

👍 2
onetom12:08:42

might still be a good stop-gap solution, just need to have a way to reverse its effect

rolt12:08:47

eval (defmethod print-method clojure.lang.Keyword [o ^java.io.Writer w] (.write w (str o))) 😅

rolt12:08:28

you could also add a conditionnal on a dynamic var in the method body

frozenlock13:08:50

https://cljdoc.org/d/org.clojure/core.cache/1.0.225/doc/composing It's interesting to see that caches can be composed. Quickly glancing at the source, it looks like cache states are invisible outside of the cache object. Am I correct in concluding this means those caches can only be composed while they stay in memory? For example, using https://github.com/michaelklishin/monger/blob/master/src/clojure/monger/cache.clj would NOT store the state of the other caches?

hiredman14:08:53

CacheProtocol is intended for immutable caches, so implementing it on top of mongodb, now you have 2 problems: your immutable thing is mutable, and you're using mongodb

frozenlock14:08:30

In most cases the caches are put into an atom to make them useful. And my question would remain the same if the storage backend was postgresql.

hiredman14:08:14

Same problem, CacheProtocol is for immutable caches

hiredman14:08:52

If you put a mutable implementation of CacheProtocol in an atom, it won't work correctly because swap! can run what you pass in more than once

hiredman14:08:48

Wrapping an atom around immutable things and implementing an API for immutable things directly on a mutable thing is not the same thing at all

frozenlock14:08:47

The immutability looks tangential to my question. Caches return a "new" updated cache. That we store it in an atom or a DB is an implementation detail. swap! can retry the functions, which is why they must be free of side-effects. But it's not a property of the caches. Also, from the docs: "Caches are generally immutable and should be used in conjunction with Clojure's state management, such as atom. SoftCache is the exception here, built on top of mutable Java collections, but it can be treated as an immutable cache as well."

frozenlock14:08:57

So to come back to my question, it looks like many of the implementations in core.cache cannot be serialized, which is why, as far as I can tell, they can't be used with durable backends.

frozenlock14:08:37

> Wrapping an atom around immutable things and implementing an API for immutable things directly on a mutable thing is not the same thing at all Okay, thinking more about it I see the difference now. A mutable cache could change under the other cache layers and screw things up...?

Drew Verlee17:08:02

I'm trying to understand what this error message is telling me:

Unhandled clojure.lang.ExceptionInfo
   Invalid keyword: ::tenant/enable-recalls?.
   {:ex-kind :reader-error, :type :reader-exception}
How would I reproduce this? evaling ::tenant/enable-recalls? gives me an "invalid token", which isn't the same error. Is the error telling me that where that keyword is being evaled without it's namespace (::tenant)? The stacktrace that leads to this error ends at clojure.tools.reader.impl.errors/throw-ex` and ends in my application code at this function:
(defn restart!!
  []
  (reloaded.repl/suspend) ;; stop/suspend all components
  (c.t.n.r/refresh) ;; reload all clojure code
  (start!!)) ;; start is more or less reloaded.repl/set-init! followed by reload.repl/go 
Neither of which directly (visible) interact with that keyword, so i'm not sure what the context is where this is happening.

seancorfield17:08:50

Perhaps the refresh has zapped the ns that tenant was aliased to and the context for ::tenant/enable-recalls? is no longer valid somehow. (I was just saying in another thread that I have always avoided the reload/refresh stuff because of edge case failures like this)

👀 2
hiredman17:08:33

the difference in errors is one the invalid token error is from the clojure reader, the invalid keyword error is from tools.reader

hiredman17:08:50

so something is trying to read something that contains the keyword using tools.reader, in a context where *ns* is not bound to a namespace where the appropriate namespace exists

Drew Verlee17:08:08

thanks @U04V70XH6 i'll ponder that a minute after i fix this. thanks @U0NCTKEV8 that makes sense, I'll just have to find where the keyword is read where the ns isn't bound.

hiredman17:08:56

it isn't that *ns* isn't bound, it is that it is bound to a namespace where the alias doesn't exist

Drew Verlee17:08:01

Right, i suffer from not being sure how much exposition is worth giving laughcry To clarify and confirm by example, the idea is that this would work: (ns foo (:require [centriq-web.tenant :as tenant])) ::tenant/enable-recalls? This would not: (ns foo) ::tenant/enable-recalls? ... (i hope that's right) The interesting bit in this case is that that it's happening via tools refresh, which i don't use nearly as much. (maybe, as sean suggests, that's ideal) But i'm not sure how to get away with the workflow i want (update a server endpoint so i can use it to get changes on my client) without going this route.

hiredman17:08:44

you need to figure out what is calling tools.reader

hiredman17:08:53

ah, of course tools.namespace uses tools.reader, so could be that

👍 2
hiredman17:08:20

do you have any random .clj files on the classpath that just contain like a map or something, and don't actually start with a ns form?

practicalli-johnny18:08:05

Is it failing because the keyword is being qualified twice? Once explicitly with tenant and implicitly with the current namespace via :: :tenant/enable-recalls? I assume is the correct form Or have I missed something?

hiredman18:08:15

:: allows you to resolve keywords via aliases that the current value of *ns* has

Drew Verlee03:08:53

It ended up being because of a file called centriq-web.graphl_scratch that had this:

(in-ns 'centriq-web.graphql-service)
(require '[centriq-web.tenant :as tenant])
...
::tenant/enable-recalls?
I suspect some combination of in-ns and the require not being in the namespace macro caused the keyword to not be in scope.