This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-03-26
Channels
- # announcements (1)
- # autochrome-github (1)
- # babashka (9)
- # beginners (112)
- # bristol-clojurians (2)
- # calva (26)
- # cider (10)
- # clj-kondo (31)
- # cljs-dev (40)
- # clojure (114)
- # clojure-austin (1)
- # clojure-dev (112)
- # clojure-europe (22)
- # clojure-germany (5)
- # clojure-italy (1)
- # clojure-nl (2)
- # clojure-norway (1)
- # clojure-spec (10)
- # clojure-uk (96)
- # clojurescript (39)
- # core-logic (5)
- # datomic (40)
- # fulcro (34)
- # graphql (17)
- # jobs (3)
- # kaocha (4)
- # leiningen (10)
- # luminus (1)
- # malli (3)
- # meander (44)
- # midje (2)
- # off-topic (40)
- # pathom (5)
- # re-frame (8)
- # reitit (8)
- # ring (3)
- # ring-swagger (4)
- # shadow-cljs (83)
- # spacemacs (96)
- # tools-deps (16)
- # vim (4)
- # xtdb (15)
- # yada (20)
Does anyone know why this doesn’t work on Spec 2 - or more likely, what I’m doing wrong? 🙂
(s/valid? (s/and string? (complement str/blank?)) “Hello”)
>Execution error (IllegalArgumentException) at clojure.alpha.spec.protocols/eval14632$fn$G (protocols.clj:11).
No implementation of method: :conform* of protocol: #’clojure.alpha.spec.protocols/Spec found for class: clojure.lang.PersistentListYou can’t use complement like that with spec 2 - it needs to be explicitly wrapped into a spec with s/spec
Or you could use an anonymous function there too
Gotcha! Thank you, Alex.
anonymous functions are explicitly handled as symbolic specs
Ah okay. I should have read the wiki with more attention. One other thing, does select sub-selections should work for nested unqualified keywords? The examples on the Wiki use qualified keywords, but then I try to nest sub-selections with unqualified keywords and it seems to only work for the “first level”.
Take this one for example
(s/select ::user [::id ::addr {::addr [::zip]}])
If we use an unqualified :addr
and :zip
, the spec doesn’t validate, or require, the`:zip` key.I think there is a bug in this area, someone else had a similar case
there are several outstanding bugs in the schema/select stuff
Ah alright then. I was wondering what I was doing wrong.
using unreleased software :)
Yep, schema
and select
are too nice 🙂
Well, thank you very much, Alex.
Whereas this works:
(s/valid? (s/and string? #(not (str/blank? %))) "Hello")
Hi all, I generate a class like this:
(ns logging.logback-stackdriver-pattern-layout
"Logback PatternLayout that logs in Stackdriver JSON format to stdout.
It masks sensitive data with replacements from the pattern->replacement map."
(:gen-class
:extends ch.qos.logback.classic.PatternLayout
:name logging.StackdriverPatternLayout)
(:require
[cheshire.core :as json]
[clojure.string :as string])
(:import
(ch.qos.logback.classic Level)))
Then in the same project I have an XML logback-gcloud-appender.xml
file that uses that class:
<appender name="GCLOUD" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="logging.StackdriverPatternLayout"/>
</encoder>
</appender>
Then from another project that uses the above project using lein-git-down
. This project also has a logback.xml
and refers to this logback-gcloud-appender.xml
from the project’s resources:
<configuration scan="true" scanPeriod="10 seconds">
<include resource="logback-gcloud-appender.xml"/>
<root level="info">
<appender-ref ref="GCLOUD"/>
</root>
</configuration>
When running the project we see this error:
09:26:03,352 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [GCLOUD]
09:26:03,356 |-ERROR in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Could not create component [layout] of type [logging.StackdriverPatternLayout] java.lang.ClassNotFoundException: logging.StackdriverPatternLayout
at java.lang.ClassNotFoundException: logging.StackdriverPatternLayout
at at .URLClassLoader.findClass(URLClassLoader.java:382)
at at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at at ch.qos.logback.core.util.Loader.loadClass(Loader.java:120)
at at ch.qos.logback.core.joran.action.NestedComplexPropertyIA.begin(NestedComplexPropertyIA.java:102)
Why does the class logging.StackdriverPatternLayout
lead to ClassNotFoundException
? This class should be generated?I include it using lein-git-down
Retrieving project-with-class/21e8b5bc0990eb5321694d38e2a676789426fd7a/project-with-class-21e8b5bc0990eb5321694d38e2a676789426fd7a.jar from private-bitbucket
Created /Users/erooijak/.gitlibs/libs/mediquest-nl/project-with-class/21e8b5bc0990eb5321694d38e2a676789426fd7a/target/project-with-class-0.0.0.jar
Lein git down is a plugin that pulls code from a repository
The jar file that is ought to have the CLJ code - does it have the relevant class
file?
I don’t see it…
It does have the clj file
The plugin then has nothing to do with it. You cannot just package the code that has :gen-class
, you have to compile it. Ahead of time.
I see how can that be enforced?
Likely Lein has some flag or plugin for it that you can use when you bundle the code. I have no idea - I don't use Lein at all.
This fixed it!
:aot [logging.logback-stackdriver-pattern-layout]
Thank you
When working in a codebase, I was suprised that the REPL doesn't seem to pick redefinitions of certain functions; finally I've noticed that it's because they are defined in a hashmap like:
(def w {:fn other.ns/my-fn})
(defn wrapper []
(-> w ...))
;; in other.ns
;; this function is changed and evaled but no changes detected!
(defn my-fn [] ...)
It was very confusing.
Now if I reload the wrapper function / ns I can get new changes but it's not the best workflow and easy-to-forget.
So I changed it to use #'
:
(def w {:fn #'other.ns/my-fn})
Would you say that that's a valid approach?
Note: the wrapper fn isn't called in a tight loopI was aware of a similar issue with closures (e.g. when passing a ring handler to jetty) but this one stills surprised me. Any other contexts that this thing can manifest itself in?
Hmm, not actually vars, but wrapper functions. Same idea though. Vars would be good to test.
It seems that the indirect use via lambdas ended up being a tiny bit faster. Do you have any idea why that might be the case?
Thanks for sharing the numbers; for me it's not really a concern though 🙂. I'm mostly interested in knowing if this is the right thing to do (I assume it is) and then in what other situations it can happen.
@U2FRKM4TW I have no idea! That surprised me too, but I ran a few times to verify.
The common response to your solution is "bad performance", which is why I measured :)
I’d use vars here personally
They’re probably slower than lambdas due to the synchronization they incur
although I guess if you're relying on a lambda call to the function to pick up changes, that has to go through the same synchronization, so not sure off the top of my head
well unless it's a hot spot, I'd say it's probably not worth measuring... :)
there used to be a significant perf issue in calling through vars for variadic functions (iirc) that was fixed in the last few years
that was fixed in 1.9 - before that this case was noticeably slower
@alexmiller are you saying that every call through a defn synchronizes, on the var?
I must be misunderstanding.
getting the value of a var means reading the root value, and access to that field is synchronized (so it can be safely set)
or so, I should say it's a volatile read, not synchronized
ah, thanks, that's better
I see there is an option to avoid the volatile read as well, :direct-linking
, which is nice.
yes - you lose the reference then, but that's fine if you're compiling an app, not at the repl
understood
I can imagine that hotspot may be able to do optimizations with :direct-linking that are not possible without it
such as inlining
definitely
additionally, the compiled classes do not need to load and save the vars during class initialization, so it improves both startup time and execution time
the clojure jar itself is compiled with direct linking
pretty cool that we can have such a dynamic system during dev, and still optimize in this way
Hmm, not actually vars, but wrapper functions. Same idea though. Vars would be good to test.
Are there any libraries that will give me all different paths of a tree? Like tree permutations?
Without knowing too much about what you mean by "tree". You could zip your data structure, walk through it and return the path of each node. https://clojuredocs.org/clojure.zip/path
@U963A21SL I haven't used zip much, what would I use to walk it?
Found this article, thanks for the suggestion! http://josf.info/blog/2014/03/21/getting-acquainted-with-clojure-zippers/
I saw this video, The Art of Tree Shaping with zippers, after reading this thread: https://www.youtube.com/watch?v=5Nm56YvTKZY A good explanation IMHO. Slides here: http://arnebrasseur.net/talks/2018-clojure-zip-denver/#1 Based on those slides, I would find all-paths like this:
(def all-paths
(->> my-zipper
(iterate z/next)
(take-while (complement z/end?))
(map z/path)))
Works like a charm (without a recursive helper function).Playing off your snippet this is what I originally set out to do :
(defn full-path [loc]
(conj (vec (zip/path loc)) (zip/node loc)))
(defn leaf-paths [z]
(->> z
(iterate zip/next)
(take-while (complement zip/end?))
(filter (complement zip/children))
(map full-path)))
Glad that it helped you! I'm hoping to (soon) use zippers for something that "starts" out at the leafs as well. Before I've typically recursed down a mix of map and vector structures, building up the result as I go. It has worked, but I find the code hard to reason about.
(filter (complement zip/children))
^^ Nice way of finding leafs by the way 🙂
Hello folks. I have a doubt here. i have this vector:
[{:customer-id "cid-1"
:customer "Customer 1"
:policy "Policy 1"
:term 1000
:settlement 300
:brio-nr 100}
{:customer-id "cid-2"
:customer "Customer 2"
:policy "Policy 2"
:term 1000
:settlement 300
:brio-nr 100}
{:customer-id "cid-3"
:customer "Customer 3"
:policy "Policy 3"
:term 1000
:settlement 300
:brio-nr 100}
{:customer-id "cid-4"
:customer "Customer 4"
:policy "Policy 4"
:term 1000
:settlement 300
:brio-nr 100}]
I would like to update a field in one of the maps inside of the vector. How could i do this?
I was thinking to use merge
but i look a the docs and saw that do not work with vectors 😞@ramonp.rios update-in
can use vector index as part of its "path" argument
user=> (update-in [{:a 1 :b {:c 3}} {:a 2 :b {:c 6}}] [0 :b :c] + 12)
[{:a 1, :b {:c 15}} {:a 2, :b {:c 6}}]
also for more complex data queries/manipulation I would recommend learning specter[1] https://github.com/redplanetlabs/specter
@ramonp.rios I'd consider just using map
I would reconsider having a vector in the first place, vs indexing by customer-id
Thank you all of you! I'll try each of your suggestions
Feel free to ask for clarification if you need to. Sometimes too many options makes it harder to pick one!
clojure makes reindexing in new ways easy at least
or you can just use the clojure.set namespace, which implements the relational model :)
@alexmiller Would you just stick maps next to each other then? Or would you do it on a per-property basis?
it erased the gist link but this is @hiredman’s gist i always go back to at > https://gist.github.com/hiredman/7d17d8d2b58c41ce95bf2db305b0f427
if I want to have a core.async channel with a transducer on it, but the rest of the settings the same, what should I provide as buffer size, 0?
When using reduce
with a string, does it optimize internally with a StringBuilder
? Specifically, I want to know about this,
(defn reverse-string [s]
(reduce (fn [coll elem] (str elem coll)) "" s))
(defn into-str
"reduce coll into a String, given a transducer"
[xf coll]
(transduce (comp xf (map str))
(fn
([] (StringBuilder.))
([^StringBuilder sb] (.toString sb))
([^StringBuilder sb s] (.append sb ^String s)))
coll))
@hindol.adhya reduce is polymorphic on the source collection
yeah. i put some examples with time
where i can do 50,000 loops in an order of magnitude less than their example can do in 500 loops.
@hindol.adhya str
does use a StringBuilder internally, so you could probably just (apply str (reverse s))