Fork me on GitHub
#clojure
<
2017-01-03
>
notanon00:01:28

are you using lein or boot

bcbradley00:01:39

i can use either

notanon00:01:53

just add [enlive "1.1.6"] to the dependencies section and restart your repl

notanon00:01:06

then (require '[my.library :as whatever]) in the repl

notanon00:01:28

or whatever dependency

bcbradley00:01:11

its unfortunate that I would have to make a project and edit the dependencies to access a remote maven repository without hassle, or edit the global dependencies (which would pollute any future project if i forget to remove it)

bcbradley00:01:28

ideally you should be able to just start a new repl from an old repl, with new dependencies

notanon00:01:46

the JVM does not support adding code at runtime, i'm amazed there's libraries to even hack it

notanon00:01:14

like tolitius and hiredman said though, there's apparently a way to do it

notanon00:01:57

it's not something i imagine being worth the effort though, the amount of time you spend downloading libraries should be a very small part of the total time you spend writing code

hiredman00:01:09

the jvm does infact support it very well

bcbradley00:01:31

well this isn't really a serious thing, I was just hoping that the repl would be powerful and flexible enough for me to rely on it for hokey pokey stuff

bcbradley00:01:37

like "lets parse this random webpage"

bcbradley00:01:44

"oh that tool looks cool, i'll get it from maven"

bcbradley00:01:03

you know, something i can just start up without making a project and jumping through a few hoops

bcbradley00:01:10

its not that much effort to make a new project

hiredman00:01:11

the jvm was originally conceived as a environment for set top boxes

tolitius00:01:11

@bcbradley: > its unfortunate that I would have to make a project and edit the dependencies you would not need to if alembic is in your ~/.lein/profiles.clj, since a call lein repl would load it

hiredman00:01:32

and its classloader system provides for loading code in from anywhere basically

notanon00:01:34

you cant reload a class at runtime right?

bcbradley00:01:36

yes but then it would pollute any other project i make

tolitius00:01:40

then from within the repl you can just:

(alembic.still/distill '[org.clojure/tools.logging "0.3.2"])

hiredman00:01:40

the tricky thing is visibility

bcbradley00:01:01

i was thinking of the repl kind of like unix command line

bcbradley00:01:09

like, you just use it for utility if you want

bcbradley00:01:17

i guess it isn't quite like that

hiredman00:01:25

exactly, class definitions are not mutable

notanon00:01:31

the repl is an empty environment ready to execute code

notanon00:01:35

that is all

hiredman00:01:17

and a class technically is idenitifed by its name and the classloader that loaded it, which is why you can get weird errors about not being able to cast an instance of Foo to Foo

bcbradley00:01:29

you know it wouldn't be that hard to make it more flexible in the way i'm imagining, if the repl had the ability to spawn a new repl with a different context

tolitius00:01:34

@bcbradley: if you just want to try some lib you can: https://github.com/rkneufeld/lein-try

notanon00:01:51

@hiredman yeah like 400 version of log4j 🙂

bcbradley00:01:57

like we have a custom symbol for exiting a repl

bcbradley00:01:01

its called "exit"

bcbradley00:01:15

it would be cool to have another for spawning a new repl with different dependencies

notanon00:01:36

lein-try sounds like what you're talking about

notanon00:01:48

minus spawning new repls

hiredman00:01:58

the exit thing isn't part of clojure

hiredman00:01:07

some other tool you are using is adding that

notanon00:01:09

thats in the clojoure.repl namespace, no?

notanon00:01:42

nvm it's being loaded by nrepl probably

hiredman00:01:13

yeah, the other thing is, most of what you think of as the "clojure repl" is provided by other tools on top

bcbradley00:01:35

well i mean it doesn't matter where it comes from really

tolitius00:01:53

@bcbradley: btw with boot it's even simpler

$ boot -d clj-time repl
;;; output omitted
boot.user=> (require '[clj-time.core :as t])

hiredman00:01:01

well it does, it matters who's ear you need to get the feature added, and how many people you need to talk too

notanon00:01:14

well add lein-try or alembic to your project

notanon00:01:27

and then your repl is a lot more powerful (well featureful)

bcbradley00:01:04

i've sort of had a breaking up with lein

bcbradley00:01:13

i think i'll try the boot -d approach

hiredman00:01:48

java -jar clojure-1.9.0-master-SNAPSHOT.jar is how to launch a bare repl, which is very austere

hiredman00:01:16

paired with rlwrap or run in eshell it is ok

bcbradley00:01:57

i can see how not being able to dynamically load code at runtime might be a bit frustrating

bcbradley00:01:10

for instance, if i discover i need x y z tools while i'm in the middle of a repl session

notanon00:01:13

if you load a new class, it's fine

bcbradley00:01:19

it would be a pain to restart everything with that new dependency

bcbradley00:01:47

i'm just trying to make the repl more than it is i guess

notanon00:01:49

but the odds of pulling in a random jar and all of it's jar dependencies and not getting random versions of common classes intermixed sounds likea miracle to me

hiredman00:01:20

so people have come up with ways to do it, I even have my crazy trick for it that I use to write shell scripts with clojure

hiredman00:01:40

but for example, alembic, I had that enabled for a while

hiredman00:01:44

but I never used it

notanon00:01:50

like i said earlier, the amount of time you spend looking for a library is going to be a very small amount of time compared to using those libraries. restarting takes like 10 seconds... not worth the effort imho

notanon00:01:21

magic 🙂

notanon00:01:45

thumbs up to whoever wrote that

bcbradley00:01:24

"the dream" would just be being able to look through github or maven for whatever cool fancy thing you want to play with, and being able to play with it at any time in any repl, without creating a new repl or any of that. I realize that there may be technical issues with trying to implement that because of the way java classloaders work, but i'm just trying to get you in the mood of mind that i'm in so you can see where i'm coming from. When I want to goof around with webpages on a unix command line i can just use curl, I can grep and do all kinds of stuff. When I want to get the latest greatest tool I can do that, straight from the command line. I don't have to create a new shell to do it. I'd like something similar in the repl. Again, maybe I'm just trying to make the repl more than it is, but it feels so powerful as a tool I'm compelled to to use it anywhere that I can, because when I'm able to use it I work faster, easier, and with less errors.

notanon00:01:12

tolitius just linked you to the dream

notanon00:01:52

just run that set-env! function in a boot powered repl and you have what you want

bcbradley00:01:30

thats exactly what i wanted!

lvh02:01:45

This might be my computer’s way to tell me to call it a day, but… I have a test ns that fails to compile when this new fn I added has a question mark in the name.

Error refreshing environment: java.lang.RuntimeException: No such var: r/xy-zzy?, compiling:(payne/refl_test.clj:95:3)
renamed to: xyzzy: works fine. Renamed to xy-zzy: works fine.

lvh02:01:34

Doesn’t seem to matter if I varquote it or not.

lvh03:01:14

What the heck? hello? works fine; typedesc? does not

andy.fingerhut03:01:44

I haven't seen that "Error refreshing environment" before. It isn't in Clojure itself, nor tools.namespace. Do you know which tool is producing that message?

lvh03:01:14

andy.fingerhut: that’s lein-test-refresh; but the error happens in CIDER or with plain old lein test, too

andy.fingerhut03:01:35

You get 'Error refreshing environment' part of the message when running 'lein test' at a shell prompt?

lvh03:01:55

No, but I get the java.lang.RuntimeException: No such var: r/xy-zzy?, compiling:(payne/refl_test.clj:95:3) with associated stack trace.

lvh03:01:02

(Same in my editor.)

qqq03:01:27

is there a way to define a "all.clj" file which just :requires other namespaces, then exports functions and macros ? I know how to export functions from other namespaces, but not sure how to export macros from other namespaces

qqq03:01:30

Clojure namespaces conflate the layout of your code and your API. For larger libraries, this generally means that you either have large namespaces (e.g. clojure.core) or a large number of namespaces that have to be used in concert to accomplish non-trivial tasks (e.g. Ring). <-- so true, exact problem I'm running into, in particular too many small namespaces

qqq04:01:42

I don't know if this is on topic or off topic. I am editing *.cljc files in emacs/cider. When dealing with large (300+ line files), I am having trouble getting a "summary view" of the file. I am already using emacs show-hide. Are there other things that can help me?

tbaldridge04:01:37

Please don't use potemkin....

tbaldridge04:01:22

It really does way to much mucking with the internals of Clojure, it's a fantastic way to introduce a ton of hard-to-debug issues when it comes to compilation and runtime debugging.

tbaldridge04:01:20

@jtmarmon at least don't use it unless you understand how it works and all the side-effects it could have on the Clojure runtime.

qqq04:01:38

I'm currently moving towards "large *.clj files", but I need better tools for managing a single file

tbaldridge04:01:03

Well 300+ lines isn't large at all...something must be wrong with your editor.

tbaldridge04:01:14

about 5k lines is "large"

tbaldridge04:01:52

@qqq things that can help a lot: enabling "jump to definition" in your editor. Also "show uses". Using those two I rarely care where a thing is defined. I simply navigate via callers/definers

jtmarmon04:01:19

@tbaldridge sorry for recommending it then! i had just seen it around so i thought it might help him out.

qqq04:01:24

no, it's I used to use vim, recently switched to emacs for clojure/nrepl/cider, and don't have everything setup properly for navigating files

qqq04:01:47

@tbaldridge : okay, will try to navigate via those two functions instead

tbaldridge04:01:17

@jtmarmon oh, don't take it personally 🙂. I just have some issues when it comes that library, too many hours spent debugging code that uses it. It's like a bad bug that will never go away 🙂

tbaldridge04:01:36

I think the summary for Potemkin is perfect....ideas that are "almost" good.

tbaldridge04:01:50

@qqq you're using emacs at the moment?

tbaldridge04:01:24

I'd imagine the summary view is what's slowing everything down. Emacs is single-threaded

dpsutton04:01:07

I don't think he meant the editor is slow

dpsutton04:01:22

but he meant how to start wrapping your head around a large file

dpsutton04:01:31

"get a glance'

qqq04:01:20

@dpsutton , @tbaldridge: yes, I should clarify, my problem is NOT "emacs is slow", my problem is "with emacs hide-show, I can hide-show the entire file, but I only get "one level" of defs, -- I'd somehow like a lartge file to be split into a "tree" of defs that I can better navigate"

qqq04:01:28

emacs performance is fine; the problem is my ability to configure emacs

dpsutton04:01:52

I put this in the other channel, not sure if you saw it

dpsutton04:01:07

but clicking on those makes your buffer expand at that point

dpsutton04:01:14

good for an over view of functions

beppu04:01:03

@dpsutton How did you get those defn's to display folded like that in emacs?

qqq04:01:24

@dpsutton: yes, thanks! I can currently achieve something similar via hide-show ... eh = "only show defn/def lines", ek over a line = expand this particular def; however, this is only "one level" -- I'd somehow like anested/tree view of the functions (like neotree does for a directory tree, but I need this for a single file)

dpsutton04:01:58

its the package loccur

dpsutton04:01:08

install from melpa

dpsutton04:01:17

but it kinda mirrors a builtin to emacs called occur mode

beppu04:01:17

I'll check it out. Thanks.

dpsutton04:01:30

you just give a regex and it collapses all to lines matching that

dpsutton04:01:42

then you navigate to the one you want, press enter and you've expanded back at that area

beppu05:01:56

Ideally, I'd like something that works well with spacemacs. I just gave the hide show minor mode that @qqq mentioned, and those keybindings are killing me.

dpsutton05:01:49

that's one of the reasons i haven't jumped into spacemacs

qqq05:01:57

I'm not using spacemacs either. It's emacs + evil + cider + paredit + helm + projectile + a lot of emacs hydras configured for my particular needs; the most important library being hydra, which allows me to not have to lmemorize the hotkeys I define

beppu05:01:07

I'm a decade+ vim user, so spacemacs feels good to me. Out of all the curated emacs configs out there, it has impressed me the most. I used to use emacs-live before, but it wasn't until spacemacs came along that I felt really comfortable w/ emacs.

beppu05:01:51

It's not exactly vim, but it's vi emulation is good enough for me, and the rest of the configuration is really well thought out. You can use classic emacs keybindings, but the SPC menu provides a nice discoverable alternative that won't kill my fingers and wrists.

qqq05:01:55

@beppu: I'd love to chat more, let's move this to off-topic.

beppu05:01:13

I'll stop now. 😛 (I just wanted to sing its praises.)

seancorfield06:01:19

@tbaldridge for all its problems, Potemkin seems to crop up a lot in real world programs tho'... https://crossclj.info/ns/potemkin/0.4.3/project.clj.html

seancorfield06:01:57

(that doesn't even list clj-http when drags it in as a dependency, for def-map-type)

seancorfield06:01:31

I think this is an interesting downside to Clojure and its ecosystem: it's so easy to just add another dependency to pull in a single, convenient, utility function from some arbitrary library... so your nice, small codebase can easily become a giant ball of 3rd party code when you run it.

qqq06:01:03

http://stackoverflow.com/questions/4690758/splitting-a-clojure-namespace-over-multiple-files <-- is this from 2011 still best practice? (1) I don't want too many namespaces, (2) I don't want files that are too long. This seems like a nice way to split one namespace into many smaller files

leov10:01:06

maybe noob question - I have a java API that has 2 methods - init (takes a listener with onInit, and returns the API object) and doThing. but init does not block while it prepares everything for a couple of seconds - instead it wants from you a listener interface where there is a single method onInit. only then you can call doThing and succeed. (well, in Android this for some reason is quite popular way of doing APIs, maybe in Java as well) what is a clojure idiomatic way to have this API object inside an atom only when it is fully initialized?

leov10:01:36

(def tts (atom nil))

(defn say [text]
  (compare-and-set! tts nil
                    (TextToSpeech.  neko.App/instance
                                   (reify TextToSpeech$OnInitListener
                                     (onInit  [_ status]
                                       (if (= status 0)
                                         (.setLanguage @tts (java.util.Locale. "en"))
                                         (log/e "speech.internal >> Failed to initialize TTS"))))))
  ; doesn't always work, should be placed AFTER initialization finished
  (.speak @tts
          text
          TextToSpeech/QUEUE_FLUSH
          (java.util.HashMap. {TextToSpeech$Engine/KEY_PARAM_STREAM
                               (str AudioManager/STREAM_NOTIFICATION)})))

leov10:01:14

I have a feeling I can somehow invert control flow with core.async here rather simply. (it doesn't work reliably with clojure-android, though)

mpenet10:01:10

A simple clj promise would work

leov10:01:31

yes, but how do I write it in a blocking way?

leov10:01:42

say should block on the first use

mpenet10:01:47

You just deliver! inside init then in your code you deref it

leov10:01:41

omg. thanks

leov10:01:25

I thought promises are about just chaining

jtmarmon11:01:34

>I think this is an interesting downside to Clojure and its ecosystem: it's so easy to just add another dependency to pull in a single, convenient, utility function from some arbitrary library... so your nice, small codebase can easily become a giant ball of 3rd party code when you run it. hmmm I think I must've heard that somewhere... "gem install hairball" 😆

Yehonathan Sharvit14:01:39

What is the proper way to pass a string as is (without the quotes)and wrap it into an s-expression ?

Yehonathan Sharvit14:01:00

I could use (symbol s) or (read-string s)

blkt14:01:13

depends on what you mean by wrapping it into an s-expression

jiri.knesl14:01:45

or (identity s)?

Yehonathan Sharvit14:01:03

Let’s say s is a string that contains an array e.g. "[1 2]"

Yehonathan Sharvit14:01:24

Now I want to put this array inside a list as a single element ([1 2])

Yehonathan Sharvit14:01:59

I need to find a way to get rid of the quotes

blkt14:01:26

you want to read the string

blkt14:01:47

symbol does a different thing

Yehonathan Sharvit14:01:03

What does symbol do exactly?

blkt14:01:11

but that's not a legal expression, you may have to quote it to make it work

blkt14:01:31

symbol creates a symbol named with the string pass to it

blkt14:01:46

i.e. (symbol "foo") => foo

blkt14:01:10

just like keyword creates a keyword, i.e. (keyword "foo") => :foo

blkt14:01:14

symbol called on a string with spaces should output a symbol like (symbol "a b") => |a b| iirc

blkt14:01:17

but creating symbol at runtime without restrictions is pretty bad

blkt14:01:50

also, reading or evaluating strings at runtime is bad aswell, as they may contain nasty commands

blkt14:01:12

take a look at clojure edn, it should do the trick

Yehonathan Sharvit14:01:26

Why creating symbol at runtime is dangerous?

blkt14:01:39

it may generate a lot of garabage

blkt14:01:45

causing memory leaks

blkt14:01:26

that's a problem in Erlang aswell

blkt14:01:39

any language that support creations of symbols I think

mpenet14:01:24

not necessarly, ex clojure keywords

mpenet14:01:02

not that' I'd advise going crazy generating insane amounts. But I don't think you can oom creating huge amount of kw at least

mpenet14:01:56

the internal keyword map uses weak refs if I recall

blkt14:01:17

well, you pollute namespaces at the very least, don't you?

mpenet14:01:27

then it's arguable that erlang atoms and clojure keywords are similar

mpenet14:01:02

erlang atoms can lead to problems tho, they are never gc

Yehonathan Sharvit14:01:05

The problem with read-string is that if the string contains an invalid expression, it will throw an exception

Yehonathan Sharvit14:01:17

So I’m really tempted to use symbol

blkt14:01:46

why would you want an invalid espression in literal clojure syntax?

blkt14:01:57

I mean, what's the "business need" for it?

Yehonathan Sharvit14:01:33

Ok. the full use case is for supporting rendering reagent component inside klipse https://github.com/viebel/klipse

Yehonathan Sharvit14:01:20

There is a code snippet that contains the reagent component e.g. [:div “Hello World!”]

Yehonathan Sharvit14:01:24

And I need to wrap it into a call to (reagent.core/render-component s container)

Yehonathan Sharvit14:01:42

and pass this string into a eval-str function

Yehonathan Sharvit14:01:17

I wrote it this way: (str `(reagent.core/render-component ~(read-string s) (js/document.getElementById “id")))

blkt14:01:20

that looks like job for a macro to me

Yehonathan Sharvit14:01:34

how exactly a macro will help?

blkt14:01:48

wait, you just want to output the string

blkt14:01:50

for example

blkt14:01:23

(str (whatever-quote-was-that (reagent.core/render-component ~(read-string s) (js/document.getElementById “id")))) => "(reagent.core/render-component [1 2 3] (js/document.getElementById \“id\"))" ?

Yehonathan Sharvit14:01:26

@blkt how can I achieve that?

tbaldridge14:01:24

@blkt no, symbols are completely detached from namespaces.

tbaldridge15:01:09

@viebel At this point it might be cleaner to simply write your own printer. If this is CLJS you could setup a condp that dispatches on satisfies? and various protocols. Then simply walk the data structure. Not sure exactly why you need this, but there's been times I've needed slightly different printing rules, and writing a custom printer is the simplest approach.

tbaldridge15:01:01

You only really have to extend it to Sequence, ISeq, Associative, Numbers, and Strings. And depending on the shape of your data, perhaps even less than that.

Alex Miller (Clojure team)15:01:11

or you could just tweak the existing printer

neupsh16:01:11

Hi, I want to write a function which takes an argument (lets say for a device), and returns the status of the device. Now, i want to write a function, which can dispatch based on the type of argument - if 'device' record is passed, get device-id from the record and make external call, if 'String' is passed, then use it as device id and make external call. In both case, there will be single argument. What is the most idiomatic way of doing this? I am thinking a multimethod with dispatch based on type would do. Is this idiomatic way of doing it?

mpenet16:01:49

@nux sounds like a good use case for defprotocol

neupsh16:01:48

@mpenet thanks i think protocol will suit more than multi method. I also just came across @alexmiller 's post: http://insideclojure.org/2015/04/27/poly-perf/

qqq17:01:30

m = clojure map, k1, k2 are keys with k1 < k2; is there a way to say "get me all kv pairs where k1 <= k < k2" ?

qqq17:01:56

(without looking at all kv pairs and filtering on k)

joshjones17:01:30

@qqq no — as a map is unordered, there would be no way to forego examining every k-v pair

qqq17:01:59

@joshjones: interesting, so "map" is a hash map, not a red-black/avl tree ?

joshjones17:01:46

let me clarify — there is a sorted map — and array maps are simply an array of kv pairs. but if you’re talking about the notion of a “map” in general — it is associative, not sequential

joshjones17:01:17

{:a 1 :b 2} is an array map. (hash-map :a 1 :b 2) is a hash map

qqq17:01:52

so are hash-map, sorted-map, and {} three different types of maps ?

joshjones17:01:53

yes — the underlying data structure is different

qqq17:01:37

do array-maps even have O(log n) time updates?

qqq17:01:52

I thought that unless you were a red-black tree, you couldn't make that guarantee for persistent data structures

joshjones17:01:58

not sure about how sorted map is implemented, never looked, but yes you can see https://github.com/clojure/clojure/tree/master/src/jvm/clojure/lang has different underlying java classes for PersistentArrayMap and PersistentHashMap

qqq17:01:10

so updates are O(n) }?

qqq17:01:23

(type {}) ==> clojure.lang.PersistentArrayMap

qqq17:01:03

I am not a happy camper 🙂 // this is weird, "maps" with O(n) time updates

isak17:01:06

doesn't it get converted automatically to another implementation when it makes sense?

qqq17:01:36

(type (into {} (for [x (range 1000)] [x x]))) ==> persistent hash map

qqq17:01:53

@isak: looks like you're right

joshjones17:01:29

@qqq — first of all, realize that a map just means: “map some key to some value”. Just as there are different ways to implement a “list” (singly linked, doubly linked, etc), each with tradeoffs and best/worst case runtimes and space v time concerns, there are different ways to implement a “map”. It’s just a data structure, an abstraction, and is not tied to a particular implementation.

joshjones17:01:12

For example, retrieval time is faster on an array map for keys near the front of the array. So if you have a choice to make for the type of map to use with 5-10 kv pairs (a very common use case in clojure), it will almost always be faster to use an array map than an equivalent hash-map, particularly if it’s expensive to compute the hash for the key

tbaldridge17:01:33

@qqq maps start as persistent array maps, and are converted to PersistentHashMaps after more than 8 items are added.

tbaldridge17:01:53

Yep, especially when the structure of an array map will more closely fit with CPU cache lines, etc.

tbaldridge17:01:49

Performance is often all about branches, not so much about actual work done.

kenan.warren17:01:00

Anyone know what the status of strint is in the incubator

kenan.warren17:01:06

looks like it’s been there for awhile

joshjones17:01:38

@qqq to see what @tbaldridge was referring to (the 8-item kv pair threshold to convert an array map to a hash map): https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentArrayMap.java#L203

qqq17:01:50

@tbaldridge , @joshjones : understood, thanks for the clarifications / rationale

carocad18:01:37

hey guys, have anyone used eastwood to check some specs with clojure 1.9? I get some warnings when analizing my code due to some expressions always being true or being redundant 😕

carocad18:01:57

@alexmiller regarging my comment above, I found the problem is the use of clojure/or and clojure/and inside the every macro. I have never written a macro so dont trust me on this one but, wouldnt something like this

{:keys [into kind count max-count min-count distinct gen-max gen]
         :or   {min-count 0, max-count Integer/MAX_VALUE, kind `coll?}} opts
        
solve the problem?

dottedmag18:01:48

Is there a "grouped" view of API documentation? I'd like to learn some new Clojure core functions every day, and doing it in alphabetical way seems stupid -- it should be much easier to learn groups of related functions.

hiredman18:01:03

if you look at http://clojure.org/reference/sequences it has related clojure functions at the bottom

joshjones18:01:15

@dottedmag There’s not one that I know of, but it sounds like a great project (that one could use to learn from while doing, as an added benefit).

dottedmag18:01:54

@jstokes That's a good one, thanks.

Alex Miller (Clojure team)19:01:19

@carocad can you give me an example of what you're talking about? Not getting it

qqq19:01:48

is there a way to put a (break) inside a functikon, then eval something in the repl, and when the (break) line hnits, it jumps me into a debugger, which I can (1) examine locals and (2) move up the stack frame, and examine other locals in other frames ?

arrdem19:01:04

@dottedmag LMK if you have issues with http://conj.io, I’m the operator

joshjones19:01:30

@arrdem, just saw it for the first time, very nice site! :thumbsup::skin-tone-2:

arrdem19:01:26

@joshjones thanks! welcome any/all user feedback, clojuredocs seems to have a lock on the docs market, would like to change that 😛

benfleis19:01:58

@arrdem is there a url for direct search, a la http://conj.io/search/?query=reduce

arrdem19:01:43

@benfleis humm lemme check it’s been a while. Not one that I have documented right now, but similar things do exist.

bfabry19:01:54

@qqq you can do that in cursive

arrdem19:01:06

@benfleis yeah there’s https://www.conj.io/search/autocomplete?query=reduce, but it’s internal. I’ll throw open a ticket about exposing that.

qqq19:01:24

@bfabry: cursive will some me local vas not only in "bottom most frame", but all "clojure frames" ?

qqq19:01:47

in cider, I can only get "bottom most frame"

bfabry19:01:50

good question

cfleming19:01:27

@qqq @bfabry Yes, you can select all previous call frames, and evaluate expressions in the context of each frame

qqq20:01:01

@cfleming: is this a nrepl feature (and I can hope to use it without cursive) or a cursive feature (so I have to buy cursive ot use) ?

benfleis20:01:52

@arrdem cool, thanks. the alternative (for bringing up docs via launchbar, etc.) has always been google searches w/ site: or inurl: tags.

joshjones20:01:55

I use cursive commercially so have a license, but cursive also has a personal and non-commercial license.

cfleming20:01:57

It’s a Cursive feature. Cursive uses the JDI (Java Debug Interface) for debugging, not nREPL. It’s really a JVM feature.

cfleming20:01:37

@qqq Right, as @joshjones says if you’re not doing commercial work Cursive is free.

arrdem20:01:58

@benfleis https://github.com/clojure-grimoire/grimoire/issues/258 I’ll try and take a look at that this week, should be really straightforwards.

qqq20:01:03

I realize this is getting off topic; but if it's JDI -- does this mean nrepl / cider have no support for this? [showing bindings beyond the "bottom most frame"

cfleming20:01:30

Right. The CIDER debugger works in a very different way.

cfleming20:01:43

It transforms Clojure source and instruments it.

cfleming20:01:53

Cursive debugs the compiled bytecode.

cfleming20:01:27

Each has pros and cons - CIDER has expression level debugging, and handles things like threading forms better.

qqq20:01:08

I don't like breakpoints. My ideal debuging situation is (1) run until exception is thrown and (2) go up all the stack frames, lookikng at what values were "passed down"

joshjones20:01:21

you can do that in cursive

dpsutton20:01:27

what was the debugging thing shown at conj?

cfleming20:01:32

Cursive can debug across Clojure and Java (and Kotlin, or whatever else) and has raw access to JVM data (like stack frames and exception trapping) but is line based.

dpsutton20:01:34

that's gonna be right up your alley

qqq20:01:47

prints statements clutter the output; instrumenting everything causes too much stepping; I just want "run until exception, and show stack frames all the way up/down"

cfleming20:01:54

@qqq Cursive can do that, it’s how I do 90% of my debugging.

qqq20:01:03

@cfleming: I may convert.

dpsutton20:01:09

give it a try

joshjones20:01:10

it’s great

cfleming20:01:15

I spoke at Clojure West about the Cursive debugger, the talk is basically one long demo

dpsutton20:01:24

i think its got really good cljs support as well

cfleming20:01:27

I also talk about a lot of the problems debugging bytecode.

cfleming20:01:53

It’s swings and roundabouts, Clojure doesn’t make debugging particularly easy.

qqq20:01:57

https://www.youtube.com/watch?v=vt1y2FbWQMg <-- wait, you're the author of cursive?

cfleming20:01:06

I am indeed.

dpsutton20:01:08

it's a good slack channel haha

qqq20:01:26

no wonder you knew cursive is debubbing clojure via the JDI at the bytecode level

cfleming20:01:45

Right, it’s information from the horse’s mouth.

nooga20:01:51

oh, and there’s a free license for personal work

nooga20:01:25

didn’t know that

bfabry20:01:46

apparently I need to re-watch, I didn't know you could break-on-exception

cfleming20:01:50

@nooga Yes, it’s good for tinkering, OSS, student work etc

cfleming20:01:08

@bfabry It’s the best thing ever.

nooga20:01:31

@cfleming As a propetiary software developer myself, I must ask: how do you know that people aren’t cheating? 😄

bfabry20:01:56

kind of ridiculous considering I've used cursive professionally every day for like 2 years

sveri20:01:56

Its funny in general if you are on a "big" stack and turn on "break on exception". You will hard ever reach your code again, cause there are exceptions everywhere 😄

cfleming20:01:11

@nooga I don’t - the whole thing is one big honesty box 🙂

sveri20:01:14

Not talking about cursive here, but more Java in general

cfleming20:01:02

With the non-commercial licence, basically there’s no way for me to check that since I can’t possibly tell if you’re getting paid for the work you’re doing.

cfleming20:01:35

The nice thing about that is that then I just stop worrying about piracy, since anyone who wants to rip me off can trivially do so with a non-commercial licence.

cfleming20:01:04

So I don’t fret about elaborate licence management schemes, I just do the simplest thing that doesn’t annoy actual users.

qqq20:01:26

From a purely economical point, on any large (> 10 ppl) team, the chance of someone having a moral fiber and whistle blowing is high; and the lawsuit would cost the company far more than the license, so the expected value of cheating isn't even worth it.

cfleming20:01:59

Exactly - companies worry about liability.

arrdem20:01:21

I should figure out how to get work to buy me a copies of gitkraken and cursive...

cfleming20:01:31

I suspect licence checking would mostly catch cases where they’ve just forgotten who has which licence.

johanatan20:01:37

hi, is it a widely held belief among Clojurians that it is not possible to have a "data-oriented language" without it being homoiconic?

cfleming20:01:40

@arrdem Yes please 🙂

qqq20:01:59

https://gist.github.com/leobm/6061734 <-- can this be built into a fully fledged debugger, or is this also limited to just the "bolttom most frame"

qqq20:01:15

(I just got the code working, but I don't see how to extend it)

cfleming20:01:36

@qqq basically, I think you need the JDI to look at previous stack frames. They’re not exposed to the language, so anything working on source manipulation can’t do it.

cfleming20:01:22

There were some projects using the JDI for Clojure debugging: http://georgejahad.com/clojure/cdt.html

cfleming20:01:34

That is very old though.

cfleming20:01:04

I use http://youdebug.kohsuke.org occasionally, I’m considering making a Clojure version

cfleming20:01:18

Much as I hate to admit it though, Groovy actually works better.

joshjones20:01:29

@sveri you can choose a particular type of exception with all sorts of filters, conditions, logging, etc.

cfleming20:01:27

@joshjones @sveri Right, and you can do some neat tricks with breakpoint dependencies, e.g. put a breakpoint at the start of your code, and say my other breakpoints all depend on this one. That means that you don’t break in framework init code etc.

bfabry20:01:18

sounds like I really need to learn the intellij+cursive debugger

cfleming20:01:34

@bfabry And I need to document it

tolitius20:01:54

@qqq just in case you find it useful. you can set an exception breakpoint in intellij: https://www.jetbrains.com/help/idea/2016.3/creating-exception-breakpoints.html which will throw you into the debugger only when then exception occurs, and then you can travel the frozen stack. i.e. cross cutting => you don't need to set a breakpoint in your source to see why the exception happens

joshjones20:01:48

right click on a breakpoint, click “More”, (or Run->View Breakpoints) and you will see lots more options.

tolitius20:01:58

@qqq: (cursive is an intellij plugin)

qqq20:01:21

@tolitius : noted, thanks

cfleming20:01:49

IntelliJ 2017.1 EAP has some neat new features, like this: https://plugins.jetbrains.com/idea/plugin/8537-jvm-debugger-memory-view

qqq20:01:57

After 15+ years on Vim, I just spent 2 months learning emacs/cider, so I'm not ready to switch yet. In clojure, because purity, it's very cheap to save the stack frame right? so all I need is to write a "my-defn" which uses a macro to push all the args to a stack-frame-archive var (and pops it on return) ;; then when I get a exeption, I just look at stack-frame-archive and get my entire stack frame.

cfleming20:01:17

And method breakpoints no longer slow things to molasses.

tolitius20:01:46

@qqq: I am still a vim user, but any time I need to debug anything concurrent, and neither println nor my brain have answers, I jump into cursive. you can't beat intellij with neither vim nor emacs for debugging. at least currently

qqq20:01:15

@tolitius : yeah, I might do that as well, develop in emacs, and jump to intellij/cursive whenever I have to debug

tolitius20:01:37

@qqq: I also do Java, and occasionally Scala. for those intellij saves a lot of time. So jumping there for Clojure debugging might feel more natural, since I already use intellij for other languages. But give it a try, you might like it to the point where it could become the Clojure editor for you 🙂

qqq20:01:10

(def instrument-stack-trace true )

(def ^:dynamic *debug-stack-trace* ())

(defmacro with-stack [s & body]
  (if instrument-stack-trace
    `(binding [*debug-stack-trace* (cons ~s *debug-stack-trace*)]
       ~@body)
    body))

(defn die []
  (println *debug-stack-trace*))

(defn f1 []
  (with-stack [:f1]
    (die)))

(defn f2 []
  (with-stack [:f2]
    (f1)))

(f2)

^^ this is what I had in mind for "instrument stack traces in clj land" -- then I'd have to create a new "defm" which is like defn, but it puts in the (with-stac ... ) on the args

qqq20:01:43

now, on exceptions, debug-stack-trace will have all the stack frames I care about

qqq20:01:51

runtime costs should be minimal since clj is sharing all the data

arrdem20:01:49

Sure but the entire application is then paying a tracing cost when you could recover a logical stack from the control stack only as needed by instantiating an Exception and looking at its stack.

qqq20:01:01

but due to sharing, the 'cost' is just a cons per function call

noisesmith20:01:03

or just .getStackTrace on Thread/currentThread

qqq20:01:15

and the cost only happens when instrument-stack-trace is on

arrdem20:01:25

I mean… profile it and find out.

arrdem20:01:19

IMO having to worry about what was and what wasn’t loaded when *debug-stack-trace* was true is totally not worth the effort of just doing something based on the JVM stack as-needed.

arrdem20:01:04

Forget any particular difference in performance overhead

bfabry21:01:54

has anyone proposed a general solution to the problem of user.clj being loaded so early in the clojure bootstrap process but also being used by people as their general "repl tools" file? there's a bunch of linked issues here https://github.com/technomancy/leiningen/issues/1245 and I just ran into an issue where the cursive debugger doesn't work correctly because of it as well

arrdem21:01:04

@bfabry there is no general fix, because user.clj is explicitly loaded by RT.java, and so doing anything that would impact that behavior would require forking Clojure or getting a patch to RT merged.

arrdem21:01:29

@bfabry preeeety much just SOL here, which is why Phil closed that ticket.

bfabry21:01:28

yeah I'm sure changing the load time of user.clj is a non-starter. I'm also sure it's going to cause more and more issues as more useful tools are developed that need to run prior to people's project code loading though, so it seems like it's not really suitable for repl tools dev setup etc like we've been using it

arrdem21:01:03

@bfabry I think you can play some tricks with the classpath and make this sorta work, in that if you don’t literally have a ./user.clj around you can escape this. I keep src/dev/user.clj which has to be added to the classpath by lein, so lein doesn’t evaluate it when booting Clojure because it’s not on lein’s classpath.

arrdem21:01:31

but it’s been a while since I’ve looked at this, so no guarantees that this is the precise behavior.

tbaldridge21:01:41

@cfleming I did ALT+. the other day from Cursive on a :import of a Java interface, when it jumpped to the decompiled Java source for the interface I blew my co-worker's mind 🙂

cfleming21:01:02

@tbaldridge Nice 🙂. You can blow it even further by debugging the decompiled source!

cfleming21:01:15

(since IntelliJ 14 IIRC)

cfleming21:01:41

(and if it were a class rather than an interface, obviously)

bfabry22:01:14

@arrdem yeah that will do it, take user.clj off the classpath, then add an init option to :repl-options that load-file's the file. I'll do that in all my projects from now on, imo that is the way people would want/expect it to behave if we could start again

qqq22:01:57

this is going to sound stupid. since 'and' is a macrok, how do I do the equiv of (apply and ... ) it's okay if it does not short circuit

arrdem22:01:53

Yeah. (apply every? identity …)

qqq22:01:03

(every? identity ....) ; thanks!

arrdem22:01:32

@qqq every? is [pred coll] -> val, it does not accept varargs.

bfabry22:01:38

I was assuming he had a collection because he wanted to apply and, but yeah if you were using some of apply's fancier features you'll need to turn all your tests into a single collection

noisesmith23:01:42

@arrdem do you recall if rt.java loads the first user.clj it finds vs. every user.clj it finds on classpath?

carocad23:01:06

@alexmiller I created some specs for a project of mine (see https://github.com/carocad/hypobus/pull/4/files#diff-bc6c73488a5e09c134fce88e69466244R17). When I run clojure lint tool eastwood on it to check for possible bugs it reports some warnings whenever I use s/coll-of due to the way that the s/every macro expands to internally. The warnings that I get from eastwood resemble the following

src/hypobus/conjectures/specs.clj:17:21: constant-test: Test expression is always logical true or always logical false: 2 in form (if or__6536__auto__ or__6536__auto__ (clojure.core/or 0))
It is only a very minor issue though, but I thought that letting you know about it and proposing a possible solution would be better 😉

joshjones23:01:41

There are a few possibilities: 1) If you have a collection of expressions (which is what you would give to and), then the suggested (every? identity coll-of-exprs) would work well, as you're simply checking whether every element in a collection is truthy. 2) However, if testing a collection of predicates which are functions (usually that take one argument), then every-pred is a good function to use. With this you can determine whether a group of predicates all return true for a single or multiple inputs. For example:

(def preds [even? pos-int? (partial > 5)])
(def coll-to-test [2 4])
(apply (apply every-pred preds) coll-to-test)    ; for a single value: ((apply every-pred preds) 4)

qqq23:01:09

in clojure.test, is it possible to just let the exceptions happne, in stead of the try-expr that "is" does ?

arrdem23:01:27

@noisesmith I think that only the first user.clj will get loaded, but all data-readers.edn will get loaded.