Fork me on GitHub
#clojure
<
2016-02-01
>
drusellers00:02:31

Given the recent clojure.string additions, is there anything planned for integers, I find it very interesting that there isn’t a native clojure function for converting strings to ints. A broader question would be, is there a library that deals with coercion from one type to the other? assuming that it doesn’t exist in core given going from a string to an int looks like this http://stackoverflow.com/a/12503724

ajoberstar00:02:53

FYI, the reason I'm not using a (:gen-class ...) in the ns declaration is that I don't want users to have to modify their tests to use Gradle. So I'm scanning for test namespaces and trying to call (gen-class ...) for each, creating a class matching the namespace name.

noisesmith03:02:02

what about making your own class (via reify or proxy) for each test ns file found, that knows how to load up clojure.lang.rt, load that ns, and run its tests?

ajoberstar03:02:43

To get the right behavior from Gradle, I would need a named class (matching the namespace). My understanding is that reify/proxy don't allow named classes.

ajoberstar03:02:29

I can make due for now with a single class (which avoids the macro evaluation issues), it just causes some incorrect logging from Gradle.

jethroksy07:02:54

I have a Component that needs to be passed a handler, but the handler must interact with the record's fields

jethroksy07:02:21

how can I achieve this?

jethroksy07:02:54

(defrecord WSClient [msg-count status handler conn]
;; ...
)

jethroksy07:02:41

handler needs to interact with status and msg-count, and also call the close from the Lifecycle protocol

crocket08:02:51

Somebody wrote

I’ve had type errors in Clojure that multiple professional Clojure devs (in-
cluding myself) couldn’t resolve in less than 2 hours because of the source-to-
sink distance caused by dynamic typing. We had copious tests. We added
println’s everywhere. We tested individual functions from the REPL. It
still took ages. It was only 250 lines of Clojure. I’ve had similar happen in
Python and Common Lisp as well. I did finally fix it and found it was due
to vectors in Clojure implementing IFn. The crazy values that propagated
from the IFn usage of the vector allowed malformed data to propagate down-
ward far away from the origin of the problem. The same issue in Haskell
would be trivially resolved in a minute or less because the type-checker will
identify precisely where you were inconsistent.

crocket08:02:29

Has the source-to-sink distance become shorter now?

bfabry08:02:35

the source-to-sink distance is a function of your program's design, so not really

crocket08:02:09

At 250 lines, the distance shouldn't be long.

crocket08:02:06

I have a hunch that clojure's error reporting was so bad that diagnosis was difficult.

bfabry08:02:10

there's not nearly enough information in that comment to usefully respond

crocket08:02:11

clojure's error reporting used to be bad.

bfabry08:02:29

it's certainly possible that a poor error message made the problem described more difficult to solve. the error messages are definitely better. it's also possible a debugger would have helped, which cider and cursive now provide. but there's really not enough information in the comment to tell. fwiw he mentions seeing the same issue in Python, which is usually regarded to have good error messages

bfabry08:02:41

my opinion: I just got an error message. java.lang.IllegalArgumentException: The end instant must be greater or equal to the start at com.google.cloud.dataflow.sdk.Pipeline.run(Pipeline.java:180) at link_dataflow.thingy$_main.invokeStatic(thingy.clj:139). this tells me exactly where in my code that happened. I look at it, no it's not a problem that would have been caught by a type checker, it's just that my domain is more complicated than I thought, and somehow comments can happen on topics prior to the topics themselves being created.

jonahbenton11:02:52

hey @jethroksy: a record can be treated like a map- fields can be retrieved with keywords- (:status wsclient-instance) and changes introduced with assoc, which returns the changed record; similarly any protocol fns can be called directly (close wsclient-instance). remember to use the returned instance.

jethroksy11:02:17

@jonahbenton I want to call handler in start though

jethroksy11:02:58

It's probably poor design...

jethroksy11:02:18

Basically the the handler is a multimethod that consumes everything in a channel and dispatches based on a value

jethroksy11:02:53

So in start I need to do something like (consume! #(handler %) chan)

jethroksy11:02:30

And this would then modify the fields of the instance

jethroksy11:02:02

Eg. (reset! status false) when disconnected

jonahbenton11:02:59

@jethroksy so the record is instance that passes through the channel?

jonahbenton11:02:30

or the record is an owner of the consumption process?

jethroksy11:02:37

I'm specifically using aleph, so I have a field conn that stores the duplex stream returned

jethroksy11:02:25

So in start I have something like (s/consume! #(handler %) conn)

jethroksy11:02:59

This handler is stored in another field of the record

jethroksy11:02:45

I need this handler to be aware of status, msg-count etc

jonahbenton11:02:08

so status is some state determined by the consuming process, and msg-count is the number of messages consumed off the channel, etc

jonahbenton11:02:58

do other parts of the program need to have visibility to msg-count and status while the consumption process is occurring?

udit11:02:09

Hey @jethroksy! This is completely unrelated to your question but apparently you are creating a websocket client in clojure. If the project is open-sourced would you mind sharing the link? I tried to implement something similar and a new approach might help me in understanding where I went wrong. Thanks!

jethroksy11:02:10

Hello @udit ! I'm not actually creating the client, I'm just using an implementation of it (aleph, which uses Netty underneath). I'm trying to make it a component since it makes sense that it has a life cycle. I'd share the snipper now but I'm on my phone :/

udit11:02:09

Hey no problem. Share it whenever you may simple_smile

jonahbenton11:02:33

hey @jethroksy it sounds to me like it may make sense to decouple the consumption process from the lifecycle of the record. so the consumption process should be started by start, but start has to return an updated record instance to the system, and presumably the consumption process should not block the return of start.

jonahbenton11:02:57

stop should be able to stop the consumption process, but that's separate from the consumption process being completed

jethroksy11:02:35

That's how it works currently

jethroksy11:02:08

(s/consume!) is the non-blocking process started by start

jethroksy11:02:51

Stop closes the stream so the consumption process is stopped as well

jonahbenton11:02:04

gotcha. did you write consume! or does it come from aleph?

jethroksy11:02:20

It comes from manifold

jethroksy11:02:29

Manifold.stream

jethroksy11:02:41

Perhaps the multimethod should take more arguments??

jethroksy11:02:01

Take the component as an argument as well

jethroksy11:02:36

I can't think of a way to use closures to fix this

jonahbenton11:02:57

i don't know the semantics of manifold and aleph off-hand, but in core.async terms, this sounds to me like start spin ups 2 go-loops. the first consumes from the channel, maintains its own internal state around the process of consumption- count of messages, etc- and it is handled a stop-chan and a complete-chan, both of which are part of the record's state. the record loses the "in-flight" state fields but has an "end-state" atom. the second go-loop listens on complete-chan and updates the end-state atom when consumption is done. calling stop on the component puts a signal on stop-chan so the consumption process stops.

jethroksy11:02:31

I guess that makes sense, my code would need some restructuring

jonahbenton11:02:08

what's not clear not knowing aleph and manifold is how those async processes communicate with other parts of a system

jethroksy11:02:38

I could give you a rough explanation

jethroksy11:02:59

It would be great if I could ping you about an hour later, I need to eat my dinner and I'll have code to show you

jethroksy11:02:28

Thanks so much for your help btw

jonahbenton11:02:42

certainly, i have to run out for a bit too, happy to continue later

stig14:02:33

is it a bad idea to load stuff from the user namespace in a Clojure test? I’m toying with a Duct app and am wondering if it makes sense to re-use user.new-system from a kerodon test.

jonahbenton14:02:22

hey @stig better to have user consume stuff from other namespaces- including test namespaces, for working with tests at the repl

donbonifacio14:02:54

I’m having a Attempting to call unbound fn: *** on clj 1.8 without using declare, don’t really know how to troubleshoot this, any ideas?

stig14:02:14

Thanks @jonahbenton. Assume I’ve done some repl testing; how do I now codify this so that it runs when running lein test?

stig14:02:13

@jonahbenton: a good point though. Thinking about it it would be difficult to run from the repl later, if I use the user namespace in my tests.

stig14:02:28

This suggests duplicating the test system instead...

stig14:02:38

(or, the bits I need from it.)

jonahbenton14:02:02

sure, just add the work you wish to retain to your test namespaces

jonahbenton15:02:28

and yes, it's a good practice to have a test config, and if using component to have a test system.

rauh15:02:04

Under what circumstances is *ns* bound to clojure.core even though I used it in a function in my own namespace?

rauh15:02:32

More details: The function is called from pedestal and the "route" function that returns the deref'ed route var. CLJ 1.8

jonahbenton15:02:10

hey @rauh can you say more about what you are seeing?

rauh15:02:03

Request comes in, route function gets evaluated. In it I do a (println *ns*) and it prints me clojure.core instead of my ns.

rauh15:02:20

Reason is that I get an exception (and an empty response) if I reload the namespace itself while pedestal is doing a request (my guess). So i wanted to (remove (fn-with-*ns*) (modified-namespaces))

rauh15:02:41

I guess it's only bound to the current namespace while the namespace is loaded. So I just capture it in a simple def.

jonahbenton15:02:19

hmm. i haven't used that particular template but it should be reloading the namespaces before traversing the route table to find your handler. what exception are you getting?

meow16:02:33

@rauh: Hey there, stranger. It's been a while. Hope you are well simple_smile

rauh16:02:29

@meow: True. I've been busy with lots of other stuff but finally doing more clojure again. Thanks, all is well. simple_smile

rauh16:02:40

@jonahbenton: Thinking a little more about it: It might be that I'm getting that exception because mount (similar to component) will restart pedestal when reloading that namespace.

jonahbenton16:02:55

@rauh ah, yeah, that would be a problem

solomonhawk16:02:07

as a self-taught programmer coming from a deep JS background…. clojure is pretty awesome. just scratching the surface

solomonhawk16:02:43

also idk why i didnt pick up emacs before

rduplain17:02:04

Does clojure have a packaged function for text dedent? i.e. this https://gist.github.com/jturner314/3807830 (which is the behavior of something like this https://docs.python.org/3.5/library/textwrap.html#textwrap.dedent)

rduplain17:02:02

I'm looking for something to drop into my project.

jonahbenton17:02:48

hey @rduplain am not aware of one in either clj or java, though at first glance that gist doesn't look bad. could just copy paste the code into a namespace in your project and use it.

rduplain17:02:52

That's what I'm considering. I'd prefer something packaged instead of copy/paste. If it doesn't exist, I will consider forking the gist into a package.

tesseract17:02:29

@solomonhawk: emacs is arcane and has bad package support.

tesseract18:02:08

I am hoping that atom will turn into a world class clojure environment

solomonhawk18:02:40

👍 how does it stack up right now?

solomonhawk18:02:56

I’m still very new so it’s not easy for me to make that kind of assessment

tesseract18:02:59

I tried to get a few packages installed and the system was pretty bad. All of that pain just so parens would line up nicely

tesseract18:02:16

I think atom has nrepl support too

tesseract18:02:45

basically I think of Atom as modern and would like to see it be the first place people go to program Clojure

tesseract18:02:02

from what I saw at the Conj, a lot of people use Emacs but you need to find someone pretty advanced to be able to help you debug your issues. IMO it just wasn’t worth it as emacs provides no “big enough” benefit for the trouble

shayanjm18:02:25

@tesseract: Well, other than it being built for lisps.

roberto18:02:52

i just started using Emacs less than a year ago, and haven’t had any issues with it. Found it to be a pretty smooth ramp up process.

roberto18:02:58

But experiences differ

shayanjm18:02:08

there’s an obvious learning curve, but the pros outweigh the cons

roberto18:02:12

what works for me won’t work for someone else, the more choices we have, the better

solomonhawk18:02:18

the resources at http://braveclojure.com were invaluable for me

shayanjm18:02:21

I jumped from sublime text/Atom to Emacs and never looked back

solomonhawk18:02:39

basically sets you up with a decent emacs config w/ a bunch of clojure geared stuff

solomonhawk18:02:47

been on ST for awhile now

solomonhawk18:02:56

ready for keyboard-only editing experience..

shayanjm18:02:08

One thing I do miss is ST’s CMD+P

shayanjm18:02:33

grep -r just doesn’t cut it for me now 😕

yenda18:02:35

And there is spacemacs for those who want bells and whistles with community supported config

nkraft18:02:04

My clojure-Emacs setup works great when it works, but it breaks often after package upgrades. I've been using LightTable more and more lately.

shaun-mahood18:02:30

@nkraft: How does the current light table work for Clojure? I haven't tried it for quite a while

derwolfe18:02:33

Hmm. I feel like I’m having a bit of difficulty redefining a logger in testing. I want to redefine taoensso.timbre/error in some tests so that I can assert some logging output exists; but it looks like error (https://github.com/ptaoussanis/timbre/blob/master/src/taoensso/timbre.cljx#L515) is a macro. Any tips about what I might be missing?

derwolfe18:02:25

Or would a better approach be to redefine taoensso.timbre/log! the function; this is used by error?

derwolfe18:02:02

I was incorrect about log, it is a macro as well.

jonahbenton18:02:28

hey @derwolfe how about just passing timbre a custom appender in test?

derwolfe18:02:51

jonahbenton: I hadn’t thought about that! I’ll read up and see how to do so. Thanks!

tesseract18:02:27

but I did not mean to start this conversation in here, we can take it #C03RZGPG3

derwolfe18:02:18

jonahbenton: That was exactly what I needed. Works perfectly -

(timbre/merge-config! {:appenders
                               {:atom-appender
                                {:async false
                                 :enabled? true
                                 :min-level nil
                                 :output-fn :inherit
                                 :fn (fn [data]
                                       (let [{:keys [output-fn]} data
                                             formatted-output-str (output-fn data)]
                                         (reset! log formatted-output-str)))}}})

derwolfe18:02:33

then I can just assert against the log atom

jonahbenton18:02:24

nice! timbre is a very open system

derwolfe18:02:57

yes. This also feels much nicer than mocking this out. Thanks for your help simple_smile

nkraft18:02:55

LightTable has really come along in recent years. I like being able to run sections of code to see the output, though I miss a true repl.

meow19:02:33

@tesseract: Have you seen Proton? It is atom plus spacemacs plus parinfer plus REPL - #C0GCNE3B3

xc4meron19:02:53

Is there anyone here that can help me with my clojure work?

meow19:02:44

@xc4meron: Plenty. Just ask and you should get an answer or a suggestion for a better channel to ask on. simple_smile

xc4meron19:02:43

basically, I'm doing clojure as a module and ive gotta do this question and i just need help starting sigh

meow19:02:04

@xc4meron: The #C053AK3F9 channel would be good for that.

lucien.knechtli19:02:39

@meow Proton definitely has potential, but its missing too many of the basic features that spacemacs provides for me to consider it a replacement at this time.

meow19:02:57

I've only played with it a little bit as I'm quite happy with Cursive.

akiva19:02:26

Spacemacs 4 LYFE

PB19:02:41

When evaluating the result of a for loop. Is each element realised sequentially?. I.e. Will it evaluate the element at 0 first, then the element at 1. Or does it evaluate them all asynchonously?

bronsa20:02:37

the former

Alex Miller (Clojure team)20:02:52

I think there is a parallel for in one of the utility libs out there though

Alex Miller (Clojure team)20:02:15

yeah, claypoole has a pfor

amro21:02:31

how can I see the ... x more frames in clojure stack traces?

ljosa22:02:32

Suppose I do something like this:

(do
  (doall (map println (repeat "foo")))
  nil)
Will it hold onto the head of the infinite sequence of nils (and eventually run out of memory), or will that be optimized away because the value is not being used? (In reality the code is a little more interesting, consuming a stream of data received via HTTP with server-sent events (SSE).)

seriousbug22:02:23

How about something like this?

(do 
  (reduce (fn [_ a] (println a))
          (repeat "foo"))
  nil)

seriousbug22:02:54

Tried running both in REPL while watching the memory usage, the former code causes the memory usage to rise but the latter doesn't

jsa-aerial22:02:33

@ijbriscoe: You are looking for doseq

ljosa22:02:12

yup, that would do it too. I ended up with map + doall because it looked better with ->>. I had hoped the return value would not be collected. From @seriousbug's test, it looks like I was wrong. Thanks!

ghadi23:02:45

doall holds on to the head. doseq doesn't

jsa-aerial23:02:16

I wonder why slack picked ijbriscoe when I selected @ljosa from the list? Anyway, doseq is intended for use when your body is for side effects (such as printing in your case) and as such does not hold the head. It's idiomatic for this type of case