Fork me on GitHub
#clojure
<
2020-07-20
>
hiredman02:07:14

The input is like input at a repl, needs a new line to trigger

Hlodowig05:07:13

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.

dominicm12:07:48

Override :print as an option to do whatever you like :)

thanks2 3
seancorfield05:07:01

@zanategdl Maybe take a look at Cognitect's REBL which can display data structures as tables and lets you drill into them?

thanks2 3
wombawomba11:07:58

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?

Daniel Stephens12:07:44

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 [email protected])))
for example to only execute some code if a class exists

Daniel Stephens12:07:37

as 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

wombawomba12:07:16

Cool, thanks! I’m not sure how I’d adapt that for Schema though, since Schema’s a Clojure lib

wombawomba12:07:41

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

Daniel Stephens12:07:50

ahh yeah mb, I haven't tried it but if require throws an error if it doesn't exist that might be possible

dominicm12:07:59

The piggieback source does this fwiw

dominicm12:07:09

Cider piggieback, that is

👍 3
wombawomba12:07:09

seems like I can do the same thing in cljs via (try (require 'foo.bar) true (catch :default _ false))

wombawomba12:07:20

…so I guess that answers my question 🙂 thanks!

noisesmith18:07:47

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

noisesmith18:07:04

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

reefersleep13:07:32

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) ...

wombawomba13:07:18

I basically do that when I want compile-time enforcement around constants

wombawomba13:07:28

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

reefersleep13:07:38

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?

reefersleep13:07:41

Yeah, exactly

alexmiller13:07:06

this is in general, an anti-pattern in Clojure

3
alexmiller13:07:51

the whole benefit of making keywords invokable is to reduce the distance between the attribute and the invocation.

alexmiller13:07:13

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

wombawomba13:07:16

I end up using it every once in a while, especially when e.g. building a DSL or generating code for something

alexmiller13:07:02

you've also made everything slower by introducing a var lookup in your keyword invocation

alexmiller13:07:29

so you're doubling the invocation overhead

wombawomba13:07:30

another benefit is that tooling support is better for vars than for keywords, so you can get autocomplete etc

wombawomba13:07:29

as a rule of thumb for ‘normal’ code, I’d recommend defing constants including keywords that feel like ‘magic numbers’, and leaving keywords used for lookups etc inlined

Ben Sless13:07:51

Is the lookup overhead eliminated if I use direct linking?

wombawomba13:07:39

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 defing these is generally a good idea

wombawomba13:07:19

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

dominicm13:07:42

There's autocomplete for keywords in cider

alexmiller14:07:30

@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.

alexmiller14:07:33

Cursive also has keyword autocomplete

Ben Sless14:07:28

I see. And if I define it as :const there will be no lookup as well because the compiler will inline it?

alexmiller14:07:18

it should in that case. but this seems to me to be going increasingly far just to avoid doing the simple thing

👍 3
isak14:07:22

Go to definition doesn't always work if you just use keywords, so that is one point in favor of defing. 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 [...] ...)

dominicm15:07:25

But the definition you jump to will be pointless

isak15:07:04

@U09LZR36F Not if you use a macro, and tell Cursive to resolve it like a def

noisesmith18:07:12

@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

noisesmith18:07:21

to me human readability is first priority

reefersleep20:07:24

@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.

alexmiller21:07:05

with that scope, seems reasonable

noisesmith22:07:31

@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

noisesmith22:07:14

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"

reefersleep08:07:08

@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.

noisesmith15:07:22

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

reefersleep12:07:00

Right. Thank you for your thoughts 🙂

oly14:07:55

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 😕

alexmiller14:07:19

resource just loads from your classpath, probably whatever is first on your classpath

alexmiller14:07:58

maybe compare (System/getProperty "java.class.path")

oly14:07:02

well it seems to resolve to this jar:file:/home/oly/.m2/repository/javax/xml/bind/jaxb-api/

alexmiller14:07:39

I would not really expect that to resolve to anything particularly stable and useful

dpsutton14:07:51

> (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

oly14:07:34

well /home/oly/ being my user folder and my project being in /projects/

oly14:07:15

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

oly14:07:11

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 😕

oly14:07:10

:lein-tools-deps/config {:config-files [:install :user :project "deps-backend.edn"]}

oly14:07:37

doing that in the root seemed to fix my issue instead of using a nested path

wombawomba14:07:55

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)

alexmiller15:07:18

type works on objects and it looks like you're trying to get the type of (symbol "3"), which is invalid

alexmiller15:07:36

symbols can't start with a number

wombawomba15:07:52

@alexmiller

> (prn (type (symbol "3")))
clojure.lang.Symbol

wombawomba15:07:30

but that’s beside the point; pretend that it says "hello" instead of "3" if that helps 🙂

alexmiller15:07:33

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

alexmiller15:07:16

(defmacro mc [] `(prn (mapv type '[1 :2 ~(symbol "3")])))

alexmiller15:07:35

sorry if I misdiagnosed above

wombawomba15:07:11

oh, cool, thanks 🙂

wombawomba20:07:04

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"])

bronsa20:07:39

(list 'quote (symbol x))

bronsa20:07:52

or a bit more esoteric

`'~(symbol x)

wombawomba20:07:56

I was trying to call quote in the macro

skalangrinsson20:07:06

Hello! What do you guys think about Riemman for monitoring system health and performance? How do you compare it with other options?

chrisblom21:07:04

riemann doesn't keep history so it's not a complete solution

chrisblom21:07:54

alerts and processing is done in clojure, so that is powerful but pretty brittle in my experience

chrisblom21:07:32

it's easy to accidentally break stuff, which is not something i'd want in my monitoring stack

chrisblom21:07:15

what alternatives are you considering?

skalangrinsson14:07:48

Kibana, Instana and Zabbix are the other options