Fork me on GitHub
#beginners
<
2020-01-07
>
hindol.adhya06:01:43

For transducers, is a single step transducer filter #(and (int? %) (pos? %)) more efficient than a two step transducer (filter int?) (filter pos?) or are they same because no intermediate sequences are created anyways?

alexmiller13:01:40

Yes, it is faster as it will perform a single pass with no intermediate sequence objects, rather than two passes. Filter seqs are chunked (in 32-element chunks) so the benefits are smaller than you might expect. In general, transducers will increasingly win as you increase the number of transformations and/or the size of the collection.

hindol.adhya21:01:02

Are there other cases where the lazy seq is realized in chunks?

alexmiller22:01:45

and many that aren't

alexmiller22:01:04

and generally, I'd say that if you care which you're using, you shouldn't be using lazy seqs

seancorfield06:01:18

@hindenbug I wouldn't expect there to be much difference in practice -- I'd expect the single step to be slightly faster -- but I'd go with readability until it was proven I had a performance issue.

seancorfield06:01:01

I ran some tests with Criterium and, yes, the single step is faster but it's not all that much faster (and the output I'm getting from my benchmarks are sufficiently variable that I can't really get an accurate read on the difference).

seancorfield06:01:57

(the slowest runs of the single-step are slower than the fastest runs of the two step)

hindol.adhya08:01:03

Perfect, thanks. I really need to start looking into criterium for quick perf tests like this.

grounded_sage08:01:38

This (slurp (:body (client/get "" {:as :stream}))) with the actual domain I am requesting. Returns this

Execution error (IOException) at org.apache.http.conn.EofSensorInputStream/isReadAllowed (EofSensorInputStream.java:107).
Attempted read on closed stream.
class .IOException

grounded_sage08:01:38

This (slurp (:body (client/get "" {:as :stream}))) with the actual domain I am requesting. Returns this

Execution error (IOException) at org.apache.http.conn.EofSensorInputStream/isReadAllowed (EofSensorInputStream.java:107).
Attempted read on closed stream.
class .IOException

ales.najmann09:01:53

can't you just get the content directly? (slurp "")

didibus10:01:26

Ya, you should be able to just slurp the URL directly

didibus10:01:47

But if not, you'd have to tell us at least what library client is from

grounded_sage13:01:11

I can't slurp directly because i run out of memory.

grounded_sage13:01:46

(defn append-to-file
  [file-name s]
  (spit file-name s :append true))

(defn write-json-file [file-name s]
  (with-open [rdr (io/reader (:body s))]
    (map #(append-to-file file-name (str % "\n"))
         (line-seq rdr))))

(defn fetch-data
  [{:keys [url query-params]}]
  (client/get url
              {:accept :json
               :as :stream
               :query-params query-params}))

(write-json-file "result.json"
                       (fetch-data {:url "}))

grounded_sage13:01:05

This is what I have so far. The client is clj-http

grounded_sage13:01:52

I am getting this

Error printing return value (IOException) at .BufferedReader/ensureOpen (BufferedReader.java:122).
Stream closed
class clojure.lang.ExceptionInfo

grounded_sage13:01:21

Though it does write the file to disk. How do I return a value? When I add a println as a message to say it's finished it doesn't write to disk. Adding a nil or ìdentity also stops it from writing to disk.

grounded_sage13:01:23

Ah figured it out. I use doseq

didibus19:01:44

ah ok, that's a really big webpage you're loading :p

grounded_sage08:01:22

Just realised it closes stream after first read. This is what I get when first running against the stream.

Execution error (OutOfMemoryError) at (REPL:1).
Java heap space
class java.lang.OutOfMemoryError

ramon.rios09:01:40

Hey guys, i'm triyng to create a vector with some maps on it.

(def address-request {:uri "api/address"
                      :method :post
                      :format ajax/json-request
                      :response-format ajax/json-response
                      :on-success [:customer/addresses-success]
                      :on-failure [:customer/addresses-failure]})
This is my map. I would like to, for each element that i have in another map do a update-in for add :param with the value and then add it on a vector. This is my attempt to do it:
(defn request-vector [params request-body]
  (reduce (conj [] (update-in request-body :params assoc params) params)))
But i'm getting a error: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Keyword What you guys think it would be the best approach do achieve this goal?

delaguardo09:01:30

check arguments for update-in , the path where you want to apply update function must be sequence. (update-in request-body [:params] assoc params) or use update instead of update-in

delaguardo09:01:30

check arguments for update-in , the path where you want to apply update function must be sequence. (update-in request-body [:params] assoc params) or use update instead of update-in

ramon.rios10:01:50

Thank you for the insight!

ramon.rios10:01:59

I got almost there

ramon.rios10:01:24

i did a (reduce-kv    `(fn [r k v]`      `(conj r (update request-body :params v)))`    `[]`    `params)`

ramon.rios10:01:34

But the v is null

didibus10:01:30

Is params a map?

ramon.rios10:01:38

params {:main {:street "name" :customer ..uuid..} :facturation {:street "name" :customer ..uuid..}}

didibus10:01:42

Maybe show an example of the map and then the resulting vector you'd want. I'm not sure I fully follow what you're trying to achieve

didibus10:01:32

But in any case, v should not be nil, unless you have a nil value in your map

ramon.rios10:01:52

I println v and it shows a value

didibus10:01:55

Right, the problem is your update

didibus10:01:13

Update takes a map, then a key and finally a function

didibus10:01:19

But your v is not a function I assume

didibus10:01:40

Try using assoc instead of update

ramon.rios10:01:56

Thanks friend

tstocker11:01:22

Hello! Starting to learn clojure and programming in general. Total beginner. I have a question. I have a nested vector: [something [a 1]] What I want from it: a new key + value based on this. so: :someting/a 1 How can I do this?

qythium11:01:39

You can construct qualified keywords by calling keyword with 2 arguments, does that help?

qythium11:01:16

Is the something in the original form a symbol?

feikas12:01:41

hello, how to substitute newlines in string with literally "\\n"?

feikas12:01:41

hello, how to substitute newlines in string with literally "\\n"?

rahul08032713:01:27

do you mean like this? (clojure.string/replace "a\nx" "\n" "\\n")

feikas13:01:45

yes, exactly this, thank you!

ozfraier13:01:52

Hi, I'm just starting with reagent, following this tutorial https://dhruvp.github.io/2015/02/23/mailchimip-clojure/ doing the input field example, I modified it to a number input, so I can input hours/minutes, and then wanted to pass :min and :max values. Not sure what to do, I've added to the input-element component an argument called &attrs , then passed a hash-map {:min 0 :max 24} and merged it with the rest of the attributes. Which seems to work, but I still fear I might have sinned and there is a more preferred way to do it. what do you think?

(defn input-element
  "An input element which updates its value on change"
  [id name type value attrs]
  [:input (merge {:id        id
                  :name      name
                  :class     "form-control"
                  :type      type
                  :required  ""
                  :value     @value
                  :on-change #(reset! value (-> % .-target .-value))} attrs)])
;; TODO pass min and max values into input-element.
(defn hours-input [hours-atom]
  [input-element "hours" "hours" "number" hours-atom {:min 0 :max "23"}]
  )

ozfraier13:01:52

Hi, I'm just starting with reagent, following this tutorial https://dhruvp.github.io/2015/02/23/mailchimip-clojure/ doing the input field example, I modified it to a number input, so I can input hours/minutes, and then wanted to pass :min and :max values. Not sure what to do, I've added to the input-element component an argument called &attrs , then passed a hash-map {:min 0 :max 24} and merged it with the rest of the attributes. Which seems to work, but I still fear I might have sinned and there is a more preferred way to do it. what do you think?

(defn input-element
  "An input element which updates its value on change"
  [id name type value attrs]
  [:input (merge {:id        id
                  :name      name
                  :class     "form-control"
                  :type      type
                  :required  ""
                  :value     @value
                  :on-change #(reset! value (-> % .-target .-value))} attrs)])
;; TODO pass min and max values into input-element.
(defn hours-input [hours-atom]
  [input-element "hours" "hours" "number" hours-atom {:min 0 :max "23"}]
  )

aisamu13:01:57

Some people like to put all the props on a map (not just max and min on your example). The &attrs also threw me off a bit, since it resembles a typo on the rest format (`& attrs`)

ozfraier13:01:06

The "&" was my very silly voodoo/cargo-cult concept of the rest format, now read about it and realized my mistake, so I'll edit it away from the snippet 🙂

jhughes15:01:53

Hi, question about embedding Metabase in a clojure app: the metabase docs say “Insert this code snippet in your server code to generate the signed embedding URL” where is server code located in a Clojure/CLJS app?

dennistel9015:01:07

Hi! I’m just getting started with clojure and one thing I find a bit confusing is which tool I should use for dependencies. Some places recommend Leiningen (which is build on top of Maven?) but others recommend just using deps. Which one is the recommended option? I’m looking for something lightweight that can generate a simple project setup with a test runner, do some builds etc

nate17:01:12

I echo everything that was said in the channel (good idea to use lein to start). If you'd like more commentary on the subject, we did a podcast episode about it: https://clojuredesign.club/episode/040-should-i-use-lein-boot-or-tools-deps/

tkjone00:01:04

If you have not read this https://corfield.org/blog/2018/04/18/all-the-paths/ I would take a look to familiarize yourself with the options available. As for what your looking for, my recommendation to each one is: > generate a simple project setup https://github.com/seancorfield/clj-new > builds + dep management clj + deps.edn > test runner Clojure has a light weight testing library. I recommend to use that. https://clojure.github.io/clojure/clojure.test-api.html

nate_clojurians15:01:14

you probably want leiningen if you're just starting out, imo

nate_clojurians15:01:11

it's still the most popular and a ton of tutorials still use it and it comes with a test runner and building stuff and whatnot

nate_clojurians15:01:28

get some experience with clojure then re-evaluate later, imo 🙂

seancorfield15:01:58

Leiningen is the "easiest", CLI/`deps.edn` is the simplest. Pragmatically, use whichever tool the book or tutorial you are learning from is using.

dennistel9015:01:02

Thanks for the advice!

dennistel9015:01:10

Leiningen it is then 😄

seancorfield15:01:03

For background @dennistel90 I started with Leiningen back in 2010 because it was the only option. At work we switched from Lein to Boot in 2015 and then to CLI / deps.edn in 2018. These days I only use the CLI / deps.edn tooling.

dennistel9015:01:36

@seancorfield what is the motivation (from your team, but also the community) to move from leiningen -> deps + cli?

seancorfield17:01:03

I blogged about our switch from Leiningen to Boot https://corfield.org/blog/categories/boot/ but I didn't write up why we changed to CLI/`deps.edn` (I will, eventually).

seancorfield17:01:25

I also blogged a comparison of Leiningen, Boot, and CLI for aspects of running code and building artifacts etc https://corfield.org/blog/2018/04/18/all-the-paths/

nate_clojurians15:01:14

deps.edn is the simplest but it also does a lot less than leiningen and you'll need to add different supporting libraries to get what you're likely looking for

nate_clojurians15:01:49

which is fine, but maybe don't let this slow you down and just use what gets you into clojure code quickest 🙂

dennistel9015:01:12

oh yeah thats definitely the plan for learning

nate_clojurians15:01:29

it's not much work to switch these things up later, especially while you're still learning and your projects are simple

dennistel9015:01:40

asking more to get an idea of what is going on and where to possibly move to after learning clojure

didibus19:01:42

One thing that's good to learn after learning Clojure with lein. Is using Clojure without a dependency manager and build tool at all. Learn how to manually download jar and sources, and build up a classpath, and call clj with it manually, and similarly start a repl with clojure.main directly and learn to use the Clojure load and compile functions

didibus19:01:56

Once you know that, you'll understand what all these tools do under the hood, and it'll be easier for you to pick up and use any of them

nate_clojurians15:01:23

you can see a rather large deps.edn with a lot of options here https://github.com/seancorfield/dot-clojure

dennistel9015:01:28

Slightly related to tooling, how hard/easy is it to write a clojure library that works on JVM but also in Clojurescript?

nate_clojurians15:01:15

also, before you maybe get stuck on this like I did, I missed the bit in the second paragraph of the reader conditionals guide where it says it needs to be a .cljc file picard-facepalm

nate_clojurians15:01:38

but that's more for the deps.edn that lives in your home directory

dennistel9015:01:35

Don’t have one yet 😄 is this similar to a global .npmrc/.bashrc or something?

nate_clojurians15:01:37

in ~/.clojure/deps.edn I think

nate_clojurians15:01:01

I don't actually use deps.edn for much just yet

seancorfield18:01:29

Yes, the CLI/`deps.edn` tooling uses three deps.edn files: the "system" installed version (from the CLI -- technically it's baked into tools.deps.alpha now rather than a physical file on disk), the "user" version (in ~/.clojure/deps.edn -- a default version appears after installing the CLI but you can customize it as you wish), and then the "project" version (in the current directory).

nate_clojurians15:01:47

but it'll give you a better idea of how things might work

nate_clojurians15:01:22

it's not too hard to make something that works for both. you'll want reader conditionals for that, probably https://clojure.org/guides/reader_conditionals

nate_clojurians15:01:13

clojure leans really hard on being a hosted language, meaning you lean on the platform's native libraries a lot and it doesn't try to hide all of that

nate_clojurians15:01:36

so for file access, for instance, you'd need to use the js file access libraries vs the java file access libraries

dennistel9015:01:02

Yeah , it being a hosted language is definitely what draws me to it since I plan to use it on node/JVM and possible the BEAM VM(clojerl?) as well

didibus19:01:49

If you're looking for doing ClojureScript as well, shadow-cljs is a great build tool for it. Probably the easiest

dennistel9015:01:25

@nate_clojurians Thank you so much for the info and suggestions! now lets learn some Clojure! 💪

nate_clojurians15:01:40

:+1: have fun! be sure to ask if you get stuck

nate_clojurians15:01:45

keep it movin' 😉

grounded_sage15:01:28

How do people redefine a variable or swap out some kind of reference with a large data structure. Using an atom and reset! Is too slow. I also tried using a volatile! Then vreset! But it’s still way too slow. At the moment I have (def my-def val-1) and (def my-def val-2) inside a comment block so I can use the repl to redefine it. I’m doing this because I have a lot of other functions I am using at the repl to inspect the data structures. I only want to change the reference once.

nate_clojurians15:01:20

how are they too slow?

nate_clojurians15:01:33

I'm probably missing something in your meaning

nate_clojurians15:01:46

slow to run yourself? or slow at runtime?

nate_clojurians16:01:28

it sort of sounds like something you could use dynamic vars for, and override the value with binding?

grounded_sage16:01:56

Setting the atom or the def is fine for the first time. I can reset it to a string or something small. But when I reset it to the alternate data structure the repl simply hangs.

didibus19:01:55

Yeah, the repl hangs because it is trying to print the data structure

grounded_sage16:01:06

Yea I was trying to avoid binding because all the snippets I have would need to go inside the binding. What I have for the moment works for what I need but I’m curious if there is something I was doing wrong.

nate_clojurians16:01:36

does it hang forever or just for a while?

nate_clojurians16:01:07

because hanging forever could be something like missing a closing parens or something

nate_clojurians16:01:30

I've been tripped up by that before

nate_clojurians16:01:17

I might be out of my depth here, or I don't have enough info to be very helpful.

dpsutton16:01:00

can you def the alternate data structure? do something like (def new-stuff big-nasty-thing-that's-slow) and then (reset! the-atom new-stuff) and see if that is slow?

dpsutton16:01:04

also, are you printing the big nasty thing? maybe try (do (reset! the-atom new-stuff) nil) so that your repl isn't choking on printing a big gnarly structure

nate_clojurians16:01:56

oh that's a good point

nate_clojurians16:01:06

printing a huge structure will be painful

nate_clojurians16:01:33

also if you have code you'd like to share that could help as well

grounded_sage17:01:39

@dpsutton aha! That’s it when you reset the atom in the repl it prints out the new result. The (do ... nil) was what I was looking for. Thanks!

qythium17:01:39

It's also a good idea to set *print-length* and *print-level* if you're working with large / infinite data structures in the REPL :)

mail83819:01:53

hi i have a short question regarding clojure.spec. how would you spec lets say a person who can have children (which are also persons)?

mail83819:01:23

The datastructure would look something like

{:name "person1" :children [{:name "child1"} {:name "child2"}]}

mail83819:01:24

when trying to register a spec child like (s/def ::children ::person) it doesn't work, 'cause person is not defined yet (which makes sense)

hiredman19:01:50

define person first, then children

hiredman19:01:29

(it will work because the spec combinators won't immediately try to resolve children)

hiredman19:01:46

user=> (s/def ::bar (s/coll-of ::foo))
:user/bar
user=> (s/def ::foo (s/coll-of ::bar))
:user/foo
user=>

mail83819:01:07

oh thank you ^^ i never tried it the other way around ^^

vachichng20:01:37

Hi Everyone, when we read a future via deference , do it add overhead of passing the data back to the reader thread?

andy.fingerhut20:01:42

For Clojure/Java, the value passed back is just a pointer, i.e. a Java reference. It will not make a "deep copy" or anything like that. Pretty much nothing in Clojure makes a deep copy of anything, unless you do it yourself.

andy.fingerhut20:01:01

Safely passing objects between Java threads requires proper synchronization, which should be implemented for you already for all immutable Clojure values, including collections. For other Java objects, it depends on their implementation.

clojurians-slack10021:01:45

I'm using a Ring request's :body's .hasContent (https://www.eclipse.org/jetty/javadoc/current/org/eclipse/jetty/server/HttpInput.html#hasContent() ) in a handler, but ring-mock uses ByteArrayInputStreams for mock requests' bodies, which causes tests to fail with an error that .hasContent doesn't exist. What is the "Right Way" to hack in a .hasContent to specific ByteArrayInputStream instances? I've looked at reify, extend and related, but haven't found anything that works.

hiredman21:01:09

the ring spec says it is an inputstream, which doesn't have that method, you are looking at a particular implementation of the ring spec, that happens to use a subclass of inputstream which has that method

hiredman21:01:58

using that method means you are not using the ring spec, which is why it will break when you use things like ring-mock and that stick to the spec

clojurians-slack10021:01:17

Ah, right. I keep forgetting that Ring is a spec 🙂

clojurians-slack10021:01:18

Hmmm... Maybe I need something with "lower level" support then. Thanks @hiredman.

dharrigan22:01:02

Is it possible to defmacro that would be available in all namespaces (of the project?)

noisesmith22:01:56

any macro must be in a namespace, all namespaces are potentially available

dharrigan22:01:43

yes, but that would mean that I would have to import the namespace (with the macro) into each other namespace. I get that (and I understood that would be the case), but I was wondering that if I define a macro, can it be treated like one of the special forms, like when-let where it's in core and available everywhere, perhaps by defining my own namespace that would be available everywhere too - rather than importing...

dharrigan22:01:16

I could mitigate this by importing the namespace and using a small alias, like m so I could do (m/my-funky-macro ....)

didibus06:01:09

Is this for your REPL?

didibus06:01:32

Because in non REPL contexts, you want to make sure that you require or use the dependent namespaces always. Using a fully qualified function from another namespace if it wasn't loaded, thus you want to be sure you do by explicitly declaring a require or use on them.

didibus06:01:36

In REPL contexts, I declare all these fns and macros I want everywhere in the user.clj file. That file is auto-required by the REPL, and so you can start using functions from it directly without requiring it.

didibus06:01:57

But, if you mean to say only within a given namespace that you explicitly required, you can use :refer :all or use to be able to call the functions or macros from the required namespace with just their name like when-let

didibus06:01:56

That said, its not good practice when not in a REPL context, since it makes it hard for people to track where the fn or macro originates from.

dharrigan08:01:15

No, not for the REPL, for the project - but thank you for helping out too! It's all good and based upon the excellent advice here and above, I can move forward with a design decision 🙂

didibus17:01:11

If its for project code, you definitely want to have a require and use an alias.

hiredman22:01:45

when-let is not a special form

hiredman22:01:57

it is a macro in the clojure.core namespace

dharrigan22:01:58

I meant macro 🙂

dharrigan22:01:14

I am wearing my n00b hat 100% 🙂

hiredman22:01:59

the ns macro just ends up making all of clojure.core available unqualified by default, if you create your ns some other way it won't be

ghadi22:01:38

this is the way to go

dharrigan22:01:39

Linking to my own suggestion - I like it 🙂

dharrigan22:01:10

Thanks everyone - appreciate it.

andy.fingerhut23:01:20

I mean, if you want, you can define new functions and/or macros in clojure.core, but I wouldn't recommend it.

didibus06:01:32

Actually don't think you can

didibus06:01:40

Because clojure.core is AOT and direct linked

andy.fingerhut07:01:24

$ clj
Clojure 1.10.1
user=> (doc foo)
nil
user=> (foo 7)
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: foo in this context
user=> (in-ns 'clojure.core)
#object[clojure.lang.Namespace 0x2e61d218 "clojure.core"]
clojure.core=> (defn foo "foo in clojure.core" [x] (+ x 5))
#'clojure.core/foo
clojure.core=> (in-ns 'user)
#object[clojure.lang.Namespace 0x235a0c16 "user"]
user=> (ns bar)
nil
bar=> (doc foo)
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: doc in this context
bar=> (clojure.repl/doc foo)
-------------------------
clojure.core/foo
([x])
  foo in clojure.core
nil
bar=> (foo 7)
12

andy.fingerhut07:01:47

For most purposes, it is just another namespace.

didibus07:01:33

Try with a macro?

didibus07:01:46

Cause it didn't work for me, but I tried with a macro

andy.fingerhut07:01:08

Note that I created a new namespace bar to test it in. foo wasn't visible in user namespace for some reason, perhaps because it did the refer-clojure operation before I defn'd foo. Not sure exactly what is happening there.

andy.fingerhut07:01:20

Yep, new defmacro created in clojure.core was visible in ns bar also

didibus17:01:02

Ah, I was just moving back to user, and you're right, you need to force refer again, or call ns again to have it refer the new clojure.core vars

noisesmith23:01:40

there's a library that uses some weird hack to make a . namespace, so your macro could be ./my-funky-macro - but this is meant more as a dev time convenience

noisesmith23:01:59

having namespaces that let a human reader know where something came from is actually a very nice feature

dpsutton23:01:27

annoying trying to read scheme, common lisp, and emacs lisp for that reason

noisesmith23:01:14

I even get annoyed by the way java code examples always leave out the import clause / full package name, with the assumption you have a tool that inserts the import for you

noisesmith23:01:46

language conventions that avoid needing tooling > tooling

dpsutton23:01:52

yes! examples that import package.* are incredibly annoying

didibus06:01:02

Oh man, and I hate static imports, I guess similar to how I hate use or refer all, though I understand its value at the repl

andy.fingerhut23:01:38

Single-letter or otherwise short aliases seem far preferable, if you can stand to type them 🙂

noisesmith23:01:03

right, and explicit aliases to a namespace with a meaningful name in the ns block

vachichng23:01:39

hi, why my repl prints less info when there is an exception? I'm using this library https://github.com/ptaoussanis/truss , calling the sample function

(defn square [n]
  (let [n (have integer? n)] ; <- A Truss assertion [1]
    (* n n)))

(square nil)
it should print something like
;; Invariant violation in `taoensso.truss.examples:10`.
;; Test form `(integer? n)` with failing input: `<nil>`
;; {:*?data* nil,
;;  :elidable? true,
;;  :dt #inst "2016-10-14T10:01:28.671-00:00",
;;  :val nil,
;;  :ns-str "taoensso.truss.examples",
;;  :val-type nil,
;;  :?err nil,
;;  :*assert* true,
;;  :?data nil,
;;  :?line 10,
;;  :form-str "(integer? n)"} 
but I only get
Syntax error (ExceptionInfo) compiling at (src/clj/sample/core.clj:200:1).
Invariant violation in `pim.product.core:198`. Test form `(integer? n)` failed against input val `<truss/nil>`. 
it happens both at Intellij with cursive and launching lein repl from terminal. I'm using the latest clojure version

noisesmith23:01:29

@vachichng if you evaluate *e , that shows the full printed form of the most recent exception

noisesmith23:01:14

this is described in the repl startup splash, alongside *1 etc. for most repls

vachichng23:01:55

@noisesmith oh thanks, it worked! how can I set that as default?

noisesmith23:01:42

that's set by the repl itself, I don't know if there' s a universal answer

noisesmith23:01:53

are you using nrepl, clj, socket repl?

noisesmith23:01:34

where you might just want pst (which is in clojure.core) without the clj-stacktrace dep

noisesmith23:01:39

I wonder if there's a more generic answer that would work with clojure.main / socket repls - maybe starting a new repl with a different error handling function is possible? sadly these days calling pr on an exception-info object has better info than pst

alexmiller05:01:28

You can use any accept function with the socket repl - the provided repl is just one convenient answer

vachichng23:01:03

@noisesmith tried both ways, as you said, and from the github comment, but still getting the same results, no stacktrace printed

seancorfield23:01:40

user=> (clojure.main/repl :caught pst)
user=> (/ 1 0)
ArithmeticException Divide by zero
	clojure.lang.Numbers.divide (Numbers.java:188)
	clojure.lang.Numbers.divide (Numbers.java:3901)
	user/eval144 (NO_SOURCE_FILE:1)
	user/eval144 (NO_SOURCE_FILE:1)
	clojure.lang.Compiler.eval (Compiler.java:7177)
	clojure.lang.Compiler.eval (Compiler.java:7132)
	clojure.core/eval (core.clj:3214)
	clojure.core/eval (core.clj:3210)
	clojure.main/repl/read-eval-print--9086/fn--9089 (main.clj:437)
	clojure.main/repl/read-eval-print--9086 (main.clj:437)
	clojure.main/repl/fn--9095 (main.clj:458)
	clojure.main/repl (main.clj:458)
(starting a repl inside a repl)

noisesmith23:01:52

ahh! that's the option I was missing

noisesmith23:01:08

(cmd)user=> (clojure.main/repl :caught pr)
(cmd)user=> (throw (ex-info "foo" {:a 0}))
#error {
 :cause "foo"
 :data {:a 0}
 :via
 [{:type clojure.lang.ExceptionInfo
   :message "foo"
   :data {:a 0}
   :at [user$eval9 invokeStatic "NO_SOURCE_FILE" 1]}]
 :trace
 [[user$eval9 invokeStatic "NO_SOURCE_FILE" 1]
  [user$eval9 invoke "NO_SOURCE_FILE" 1]
  [clojure.lang.Compiler eval "Compiler.java" 7177]
  [clojure.lang.Compiler eval "Compiler.java" 7132]
  [clojure.core$eval invokeStatic "core.clj" 3214]

noisesmith23:01:16

pr is so much better than pst now

seancorfield23:01:08

A built-in default that trimmed :trace would be nice tho'...

noisesmith23:01:24

@vachichng so if the right :caught is set you can get better printing behavior, and you can start a new subrepl and supply any one-arg-function you like there

vachichng00:01:57

yeah, it worked on the terminal launched repl, but still not working under Intellij cursive nrepl

noisesmith00:01:38

right - it only takes effect in the repl that clojure.main starts, it doesn't change any behavior of the parent

noisesmith00:01:16

I wouldn't be surprised if there was an nrepl middleware out there somewhere that improves trace printing as well

vachichng00:01:51

yeah, there is one for cider-nrepl

didibus06:01:57

I havn't used Cursive in a while, but I think it has a button to show the full exception

didibus06:01:02

Something like: Print last exception

didibus06:01:39

And you can bind a shortcut for it I think

vachichng00:01:30

yeah, you are right, there is an action for that, many thanks for the tip!

seancorfield23:01:25

There's Throwable->map if you want to turn exceptions into data and manipulate them.

noisesmith23:01:49

that's what pr/ prn use under the hood for exceptions now right?