This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-07-20
Channels
- # announcements (7)
- # babashka (16)
- # beginners (58)
- # boot (12)
- # calva (3)
- # cider (11)
- # clj-kondo (9)
- # cljs-dev (8)
- # clojure (82)
- # clojure-europe (9)
- # clojure-italy (11)
- # clojure-losangeles (1)
- # clojure-nl (8)
- # clojure-uk (8)
- # clojurescript (5)
- # css (2)
- # cursive (5)
- # datomic (20)
- # docker (2)
- # emacs (4)
- # figwheel-main (16)
- # fulcro (53)
- # graalvm (17)
- # jackdaw (2)
- # jobs (4)
- # kaocha (6)
- # lambdaisland (2)
- # luminus (2)
- # meander (1)
- # off-topic (146)
- # re-frame (4)
- # releases (1)
- # rum (12)
- # sci (71)
- # shadow-cljs (26)
- # test-check (22)
- # vim (1)
- # xtdb (9)
Is there a way to pipe REPL output through more
, Linux shell style? There are some large data structures I'd like to check more carefully but they just go flying by.
@zanategdl Maybe take a look at Cognitect's REBL which can display data structures as tables and lets you drill into them?
So I really want to use Plumatic Schema to write libraries, without forcing it as a dependency upon users. My idea for how to accomplish this is to write a shim around the schema types/methods I use, that delegates to schema.core
if it exists and can be loaded, and does nothing otherwise (e.g. my.shim/defn
delegates to schema.core/defn
if it exists, and otherwise delegates directly to clojure.core/defn
).
Is this doable/reasonable? And if so, how should I go about detecting if schema.core
exists, and loading it only if it does? Is this possible for clj and cljs?
I saw something similar to this done in https://github.com/dm3/clojure.java-time They have
(defmacro when-joda-time-loaded
"Execute the `body` when Joda-Time classes are found on the classpath.
Take care - when AOT-compiling code using this macro, the Joda-Time classes
must be on the classpath at compile time!"
[& body]
(if (try (Class/forName "org.joda.time.DateTime")
(catch Throwable e))
`(do ~@body)))
for example to only execute some code if a class existsas they mention there, you have to be careful with AOT stuff since it's a macro, you could do it on the fly but since it's reflection and throw/catching an exception performance may suffer if that is a concern
Cool, thanks! I’m not sure how I’d adapt that for Schema though, since Schema’s a Clojure lib
As for doing this on the fly, I’m thinking I could just do it once and then memoize the result, since Schema probably won’t be added to the classpath mid-program-execution
ahh yeah mb, I haven't tried it but if require
throws an error if it doesn't exist that might be possible
ah, yeah, here: https://github.com/nrepl/piggieback/blob/master/src/cider/piggieback.clj#L9-L18
seems like I can do the same thing in cljs via (try (require 'foo.bar) true (catch :default _ false))
…so I guess that answers my question 🙂 thanks!
there's also requiring-resolve
Clojure 1.10.1
(ins)user=> (requiring-resolve 'foo.bar/baz)
Execution error (FileNotFoundException) at user/eval1 (REPL:1).
Could not locate foo/bar__init.class, foo/bar.clj or foo/bar.cljc on classpath.
(ins)user=> (requiring-resolve 'clojure.data/diff)
#'clojure.data/diff
doesn't work in cljs though
ojureScript 1.10.758
(ins)cljs.user=> (requiring-resolve 'foo.bar/baz)
WARNING: Use of undeclared Var cljs.user/requiring-resolve at line 1 <cljs repl>
Execution error (TypeError) at (<cljs repl>:1).
Cannot read property 'call' of undefined
Code management:
Has anyone else considered def
ing central keywords or strings and then referring to the symbols in your code rather than the more “keywordly” (or “stringly”) typed approach we usually see in Clojure, where people just sprinkle the literals all over the code?
So, rather than the usual
(when (= role :my-important-central-keyword) ...
, you’d do
(def my-important-reference :my-important-central-keyword)
... in another ns
(when (= role constants/my-important-reference) ...
I basically do that when I want compile-time enforcement around constants
it’s a lot nicer to have the compiler tell you when you’ve made a typo than to have to figure it out yourself because your program is inexplicably not working
I like the idea, it feels more secure with that enforcement. Do you limit it to certain things, or do you use it a lot?
Yeah, exactly
the whole benefit of making keywords invokable is to reduce the distance between the attribute and the invocation.
realistically, if you have (def foo :foo), you're not ever going to change :foo or if you do, you will also change foo. and you have also made it harder for static analysis tools to track where that keyword is being used
I end up using it every once in a while, especially when e.g. building a DSL or generating code for something
you've also made everything slower by introducing a var lookup in your keyword invocation
so you're doubling the invocation overhead
another benefit is that tooling support is better for vars than for keywords, so you can get autocomplete etc
as a rule of thumb for ‘normal’ code, I’d recommend def
ing constants including keywords that feel like ‘magic numbers’, and leaving keywords used for lookups etc inlined
for instance, if you’re generating HTML/CSS/React/whatever it’s not unlikely you’ll have a bunch of magic number-style keywords like :ff1212
, and def
ing these is generally a good idea
but if you find yourself doing stuff like {constants/keyword-a 123, constants/keyword-b true}
a lot, then you’ll probably want to consider @alexmiller’s points
@UK0810AQ2 no? maybe? direct linking eliminates var lookup for invocation but I don't remember if you get the same effect for resolution. it would also potentially ruin the optimized keyword call site invocation used in record lookups.
Cursive also has keyword autocomplete
I see. And if I define it as :const
there will be no lookup as well because the compiler will inline it?
it should in that case. but this seems to me to be going increasingly far just to avoid doing the simple thing
Go to definition doesn't always work if you just use keywords, so that is one point in favor of def
ing. An example where that comes up a lot is re-frame, since it uses this pattern for registering handlers: (rf/reg-event-db :my-keyword (fn [...] ...)
@U09LZR36F Not if you use a macro, and tell Cursive to resolve it like a def
@U15RYEQPJ hard disagree about vars to keywords, if you want the compiler enforcement there's more effective options than def of a keyword, and it makes the code harder to read rather than easier
to me human readability is first priority
@alexmiller (and others): points taken 🙂 I’m not so worried about invocation optimization (in my current app) as I am about readability and safe refactorability. I don’t think it’d make sense to def
all of your constants - the example that @U15RYEQPJ brought up, {constants/keyword-a 123, constants/keyword-b true}
, is in the silly end. Rather, I’m considering using constants for string values whose literal representation might change slightly over time (outside of my power), and whose semantic value (and usage of the same) in the application should not be disrupted by these changes. In addition, there’s quite a few of them, and their literal representations can be very similar, so the extra layer of indirection gives a chance to make them more dissimilar + to attach docstrings.
with that scope, seems reasonable
@U0AQ3HP9U if I don't control the string used as a key in a data structure, and especially if someone else can decide to change that string, I prefer to have an explicit re-keying step (with a single mapping, used locally in one place), rather than changing a key that is dereferenced throughout the app
I think one of the biggest clojure antipatterns is the transition from "use vanilla data type and simple keys" to "use the data representation provided by some external API in all application logic"
@U051SS2EU the string is not used as a key in a data structure, it’s used as a val in predicates. Like I posted originally, (when (= role constants/my-role) ...
. But I get your point, I think. In the case of the key being used in maps, for example, you’d do
(->> my-domain-data-map
(map (fn [[k v]]
[(get rekeying-map k k) v]))
(into {})
at the edge of your application, right? Or something to that effect.yes - sorry, this is most frequently seen in keys, but even vals should be translated if they are symbolic constants as opposed to primitive types IMHO
Right. Thank you for your thoughts 🙂
anyone know what might cause (io/resource "") to resolve to my user folder and not my project folder, created a few projects and not seen this behaviour previously 😕
resource just loads from your classpath, probably whatever is first on your classpath
maybe compare (System/getProperty "java.class.path")
well it seems to resolve to this jar:file:/home/oly/.m2/repository/javax/xml/bind/jaxb-api/
I would not really expect that to resolve to anything particularly stable and useful
> (io/resource "") to resolve to my user folder > resolve to this jar:file:/home/oly/.m2/repository/javax/xml/bind/jaxb-api/ these sentences seem conflicting to me
I will try removing the files in my home folder, the getproperty command does list these "resources:src/clj:src/cljc:tests:" and then all the /home/oly/.m2/files
okay may have figured it out, I think its something todo with https://github.com/RickMoynihan/lein-tools-deps I am using lein but with deps and moved the file to a sub folder to avoid conflicts with the cljs deps file seems that may have changed the resources root 😕
How can I pass a symbol into a syntax-quote in a macro without evaluation? E.g. how can I get the following to print [java.lang.Long clojure.lang.Keyword clojure.lang.Symbol]
instead of throwing java.lang.RuntimeException: Unable to resolve symbol: 3 in this context
?
(defmacro mc [] `(prn (mapv type [1 :2 ~(symbol "3")]))) (mc)
you can't?
type works on objects and it looks like you're trying to get the type of (symbol "3"), which is invalid
symbols can't start with a number
> (prn (type (symbol "3")))
clojure.lang.Symbol
but that’s beside the point; pretend that it says "hello"
instead of "3"
if that helps 🙂
invoking type on that vector via mapv is going to evaluate the vector, which is going to evaluate the symbol, so you need some kind of quoting
(defmacro mc [] `(prn (mapv type '[1 :2 ~(symbol "3")])))
sorry if I misdiagnosed above
oh, cool, thanks 🙂
So… what if I want some things to be quoted and some not? Something like the following:
(defmacro foo [xs] `(prn ~(vec (for [x xs] (if (string? x) (symbol x) x))))) (foo ["foo" :bar "baz"])
ah, perfect
I was trying to call quote
in the macro
Hello! What do you guys think about Riemman for monitoring system health and performance? How do you compare it with other options?
alerts and processing is done in clojure, so that is powerful but pretty brittle in my experience