Fork me on GitHub
#clojure
<
2019-10-30
>
macrobartfast02:10:21

in Emacs, does cider-eval-defun-at-point work the same for cljs files as clj files?

macrobartfast02:10:38

every eval is producing a variant of

1. Unhandled java.lang.IllegalAccessError
   atom does not exist

macrobartfast02:10:23

i.e. when eval'ing

(ns test.core
  (:require
   [reagent.core :as reagent :refer [atom]]
   [reagent.session :as session]
   [reitit.frontend :as reitit]
   [clerk.core :as clerk]
   [accountant.core :as accountant]))

macrobartfast02:10:33

in a reagent project.

macrobartfast02:10:52

if I comment out the reagent.core line it has the same error for reagent.session.

macrobartfast02:10:15

however, changes to source compile and are reflected in the browser... so maybe I'm not understanding what can be evaluated in a buffer in a cljs project as compared to a clj one.

dpsutton02:10:40

Should be. Head to #cider to discuss?

macrobartfast02:10:43

ok, off to #cider.

ag04:10:19

Mildly annoying and perhaps an off-topic question: I’m looking for a Clojure library for “effects & handlers”, à la re-frame but for the back-end. What’s currently “trendy”? I looked at https://github.com/clojureman/special, I like the simplicity of it, but not sure if it’s okay to use it in production. Would you recommend using it or maybe something else?

seancorfield04:10:46

@ag I'm not sure I would look at that "conditions" library and think "effects & handlers" so maybe I don't understand what you're looking for with that description...

seancorfield04:10:27

...to me it sounds like you'd want some sort of event broadcast / listener pattern?

ag05:10:32

To be honest I don’t know exactly what I want. I’m just seeing a lot of code where side-effecty things are thrown together where the code is written in sorta “linear”, imperative fashion and I don’t like it. I want something similar to how re-frame separates subscriptions and events. For example: I have three different sources of data that I need to fetch in order to make a decision, each query depends on the results of previous query and each has to handle exceptions, etc. Moreover, sometimes you need to also update (e.g. write to db) before fetching some more data and that all can get pretty nasty. Clojure by default doesn’t give you any tools to deal with that problem, only wisdom in form: “maintain certain discipline; write small functions; compose.”

seancorfield05:10:05

Yeah... my attempts to go down that path have all ended up looking like monadic code which is not very idiomatic Clojure and not very easy to work with, to be honest.

ag05:10:58

but it is hard when you have developers in your team coming from imperative languages and writing it the most straightforward (from their perspective) way

ag05:10:24

working mainly with Re-frame for the past several months, and now switching to do more back-end code, I have to say - I miss re-frame model. And I used Om.next as well, even though it was more difficult to grok in the beginning, it is still very nice. I want something similar for the Clojure code.

seancorfield05:10:38

On the front end, you're constrained to single-threaded behavior so these callbacks/listeners make a lot of sense. I don't know that sort of logic makes as much sense on a multi-threaded backend tho'...?

seancorfield05:10:12

I suspect you might be headed toward either monads (there's a contrib library for that) or core.async... But I guess I'd have to see the sort of linear/imperative code you're talking about to really offer an opinion.

ag05:10:13

but it’s not just single-threaded, everything is also asynchronous. That makes it more difficult, not easy.

ag05:10:37

I need to find a good pattern for the back-end code. Where fetching data, pure transformations and side-effects (logging and exceptions) are separated.

bfabry05:10:39

I also have struggled with what is the answer here. In the past I’ve gone with “well push all the impure stuff into these few ns’s” but that is admittedly dissatisfying. I remember the silliness of monads in haskell though too. one thing I guess is that in a backend/server context there’s a lot less juggling with the outside world that generally has to go on than in a ui side process

ag05:10:05

> in a backend/server context there’s a lot less juggling with the outside world I beg to differ. There’s way more. At least in the project I’m working on right now.

bfabry05:10:34

every project is different. that’s just my experience

ag05:10:36

the pattern I’m seeing very often: get-data -> manipulate results -> feed that to another query -> side-effect (update DB, logging, exception handling) -> return something like {:result :success}. and this is all in a single function. Sometimes I see things like (let [data (get-data), _ (fire-missiles data)] - i.e. side-effecting in a let block, because no one even cares about the results of that operation.

👍 4
kenny14:10:50

On some of our services we have adopted a re-frame-esque approach to handling the effects. The one function that did all those side effects would now return a "fx" map. That fx map would get passed to a small function that just doseqs over the map and executes each effect via a multimethod. This approach lets us test the whole flow without actually firing any missiles.

ag18:10:55

Yeah, something like this. One would think this kind of pattern maybe widely adopted and used, it seems that’s not the case

kenny18:10:52

It's been quite successful for us. Maybe it's a bit too simple and possibly use-case dependent to turn into a library?

ag18:10:24

Maybe you could share a gist with an example

kenny18:10:29

It's essentially this:

(defmulti mutate! ::name)

(defn run-mutations!
  [mutations]
  (doseq [[mutation-name mutation-map] mutations]
    (mutate! (assoc mutation-map ::name mutation-name))))

kenny18:10:11

The previously effectful function just returns a "mutation-map".

ag05:10:20

it is especially difficult when you have multiple “sources of truth”. In comparison - on front-end with Re-frame - you have app-db atom - it is a single “source of truth”.

ag05:10:43

you can’t “spit where you eat” - fetching data is separated from modifying it

valerauko05:10:34

if you don't care about it, then throw it in a go block in the body of the let. at least that's what i'd do

valerauko05:10:12

i found that working with manifolds made async way more reasonable

valerauko05:10:32

with let-flow you don't need to manually wait for everything, it does the magic for you

ag21:10:00

This is really good. But sadly it does’t give me an answer I could immediately apply. This for example: > My idea of development: > Everything is RMDB. > Send SQL, > Get Results ( or side effects). > Playing table tennis between Clojure and RMDB. What does this exactly mean?

mloughlin21:10:39

The stuff about "Everything is RMDB", I admit I have no idea. I think some nuance is lost in translation. My interpretation of what the blog posts are about in concrete (clojure) terms is: - Use "pass the world"-style context maps, pass this around - Structure your functions as: [optional verification step] -> followed by a threading macro of pure functions -> end the function with a side-effect - Each function may have a single side-effect - Favour using simple functions like reduce, map, pmap and aim to keep your call stack as shallow as possible The way you described the general flow of your functions made me think of PurefunctionPipelineDataflow

mloughlin11:10:17

it takes a bit of work to tease apart the metaphors, but it seems like there's something there. Or perhaps I've imparted my own meaning by interpreting the metaphor. I suspect that might be the point :thinking_face:

gibb11:10:36

The search goes on 🙂

abdullahibra12:10:34

hello everyone

abdullahibra12:10:04

is there a good way to attach a message to be returned if the spec failed ?

abdullahibra12:10:36

this lib do what i want https://github.com/leonardoborges/bouncer , so my question is could i use the same with clojure.spec

Alex Miller (Clojure team)13:10:58

no, that's not part of spec

abdullahibra13:10:57

@alexmiller what is your suggestion to do that?

abdullahibra13:10:09

for example: if i'm using spec to validate params of APIs, so i should give the user hint what makes the call fail

mafcocinco13:10:19

You could wrap the response from spec along with the message in a higher order map. Something like this:

Alex Miller (Clojure team)13:10:19

if validation fails, you can use explain-data to get back more detailed info about why and use that to construct a user message

kenny15:10:36

@U145X0BPE This isn't always a trivial thing to do, especially with complex specs & a large information model. We have been using this lib in production to convert explain-data to user friendly error messages https://github.com/Provisdom/user-explain. It's manual, tedious work but will allow you to cover anything you'd possibly want.

kenny15:10:43

Attaching additional info to specs when they fail does seem valuable. Predicates often do not return enough information to allow you to figure out what went wrong.

abdullahibra15:10:38

that's awesome 🙂

abdullahibra15:10:28

but i'm curious if spec maybe in the future support that, to attach messages in case of failure ?

kenny15:10:11

You can see another approach in #announcements from @U0WL6FA77. It's less general but might be easier to understand.

❤️ 4
kenny15:10:55

But yes, I'd also like a way to attach more info when a predicate fails.

Gerome14:10:29

Hi everyone, I'm a frontent JS developer who is not only new to Clojure and CLJS but also to backend development. From the frontend I'm used to being able to fire up chrome and inspect my http requests to see, for example, if they contain the right payload or URL params are correctly encoded and things like that. Right now, I've started writing a middleware that I need to get data from an API and I was wondering if there is something like Chrome devtools for "backends" or middlewares that I can use to inspect HTTP requests. I've tried Wireshark. It's a great app but, boy, it is complex. I was looking for something more focussed on HTTP.

Gerome14:10:03

The only thing, that comes to mind for me is to route everything through a proxy but that seems like a lot of overhead.

bfabry14:10:18

generally just logging. tap> etc. you can also connect to your running server process with a repl and poke around at any state you keep

Gerome14:10:48

Yeah, it seems like general debugging is the way to go.

bfabry14:10:17

in my experience with server side dev: log/tap> all the things. and if you can store what you’re tapping in something queryable even better

Gerome14:10:56

I'll try that, thanks.

murtaza5214:10:10

is there a way to convert a hex string "22" into a hex literal 0x22 ?

bfabry14:10:07

(read-string (str “0x” hex-string))

dpsutton14:10:25

that would just yield the value. weird to want a hex literal

bfabry14:10:03

yeah I’m assuming he meant “value”. if you want a literal you type it with your hands 🙂

bfabry14:10:02

that said, if you are literally emitting code for something else: (symbol (str “0x” “22"))

murtaza5214:10:44

I am parsing some data, where I have hex strings, and need to compare them. Its just more cleaner to have a map of hex literals in my code, rather than hex strings. Will go with the strings for now.

jumpnbrownweasel14:10:03

You can parse into an integer and compare integers.

(Long/parseLong "22" 16)
=> 34

👍 4
jumpnbrownweasel14:10:06

The last param 16 is the base.

Alex Miller (Clojure team)14:10:04

then use .toHexString() if you want it as a hex literal string.

murtaza5214:10:55

(Integer/toHexString 55)still gives me a string and not a literal.

Alex Miller (Clojure team)14:10:21

the literal form of integer in Clojure are java.lang.Long values

Alex Miller (Clojure team)14:10:10

those always print as base 10

Alex Miller (Clojure team)14:10:23

the reader is able to read other forms, 0x etc

murtaza5214:10:38

yup but something like this 0x55 is also a literal with base 16

murtaza5214:10:50

read-string outputs that as base 10

Alex Miller (Clojure team)14:10:33

in what context do you want to print it as 0x55?

Alex Miller (Clojure team)14:10:17

there are ways to influence how the printer prints things if you have some context for doing so

murtaza5214:10:44

I have a hash map {"55" :a "FF" :b} etc, where the key is a hex value. I would have liked to represent them as literals instead of strings, its just more cleaner. However to do that I will also have to convert my input hex string to hex literals.

Alex Miller (Clojure team)14:10:45

0x22 and 34 will be the same value (a java.lang.Long) in your data

jumpnbrownweasel14:10:52

The parsed value (the integer) can be used for this. "Literal" usually means a representation of a value before it is processed by the reader, so this term is confusing us I think. :-)

bfabry14:10:04

you can represent them as a long, which will get printed as base 10. you can represent them as a string, which will get printed as a string, or you can represent them as a symbol, which will get printed as a bare word. aside from the printing, those three different types of value are associated with wildly different behaviour

bfabry14:10:43

if you really, truly, do not care that the value is a number, if it’s just an abstract “thing” that you want printed as 0x55 but you’ll never ever try to do number things with it, you’ll never try and pass it to anything (database, serialisation tool, library) that expects it to be a number, then a symbol will give you that

murtaza5214:10:41

hmm let me rethink it and get back.

murtaza5214:10:19

@alexmiller thanks for pointing out that internally both are stored as java.lang.Long which means this works ({0x03 :a} (Integer/parseInt "03" 16)). My assumption was that both have a diffrent representation and therefore the above will not work.

👍 4
bfabry14:10:06

btw, you can control how a map is printed by attaching metadata to it and defining a custom printer for it

Alex Miller (Clojure team)14:10:08

you should use Long/parseLong, not Integer/parseInt

Alex Miller (Clojure team)14:10:34

In control, the main integral type is Long, not Integer

bfabry15:10:06

user=> (defmethod print-method :foo [v ^java.io.Writer w] (.write w "overridden!"))
#object[clojure.lang.MultiFn 0x32b9bd12 "clojure.lang.MultiFn@32b9bd12"]
user=> {:a :b}
{:a :b}
user=> (with-meta {:a :b} {:type :foo})
overridden!
so you could attach a type to your particular map and then define a writer for it that writes the keys using hex notation, if you really wanted

Alex Miller (Clojure team)15:10:20

the above works but only because longs and integers both hash the same and compare equal, but you are pushing on same fragile boundaries there

Alex Miller (Clojure team)15:10:39

I'd say the printing thing is too clever and bound to trip you up eventually

bfabry15:10:51

unless the thing printed out is really obviously custom. like it prints a table

murtaza5215:10:19

@alexmiller thanks for pointing out the Long/parseLong and @U050MP39D for the printer

ec14:10:27

How viable is compiling Clojure to native with GraalVM I've seen some httpkit examples but never seen a "complex" example. I'm thinking about about making a desktop app where I write ui stuff natively and share backend logic via Clojure, graalvm to achieve lower resource usage and performance.

sogaiu14:10:45

@cakir-enes not too far back, the following was asked: https://clojurians.slack.com/archives/C03S1KBA2/p1572079261366000 if you think that's similar enough to your question, may be the following is some part of an answer: https://clojurians.slack.com/archives/C03S1KBA2/p1572083952373300

borkdude17:10:39

is it a bad idea to leave the percented names intact while transforming an anon-fn literal to a fn expr? e.g.:

$ lein run '#(inc %)' '{:fn true}'
(fn [%1] (inc %1))
what could go wrong?

Alex Miller (Clojure team)17:10:14

we do something very similar in spec

Prateek Khatri17:10:33

clojure.test does not report ArityException (arising from within tests) as errors. It just prints the stacktrace. What can I do to report such exceptions as "errors" so that lein test reports test failure in my CI/CD pipeline?

bfabry17:10:37

bfabry@18723-bfabry ~/C/c/mainstuff> lein test

lein test mainstuff.core-test

lein test :only mainstuff.core-test/a-test

ERROR in (a-test) (AFn.java:429)
FIXME, I fail.
expected: (filter true? [] [])
  actual: clojure.lang.ArityException: Wrong number of args (3) passed to: core/filter
 at clojure.lang.AFn.throwArity (AFn.java:429)

bfabry17:10:04

I suspect some code of yours or another library other than clojure.test is stealing the exception

andy.fingerhut17:10:10

Checking the contents of your $HOME/.lein/profiles.clj is a good idea. Feel free to paste it here if it isn't too long and you want advice on what might be causing issues.

Alex Miller (Clojure team)17:10:45

clojure.test seems to do the right thing

Alex Miller (Clojure team)17:10:08

leiningen monkey patches clojure.test reporting, not sure if that's a factor

Alex Miller (Clojure team)17:10:01

if so, putting :monkeypatch-clojure-test false in project.clj would test that hypothesis and fix it

bfabry17:10:31

lein test does the right thing for me, with no profiles.clj

hiredman17:10:34

errors in fixtures are also handled different if I recall

hiredman17:10:39

you may also be experiencing an annoying feature of the is macro

hiredman17:10:59

(is (f ...)) isn't always calling the function f

Prateek Khatri05:10:59

@U050MP39D @U0CMVHBL2 @alexmiller @U0NCTKEV8 Thanks everyone for the hints. I'll check go through each of them to find where the problem is.

Prateek Khatri06:10:16

The problem was with one of the fixtures where the code was catching the exception. :face_palm:

andy.fingerhut06:10:26

Makes sense. Glad you were able to find the root cause.

avi20:10:26

There isn’t anything like a select-vals function in core, is there? I didn’t see anything.

avi20:10:43

I didn’t see anything in medley either.

avi20:10:59

My naive, inefficient impl:

(defn- select-vals
  "Given a map and a sequential of keys, returns a non-lazy sequential of the values of those keys
  in the map, in the same order as the keys. If a key is not present in the map, the corresponding
  entry in the result will be nil."
  [m ks]
  (reduce (fn [result k] (conj result (get m k)))
          []
          ks))

hiredman20:10:00

(map m k)

💯 4
avi20:10:29

sweet, thanks!

avi20:10:51

I guess (mapv m ks) would be closer to my fn

Alex Miller (Clojure team)20:10:57

if you're feeling a yearning to use juxt

😆 4
noisesmith20:10:33

only works for keyword / symbol keys though

4
✔️ 4
avi20:10:53

When I feel a yearning to use juxt coming on, I go outside and take a walk and clear my head until it passes…

4
avi20:10:05

j/k (mostly)