Fork me on GitHub
#beginners
<
2018-02-22
>
Drew Verlee04:02:20

Anyone give Pyro a try yet? I included it my ~/.lein/project.clj deps and run lien run and dont see any difference…

eggsyntax16:02:52

I'm seeing the same thing, after following the instructions in the README,including calling (printer/swap-stacktrace-engine!). I feel like I'm probably missing something obvious here. @U0A59AFJA any clue what silly thing we might be doing? I'm using CIDER, if that makes any difference. Whether I cause an exception from the REPL or trigger it in code, I just get an ordinary stacktrace.

venantius16:02:01

Hi all - if you’re using Clojure 1.8.0+ I think you’ll need to wait for the next version - I developed it on Clojure 1.7.0 and some of the hooks have changed.

venantius16:02:38

If you’re using Clojure 1.7 and having problems please open an issue on the project and I’ll dig into it

venantius16:02:06

Also @U077BEWNQ — I’m not too familiar with CIDER but I know it has its own nREPL middleware that might have control over stacktraces. I’d check and see if you get issues at a terminal-based leiningen REPL as well.

eggsyntax16:02:05

I bet it's the clj version thing, I'm on 1.9. That makes sense, then. Looking forward to the next version, then, and thanks for the awesome tool!

Drew Verlee20:02:59

This answers my question. Thanks!

Will16:02:37

Can somebody explain what the partial function does in this code? ((map (partial into {})) (sequence of maps))

Alex Miller (Clojure team)16:02:54

(partial into {}) is the same as #(into {} %)

Alex Miller (Clojure team)16:02:08

the rest of that code doesn’t seem to make sense though

Will16:02:04

I was trying to simplify my code as an example but I guess the code doesn’t work, the seq is a list of maps

Will16:02:45

Thanks @alexmiller that makes more sense

Alex Miller (Clojure team)16:02:51

If you are trying to merge maps, just use merge

Alex Miller (Clojure team)16:02:18

(apply merge seq-of-maps)

noisesmith17:02:09

@alexmiller the original request was “how to turn an array of java LinkedHashMap into a list of clojure maps”

noisesmith17:02:33

there’s too many parens in that quote

Alex Miller (Clojure team)17:02:00

sorry, didn’t have all the context

noisesmith17:02:01

np - oh the original question asked for a vector, and the quote leaves out the into []

noisesmith17:02:08

now I get how we end up with that

Will17:02:46

Ya that was my bad @alexmiller I was trying to simplify, should have just posted the code lol, @noisesmith is correct

noisesmith17:02:42

@josmith2016 (into [] (map (partial into {})) c) takes some input that can be sequenced (I think it was an array you had originally?) and makes each element into a clojure hashmap, putting the result into a vector

noisesmith17:02:05

(into [] x) just makes a vector out of the contents of x

noisesmith17:02:26

(map f) can be supplied to into as a way to transform elements as they are put into a result

noisesmith17:02:56

(partial into {}) is the same as #(into {} %) and it creates a hash-map from some other collection

noisesmith17:02:09

(as long as each element can be turned into a map entry)

Will17:02:02

That makes a lot more sense, thanks @noisesmith

andy.fingerhut17:02:34

It seems like someone may have already written some kind of Clojure function that walks an arbitrary nested data structure, or at least descends into things that implement java.util.Set, java.util.List, java.util.etc interfaces, and converts them to the corresponding Clojure immutable types?

noisesmith17:02:59

@andy.fingerhut I wonder if clojure.walk/postwalk would just do that with an identity arg?

andy.fingerhut17:02:09

That sounds like something that might be made general purpose for people getting mutable collections from Java libs and making them more useful in Clojure.

andy.fingerhut17:02:39

Yeah, sounds like a job postwalk could be made to do.

noisesmith17:02:31

actually needs prewalk because otherwise it just bottoms out at non-clojure data types

andy.fingerhut17:02:32

Hmm. I haven't done it, but was guessing that there must be a component of it that needs to convert members of a container, before creating the container to hold them.

noisesmith17:02:49

I have an example that will work as soon as I find the right predicate for “is this some sort of array?”

noisesmith17:02:04

this doesn’t look promising for making a predicate

> (supers (class (int-array 0)))
#{java.io.Serializable java.lang.Object java.lang.Cloneable}

noisesmith17:02:25

=> (.isArray (class (int-array 0)))
true
- awesome

noisesmith17:02:01

@andy.fingerhut @josmith2016

(require '[clojure.walk :as walk])

(def input
  (into-array Object [nil
                      (java.util.HashSet. [1 2 3 4])
                      (into-array [1 2 3])
                      (doto (java.util.LinkedHashMap.)
                        (.put "a" 1)
                        (.put "b" 2))]))

(defn ->clj
  [original]
  (walk/prewalk
   (fn [x]
     (cond (nil? x) nil
           (.isArray (class x)) (into [] x)
           (instance? java.util.List x) (into [] x)
           (instance? java.util.Map x) (into {} x)
           (instance? java.util.Set x) (into #{} x)
           :else x))
   original))
(ins)user=> (load-file "/tmp/toclj.clj")
#'user/->clj
(ins)user=> (->clj input)
[nil #{1 4 3 2} [1 2 3] {"a" 1, "b" 2}]

Will17:02:57

Thanks guys

Will17:02:37

Do I just put that in my clojure namespace @noisesmith?

noisesmith18:02:06

@josmith2016 you could adapt that to make it a function - be sure to actually require clojure.walk rather than using it by the full name

noisesmith18:02:59

if you know the exact structure beforehand a function that targets that structure directly will be more efficient, but if you want a general purpose “make clojure hash-maps and vectors from any input” that prewalk should do OK

noisesmith18:02:49

or be a start at least (- exercise for the reader you could convert iterators to lazy-seqs etc.)

andy.fingerhut18:02:38

also could add sets easily

noisesmith18:02:48

oh, duh, of course 😄

Will18:02:53

I keep getting a null point on this line (.isArray (class x)) (into [] x) @noisesmith, can I pass in any type of object, or does it have to be a specific kind?

noisesmith18:02:21

oh! add (nil? x) nil as the first part of the cond

noisesmith18:02:35

I totally forgot to make it nil safe facepalm

Will18:02:53

Would that mean I’m passing in a nil object?

noisesmith18:02:14

prewalk is recursive, it means something somewhere in the nested structure contains a nil

noisesmith18:02:18

or that you simply passed nil

Will18:02:28

Ok I’ll try that, thanks

Will18:02:39

That’s awesome @noisesmith! it worked. thanks a lot 🙂

noisesmith18:02:04

@josmith2016 cool - I updated the paste with the differences we talked about (mostly)

noisesmith18:02:00

I’m almost certain that the only reason something like ->clj doesn’t ship with clojure is to discourage the massive slowdown of code that uses that for convenience regardless of what you might know about input data (see the discouragement of using js->clj and clj->js in clojurescript code)

Will18:02:14

This looks like something only a beginner clojure developer would need right?

Will18:02:53

How much slower is it to use that method?

noisesmith18:02:31

I don’t know about only beginners… how much slower would depend on the input

noisesmith18:02:51

interesting question though…

Will18:02:44

That’s right, it would be helpful if you don’t know what the input is already.

noisesmith18:02:02

yeah - and this is less useful in clj vs. cljs because most java apps don’t use arrays, maps, sets - they use weird object types instead

Will18:02:28

Ya, all I’ve used is the weird object types, but now I’m starting to wish they didn’t use them at all

noisesmith18:02:08

yes, this is a lot of the appeal of clojure

noisesmith18:02:15

@josmith2016 since you asked about speed I decided to measure it - a trivial translation to a direct transform (vs. the general pre-walk) was 4x faster for the example input I chose originally

(ins)user=> (require '[criterium.core :as crit])
nil
(ins)user=> (load-file "/tmp/toclj.clj")
#'user/->clj
(ins)user=> (crit/bench (->clj input))
Evaluation count : 5073240 in 60 samples of 84554 calls.
             Execution time mean : 12.089228 µs
    Execution time std-deviation : 377.278725 ns
   Execution time lower quantile : 11.568031 µs ( 2.5%)
   Execution time upper quantile : 13.001664 µs (97.5%)
                   Overhead used : 1.970251 ns

Found 3 outliers in 60 samples (5.0000 %)
        low-severe       3 (5.0000 %)
 Variance from outliers : 17.4346 % Variance is moderately inflated by outliers
nil
(cmd)user=> (crit/bench (into [] [(first input) (into #{} (second input)) (into[] (nth input 2)) (into {} (nth input 3))]))
Evaluation count : 21628200 in 60 samples of 360470 calls.
             Execution time mean : 2.898974 µs
    Execution time std-deviation : 103.854882 ns
   Execution time lower quantile : 2.755878 µs ( 2.5%)
   Execution time upper quantile : 3.119350 µs (97.5%)
                   Overhead used : 1.970251 ns

Found 1 outliers in 60 samples (1.6667 %)
        low-severe       1 (1.6667 %)
 Variance from outliers : 22.2286 % Variance is moderately inflated by outliers
nil

Will18:02:18

Woah, thats a lot slower

alex31415919:02:10

Hello - is it possible to start a clojure program and then end up in the repl? Like doing lein run which launches the main function and then be left in the repl? Thanks,

noisesmith19:02:28

@alexandre.almosni lein run -m clojure.main

noisesmith19:02:51

you might need to require and switch to your ns by hand, and you probably want to add rlwrap on there too

noisesmith19:02:15

oh, using -m clojure.main doesn’t start your app though - maybe you just want to invoke clojure.main from your own app? or start a socket repl or nrepl

noisesmith19:02:25

if you literally want to run a repl inside your running app the simplest thing might be to call (clojure.main/main) at the end of your startup function

noisesmith19:02:40

you might need to put a server into a future or something to make it work though

alex31415919:02:33

@noisesmith thanks a lot let me try that!

noisesmith19:02:53

@alexandre.almosni my normal dev workflow is to start a repl with lein repl and then start my app in a background thread

alex31415919:02:42

That’s what I do now, but my lazy self wanted to do both at once a bit like in Python

noisesmith19:02:02

I don’t know if any other option is actually as simple and well featured

seancorfield19:02:55

If your app uses Component (or similar), then your -main is not much more than (component/start (build-system)). I tend to have a (comment ...) form at the bottom of my main namespace that has expressions to build & start my application Component for dev. I almost never use a standalone REPL -- I usually work from my editor and send forms to the REPL from source files (and I almost never type into the REPL directly).

seancorfield19:02:59

https://vimeo.com/223309989 -- REPL-driven development by Stuart Halloway

seancorfield19:02:27

I'm pinning that because I think everyone getting started with Clojure should watch it 🙂

alex31415919:02:48

I basically have an app that connects to a server and does data processing at regular intervals - it’s nice for me to have it in a repl to investigate / debug but I’d also like to have the option to have a shell script that user with no programming knowledge can double click to launch the app. @seancorfield thanks for the links and I’ll check Component!

seancorfield19:02:53

@alexandre.almosni One option might be to run your app with the Java options to start a Socket REPL Server so you can use a bare bones REPL for debugging? (we do that for one of our apps at work, then we can telnet into the app and it prompts with a REPL)

alex31415919:02:56

Yes that’s exactly my use case actually - being able to remote debug when needed! Thank you

Kevin Casey19:02:10

I'm having trouble getting these :npm-deps examples working: https://anmonteiro.com/2017/03/requiring-node-js-modules-from-clojurescript-namespaces/ I posted some of the details in the comments of @anmonteiro’s blog post. Does anybody know how I can further investigate the Uncaught Error: Undefined nameToPath problem? I found this old log where @madstap said he got it working: https://clojurians-log.clojureverse.org/clojurescript/2017-10-24.html I already tried a couple different versions of npm. Does anybody have the full example working in github?

madstap20:02:27

@kevincasey I did get it working, but only kind of, in the end I just included the damned lib from a cdn and used cljs-oops. Try rm -r node_modules? I remember that solved a problem for me at some point while trying to make npm-deps work.

Kevin Casey20:02:05

ok. thanks. I have nuked node_modules several times. I was able to get this example working in a Leiningen build with :npm-deps but I had trouble with moment and left-pad.

(ns example.core
  (:require [react :refer [createElement]]
            ["react-dom/server" :as ReactDOMServer :refer [renderToString]]))

(js/console.log (renderToString (createElement "div" nil "Hello World!")))
Then I switched to the barebones approach with java -cp cljs.jar:src clojure.main build.clj

sundarj21:02:19

i've heard that http://shadow-cljs.org/ has better npm deps support than the main compiler

Kevin Casey21:02:00

thanks. I'll check it out

justinlee21:02:18

It definitely does and if you do a bunch of npm work you’ll thank yourself for using it. You just install stuff using npm or yarn and things work. Jump into #shadow-cljs if you do try it. npm-deps has never worked for me.

Kevin Casey21:02:42

got it to work! after messing around with the goog.addDependency and goog.provide I just deleted the whole out directory and main.js. I think bumping up the node version helped too

Kevin Casey21:02:47

I don't remember seeing this before. I never would have guessed to add it goog.require('module$Users$kcase$projects$clojurescript_npm_simple_example$node_modules$left_pad$index');