#clojure log - Feb 22 2016

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

3:50 CStorm: how do i set a environment variable on unbuntu which environ can get? ive tried putting it in /etc/environment but no luck.

4:49 hyPiRion: CStorm: You probably need to restart/logout then login again for it to be reflected

5:53 Kah0ona: solatis: I'm currently working on a nice green-field freelance solo project for a company in Tilburg until like May-June, but when it's done, we probably need to talk ;-) (I'm Dutch, freelancer, Den Haag based.)

5:54 (if i read correctly that you are hiring that is)

5:54 kinda skimmed over the cats discussion

5:55 I have two cats too ;-)

5:56 Anyway; in summer I have another fairly large clj project added to my portfolio. working on it now

6:06 TEttinger: haha

6:06 cats

7:13 aurelian: hi there... what's the idea with lein creating an empty folder called dev-resources ?

7:13 how do I get rid of it?

7:16 ridcully: {:profiles {:dev {:resource-paths set?

7:17 aurelian: doesn't look like

7:17 :profiles {:uberjar {:aot :all}})

7:17 it's a standard lein new project

7:17 using app template or wtv the default is

7:18 oh. upgraded lein and now is gone.

7:18 mind me

7:19 I was on 2.5.something

7:37 hyPiRion: aurelian: yeah, sorry about the empty folders. They should be gone with 2.6.x

7:37 aurelian: it's ok, thanks!

7:37 confirmed they're gone

7:58 timvisher: i'm logging from a background thread that updates an atom that i dereference. everytime i dereference the atom a log message comes out but if i don't dereference the atom no message comes out. is there any way i can force those exceptions to be logged without having to dereference the atom?

8:21 TimMc: timvisher: Dereferencing an atom should not cause side effects. Do you have lazy seqs or something in there?

8:26 timvisher: laziness…

8:26 TimMc: ~laziness

8:26 clojurebot: laziness means not traversing anything twice

8:26 TimMc: ~laziness

8:26 clojurebot: laziness means not traversing anything twice

8:26 TimMc: oh well

8:27 timvisher: So yeah, sounds like you need a dorun or doall in there somewhere. :-)

8:27 timvisher: anyway yeah. one `map → mapv` transformation later and boom

8:39 TimMc: Could I get some advice/rubber ducks on a concurrency mechanism for serializing writes to a cache?

8:40 The code is currently sending ~50 writes per second (luxuriously few, given that writes are 1-2 ms) and I was thinking of just dumping them into a dropping or sliding queue and spinning a thread to pick them up at the other end and put them in the cache.

8:42 I'm thinking simple 'n' robust is better, because we rely on the cache being up, and if we stop updating it, there's going to be trouble.

8:42 Any constructs I should be looking at in particular?

8:47 Agents are out, as usual. I've never ended up finding a good use for them.

8:50 jamesturnbull: hi all - I have a collection [var1 var2] that I am trying to join. var2 may sometimes be nil. I want to ensure a separater is present if there are two elements but not if there is one. (clojure/string.join "." [var1 var2]) becomes var1. if var2 is nil.

8:50 hyPiRion: TimMc: I think just a Thread and a BlockingQueue would work fine. Then you can use .offer to insert values which may be dropped.

8:50 I am no guru on concurrency mechanisms though

8:50 TimMc: And just a try/catch in the thread is probably sufficient to make sure it never dies?

8:51 I'll monitor the length of the queue, of course.

8:51 hyPiRion: Yeah.

8:51 TimMc: hmm, also need shutdown mechanism

8:51 Channels feel like maybe they're relevant here, although I hesitate to introduce *yet another* concurrency mechanism or structuring principle to this codebase...

8:54 hyPiRion: TimMc: It depends on how you'd like to shut down. I like to just use .interrupt and catch InterruptExceptions

8:59 TimMc: hiredman: That... sounds perfectly reasonable, actually.

8:59 oops

8:59 hyPiRion, rather

9:01 jamesturnbull: They're both strings already?

9:03 I'd probably go with something simple like (cond-> (str v1) v2 (str "." v2))

9:03 jamesturnbull: TimMc: yeah both strings. thanks will try that!

9:04 TimMc: (that handles them not being strings, but not if v2 can legitimately be the boolean false)

9:04 dysfun: what's the function called that turns '_BANG_' etc. into '!' in a name?

9:04 TimMc: demunge?

9:04 dysfun: that's the one, ta

9:04 TimMc: but I think it's only in clojure.repl

9:05 and has a bug, IIRC

9:05 dysfun: that's acceptable for this, this module is meant for during development

9:05 oh :/

9:05 TimMc: something about double underscores

9:06 dysfun: haha, and the literal word 'BANG' probably

9:07 TimMc: hmm, I think I'm thinking of a bug in pst around extracting munged fn names

9:13 jamesturnbull: TimMc: thanks - works perfectly - didn't know about cond-> - neat.

9:15 dysfun: TimMc: so demunge is fine?

9:15 (to the best of your knowledge)

9:16 TimMc: dysfun: Yeah, and I found the original (fixed) bug: http://dev.clojure.org/jira/browse/CLJ-1083

9:17 dysfun: aha

9:18 of course if you're a java programmer and you're writing _BANG_, you need your head looking at

9:20 ridcully: static final String LOL_BANG_LOL seems not so far out that head inspection is needed? ;P

9:20 TimMc: Probably true, but that kind of argument never sits well with me.

9:22 This is why we have problems like not having any way to escape characters in a <script> block in HTML. "Just don't write </script> in your script, ever, OK?" Fast forward a decade and we've got user data being plunked down in JSON into script blocks and no end of trouble.

9:22 Universality is good for security and correctness.

9:23 (I gave a talk on this at work. I should turn it into a blog post.)

9:24 dysfun: i'd read it

11:27 justin_smith: TimMc: agents are when you want a mutable container and retries on update are out of the question

11:28 (in my experience, they probably also have other uses)

11:28 TimMc: as such they are the only clojure mutable container that it's safe to put actual mutable objects inside

11:31 sineer: Hi! if I have a (let [foo "bar"] (if foo (let [foo "baz"]))) is there a nicer way to reassign my foo var without requiring yet another let?

11:31 justin_smith: ,(let [foo "bar" foo (if foo "baz" foo)] foo) ; sineer

11:32 clojurebot: "baz"

11:32 justin_smith: sineer: and it is not "reassigning" anythign, it's shadowing

11:32 but that's good enough (unless a previous binding used the value, then it's clear it was just shadowing)

11:33 sineer: right (about shadowing). it feels wierd... I'll try it

11:33 justin_smith: sineer: it's the same thing the nested let would do

11:33 Bronsa: justin_smith: care to expand on "agents are the only clojure container that it's safe to put mutable object inside"?

11:34 justin_smith: Bronsa: no retries

11:34 retries fuck with mutable things

11:34 Bronsa: ah, gotcha

11:34 justin_smith: I mean yeah you could put a mutable thing inside and promise not to mutate it in swap! or alter calls...

11:34 Bronsa: I'd feel so safe doing that

11:36 justin_smith: oh, there's vars too of course

11:36 but that's only for top level things

11:36 so for example when I use stuartsierra/component I put my system inside a var or an agent (neither retries) instead of an atom or ref

11:57 TimMc: If the actions on the mutable thing are idempotent it might be OK.

12:01 justin_smith: TimMc: sure, maybe, but still, if what you have is a thing containing maybe some clojure data and some mutable stuff that isn't concurrency safe that you need to punch in unsafe ways, agents are a decent way to manage that state

12:01 because the actions sent are guaranteed to be one at a time, no retries, etc.

12:02 simpler than wrangling locks anyway

12:06 TimMc: justin_smith: What's an example of something you've used an agent for?

12:07 justin_smith: TimMc: stuartsierra/component system object (I don't want retries just because something else tried to start it)

12:08 TimMc: various cases where I was using core.async but realized all I needed was one queue and I could send it functions

12:09 and I would use it if I needed to use a mutable object unsafe for concurrency that had namespace level scope, but that hasn't come up remarkably

12:10 TimMc: hmm

12:13 justin_smith: TimMc: if you have a simpler solution for those cases feel free to offer, of course

12:17 of course the canonical thing with a component is a var, but that doesn't cover overlapping calls as nicely I don't think?

12:20 actually I can't tell if this retries or not? https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Var.java#L302

12:25 sineer: clojure.lang.ExceptionInfo: Cannot recur accross try ... I can't try/catch inside a go loop if I must recur ?

12:25 justin_smith: sineer: you need to move the try/catch to not surround the recur

12:25 sometimes this requires a promise or delay for the value propagation to work (sadly)

12:26 sineer: so inside the go block but before the (loop ) ?

12:26 otherwise if it's outside the go block then it won't work correct?

12:26 justin_smith: or inside the loop but not surrounding the recur

12:26 depends what needs catching

12:27 sineer: (loop [x 1] (let [res (promise)] (try .... (deliver res v) ... (catch ... (deliver res nil)) (recur @res)) ; if you need to use a value created inside the try in your recur

12:28 if you don't need to use any value from inside the try in your recur call, that's much simpler of course

12:28 sineer: k, thanks!

12:31 justin_smith: sineer: actually there should probably be a deliver in the finally clause in the above, to guarantee you don't do a blocking deref that won't be fulfilled inside the recur call

15:04 mping: hi guys

15:27 gfredericks: I need some names for things in test.check

15:27 TimMc: fred

15:27 gfredericks: to be more specific

15:27 AimHere: fred smith

15:28 TimMc: the third

15:28 gfredericks: I need to differentiate a test run from a single trial

15:28 but "test run" sounds too much like running your whole test suite

15:28 I don't know which of the two "trial" sounds like

15:28 {blake}: "single trial" seems pretty clear

15:28 gfredericks: this is for things to go under the :type key in a map passed to a callback function to let you know what's going on

15:29 so event names I guess

15:29 maybe :start-test, :trial, :end-test, that sort of thing

15:29 i.e. I think "test" is a decent name for the larger chunk of work

15:29 GREAT thanks everybody

15:30 cfleming: hi

15:50 TimMc: gfredericks: Yes, trial sounds right.

15:50 or even probe, but trial is better

15:50 chcek :-P

15:50 *check

15:51 gfredericks: naming is one of the 94 hard problems in computer science, along with cache-invalidation and off-by-91-errors

15:52 TimMc: *71

15:52 * gfredericks just found out that test.check has a global atom in it

16:10 andyf: I know a gentleman from India whose last name is "Furniturewala". Yes, the English word "furniture" followed by "wala", with no space.

16:11 "wala" means "maker", so he is named for one of his recent ancestors being a furniture maker, after English was reasonably common in India, but before surnames were common, so the surname was created after that.

16:12 That was one of my top all time favorite names, until this weekend, when I heard a similar but even more awesome name: "Sodabottleopenerwala"

16:12 I am not joking

16:15 Sorry, no application to your naming question, gfredericks, although I would suggest putting 'wala' in constructor names whenever you can :-)

16:16 justin_smith: andyf: beats Factory for sure

16:16 zipper: Hey guys, I need some clojurescript help. I can get it here, right?

16:17 andyf: If all planets line up properly, then yes.

16:17 hiredman: maybe, depending on the nature of the help required, there is a #clojurescript channel I think too

16:18 gfredericks: ~andyf is a walanamewala

16:18 clojurebot: Ik begrijp

16:19 {blake}: A propos of which, I'm having reagent timing issues.

16:19 I have a reagaent component that renders a table full of controls.

16:19 After rendering, I want to attach some Jquery to the controls.

16:20 I dutifully used with-meta and :component-did-mount, which I wrapped my rendering function around.

16:20 The code is called. I know, because it starts a timer.

16:20 But the attempt to collect all the controls of a class fails. (I'm collecting, e.g., currency controls to apply MaskMoney to.)

16:21 If I put the collection code into the timer code, it works, I presume because that stuff fires long enough for everything to have settled.

16:21 er, late enough

16:21 amalloy: MaskMoney is the account bruce wayne sets aside for batman-related activities

16:22 {blake}: And I suppose I could create a timer event to fire JUST to set this Jquery code. But that seems cheesy, and wrong.

16:22 He must go through masks like crazy.

16:23 amalloy: fwiw andyf, we have lots of names like that in english already, we're just used to them because we've had them so long

16:24 plenty of masons, smiths, thatchers, coppersmiths, and so on

16:24 gfredericks: andyf: the clear conclusion is that you need to come to clojure/west this year

16:24 hiredman: {blake}: sounds like you need the js equiv of swing's invokeLater, which I guess would be a zero second settimeout

16:25 {blake}: hiredman: Mebbe. It's gotta exist. No way people =aren't= doing this exact thing. But it can be hard to find info.

16:25 (Or in this case, figure out where I've gone wrong, because if :component-did-mount isn't for this, what IS it for?)

16:27 hiredman: https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount it does sone like that is what it is for

16:27 sound

16:27 {blake}: Hmmm. Immediately after initial rendering occurs.

16:27 andyf: gfredericks: The thing I found interesting was the *combination* of words from two languages in a single name.

16:27 zipper: So since the clojurescript channel isn't full of life. I will ask here too.

16:28 So in this code https://www.refheap.com/115084#L-2 The Line 2 fails. I am trying to rewrite whatever is from L12 since that regex fails to work for () and |

16:28 andyf: gfredericks: Kids still in college, and on top of that there is big hardware/software product release coming up this April, but maybe the hubbub will be over by the Conj.

16:29 hiredman: zipper: you are qouting the regex and not the list

16:30 zipper: so you are invoking the regex as a 0 arg function, you should be seeing errors in the error console and possibly at compile time

16:30 zipper: if you do quote the list, you local 'regex' in the let is being bound the result of the if, which is a list containing a regex, not a regex

16:31 oh, I guess you only care about the second

16:31 andyf: amalloy: Sorry, meant to send one of my recent comments to you. Senior moment.

16:32 hiredman: zipper: what does "fails" mean? a compilation error, a runtime error, or it fails to match what you want?

16:32 zipper: hiredman: Yes I am seeing an error in the JS console

16:32 hiredman: for which snippet?

16:33 zipper: hiredman `Uncaught TypeError: /\/[\-\[\]\\/\{\}\(\)\*\+\?\.\\\^\$\|]\/gi/.call is not a function`

16:33 hiredman: I assume it comes from L2

16:34 I can see that because it tries to call that regex.call

16:34 plus it ends with /gi

16:34 hiredman: zipper: right, so A. you don't need to quite the regexes B. don't call them as zero argument functions

16:34 to quote

16:35 zipper: hiredman: How do I avoid calling it if not using '

16:35 ?

16:35 hiredman: you have the ' and are still calling

16:35 (foo) is a function call

16:35 you have (some-regex)

16:35 that is trying to invoke the regex as a 0 argument function

16:36 you use of ' does nothing in this case, because regexes are literals that evaluate to themselves

16:37 zipper: Okay so I get rid of the () and have that read as; `#"/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/gi"`

16:37 hiredman: '(foo) would mean it is a quoted list, not a function call, but then you would have a list containing a regex, not a regex

16:37 gfredericks: andyf: is going to conferences more difficult when your kids are in college?

16:37 zipper: That's a regex now

16:37 hiredman: zipper: yes, that is

16:38 zipper: hiredman: Trying it out

16:38 My chest hurts, it's so cold :(

16:38 {blake}: component-did-update does the trick.

16:39 andyf: gfredericks: Only in that I feel budget tightness more than before then. I should splurge on a Conj before they are done, though.

16:40 gfredericks: andyf: are you telling me college is going to cost *money*??

16:40 hiredman: if there was money in the future, instead of just hugs

16:41 andyf: gfredericks: I fully believe that it will become common-place for some cheaper alternative to traditional 4-year degree to be acceptable for more jobs than they are now. Not sure when that will happen. Maybe a decade or 2 from now?

16:42 Somelauw: How to quickly run a clojure.clj file interactively which is not part of a project?

16:43 Is lein repl, (source filename) the only way?

16:43 gfredericks: andyf: I need a proposal on my desk by 14 years from now

16:43 hiredman: http://clojure.org/reference/repl_and_main

16:43 Somelauw: source doesn't run anything

16:48 amalloy: you know, i read "that's a regex now" as "that's a regret now", and it seemed even more apt, given that the subject is #"/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/gi"

16:48 gfredericks: a programmer has a regret, and thinks, "I know, I'll use a regular expression!" ...

16:48 hiredman: amalloy: also, it is being used to edit a string, that is then being turned into a regex

16:49 crazy

16:49 Somelauw: Running 'java -cp clojure.jar clojure.main' says 'Error: Could not find or load main class clojure.main' I just want to run a single script without turning this script into a project.

16:50 hiredman: Somelauw: because you picked a random jar instead of the jar that contains clojure

16:50 clojure.jar doesn't, in this context, mean some jar with your clojure code in it, it means the jar containing the clojure runtime

16:52 Somelauw: so clojure.jar should be the full path to the clojure.jar that lays somewhere deep in ~/.m2

16:53 hiredman: or whereever, you can download the jar from the website

16:53 http://clojure.org/community/downloads

16:54 Somelauw: so that is ~/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar

16:56 I'll just write a wrapper for it

16:57 I only miss autocompletion in my repl that lein has

16:58 ridcully: don't forget to put rlwrap -m -M .clj -C clojure around it :)

17:01 Somelauw: ridcully: ehm, do I replace clojure by 'java -cp clojure.jar clojure.main'?

17:04 ridcully: Somelauw: no. it's just a name used for the history file

17:04 Somelauw: this will use ~/.clojure_history then

17:05 andyf: gfredericks: My iPhone calendar actually lets me schedule events 14 years in advance. Huh. Not sure whether the event I just created will get copied to whatever device I am using to remind me of calendar events then.

17:06 Somelauw: ridcully: I'm not sure at what place of your command to insert the whole 'java -cp clojure.jar clojure.main'

17:09 ridcully: Somelauw: i use it like this (some var with the version involved): rlwrap -m -M .clj -C clojure java -cp ~/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar clojure.main

17:10 Somelauw: the -m gives you multine capabilities - so you can open your $EDITOR with ctrl-^. the -M tells it to put a .clj on that "file" to open so your $EDITOR behaves nicely

17:27 Somelauw: ridcully: thanks, that works well, although it would be preferable to still use lein somehow

17:30 ridcully: Somelauw: you can always run a `lein repl` from anywhere

17:30 spuz: Is there a function that combines filter and first? I.e. it returns the first element of a sequence that matches a predicate?

17:30 ridcully: Somelauw: add the `try` plugin for it and you can also fetch some deps right into it

17:31 Somelauw: ridcully: I know I can run lein repl from anywhere, just not how to run it with a script that is not part of a project.

17:31 amalloy: spuz: incredibly, there is not

17:33 Somelauw: lein repl filename doesn't work for me

17:33 andyf: spuz: Some Clojure 'utility libraries' include such a thing, e.g. find-first in Medlay: https://github.com/weavejester/medley/blob/master/src/medley/core.cljc

17:33 Somelauw: then it says unknown subcommand

17:33 andyf: spuz: er, Medley, even.

17:34 spuz: andyf, thanks

17:35 Somelauw: but filter is lazy, so first-filter should already be fast

17:49 justin_smith: ridcully: cool rlwrap tricks

17:56 lerax: Someone knows a good lib for pt-br natural lang processing?

18:03 ridcully: Somelauw: mhm i might have put you on the wrong track then. i only saw your "have to wrap it" bits and tought you just want to have a faster repl

18:15 ImBadAtClojure: Is there a way to convert a clojure vector of java objects into a java List<java object's type>?

18:15 hiredman: that is a generic, those don't actually exist

18:16 ImBadAtClojure: So it's impossible?

18:16 hiredman: no, you don't need to

18:16 rhg135: generics are only a delusion that javac enforces

18:17 hiredman: javas generic types exist in the java (the language) compiler, once you have bytecode running on the jvm, they don't exist (this is called erasure and I am sure there are like a billion blog posts about it)

18:17 you just need something that implements List

18:17 ImBadAtClojure: so when I send this custom data structure back to java how do I get it into java datastructures?

18:17 hiredman: if you pull up the java docs for List, there are links to few handy implemntations of that interface

18:18 ,(java.util.ArrayList. (vec (range 10)))

18:18 ImBadAtClojure: I was just trying to map it directly into POJOs somehow

18:18 clojurebot: [0 1 2 3 4 ...]

18:18 hiredman: ,(type (java.util.ArrayList. (vec (range 10))))

18:18 clojurebot: java.util.ArrayList

18:18 hiredman: clojure data structures are java data structures

18:19 so depending on what interfaces java requires and what methods it calls, you can just pass in clojure data structures

18:19 ImBadAtClojure: Fair enough, so just pass it back in a simple array list then map into my pojos on the java side?

18:19 hiredman: ImBadAtClojure: I am not sure what you mean?

18:19 any java objects you want to construct, you can construct from clojure and pass to java

18:21 ImBadAtClojure: But to construct one of my java objects in clojure I need to create a list of a previously constructed java object

18:21 ClassCastException java.util.ArrayList cannot be cast to [L<myType>;

18:21 TEttinger: oh

18:21 that isn't a list

18:21 that looks like an array

18:22 ,(class (make-array java.util.String 2))

18:22 clojurebot: #error {\n :cause "java.util.String"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: java.util.String, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.ClassNotFoundException\n :message "java.util.String"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :...

18:22 TEttinger: ,(class (make-array java.lang.String 2))

18:22 clojurebot: [Ljava.lang.String;

18:22 ImBadAtClojure: that would make an array of strings right?

18:22 so I can make an array of my java object's type in the same way?

18:23 TEttinger: yeah, it looks like your exception is caused by passing an ArrayList where it actually wants an array

18:23 ImBadAtClojure: Yeah I was just trying random things since I didn't know how to create a new array with a non primative type

18:24 I'll try it, thanks :D

18:24 TEttinger: arrays are kinda less supported in clojure than other data structures since they can't be made to have the nice features in clojure's immutable data structures

18:24 arrays are always mutable, fixed-size

18:24 hiredman: that is non-sense

18:25 amalloy: i like the implication that clojure's built-in structures are immutable but change size all the time

18:25 TEttinger: heh

18:25 good point

18:26 I do have the feeling that arrays are not quite first-class in clojure, at least partly because of the separate amap, areduce, etc. fns for them

18:27 hiredman: TEttinger: infact, map and reduce both work on arrays just fine

18:27 TEttinger: amap and areduce are *extra* support for working on arrays

18:27 TEttinger: I didn't know that, I guess seq works on arrays

18:27 ImBadAtClojure: so can I do (make-array <custom java type class> ..)?

18:27 TEttinger: yeah, then the dimension or dimensions

18:27 ,(doc make-array)

18:27 clojurebot: "([type len] [type dim & more-dims]); Creates and returns an array of instances of the specified class of the specified dimension(s). Note that a class object is required. Class objects can be obtained by using their imported or fully-qualified name. Class objects for the primitive types can be obtained using, e.g., Integer/TYPE."

18:28 hiredman: ImBadAtClojure: you can, I would recomend looking at the set of clojure functions with 'array' in the name

18:28 amalloy: you'd almost certainly prefer to call into-array

18:28 ImBadAtClojure: awesome, thanks guys

18:28 TEttinger: right

18:28 hiredman: ,(doc apropos)

18:28 clojurebot: "([str-or-pattern]); Given a regular expression or stringable thing, return a seq of all public definitions in all currently-loaded namespaces that match the str-or-pattern."

18:28 amalloy: although hiredman's advice is probably better

18:28 rhg135: what is the best way to shutdown an agent?

18:29 just stop banging on it?

18:31 hiredman: I have some projects where object arrays were used more less like a C struct, in clojure, works fine. kind of a pain, if I did it regularlly I would have a nice set of macros that generate setter and getter functions

18:58 TEttinger: yeah, actually I might need some advice on how to best interop with array-heavy java code. I still need to get some stuff (I think it's setup related) fixed in my installation of cursive, deps still aren't visible in the editor but they are in lein repl

18:59 but once I can pull in the java deps, I need to wrap them

18:59 I don't know if it's an appropriate case for an issue on cursive somewhere

19:02 * lerax think that Clojure is nice and JVM too. But he say: "Java needs die."

19:13 rhg135: try telling that to oracle

21:51 sineer: I'm inside a (go (loop (try .... (catch Exception e e)))) and I try/catch the block that run this go block yet my exception isn't caught by that try/catch block? Clojure 1.8..

21:52 justin_smith: sineer: I assume you mean (go (loop [] (try ...)))

21:52 sineer: is the thing thrown a subclass of Exception?

21:53 sineer: justin_smith: yeah, it was throwing allright, let me push code on github it'll make our life easier

21:53 justin_smith: sineer: what I am asking is what the class thrown was

21:53 is it an Exception or maybe an Error or some other class that catching Exception would not match

21:54 sineer: NullPtrException

21:54 justin_smith: yeah, share a paste / github

21:56 sineer: https://github.com/sineer/sort-challenge

21:56 line 46 of boot.clj will throw NullPtrException

21:57 I believe it catch it and keep running the go blocks until cnt is 0 but the try/catch in -main never catch anything

21:58 justin_smith: well, of course, if the try/catch in init-products-from-chan! catches the error, why would -main ever see it?

21:59 sineer: also you don't need a new let block at line 51, those bindings can be part of the let block right before

21:59 ,(let [a 0 b (inc a) c (inc b)] c)

21:59 clojurebot: 2

22:00 sineer: I need to run the (if family (assoc info :family family)) before I do the other (let ..

22:00 justin_smith: why?

22:00 clojurebot: http://clojure.org/rationale

22:00 justin_smith: why would that matter at all?

22:00 sineer: I suppose I can do it after..

22:01 justin_smith: sineer: (if family (assoc family x y)) does not have any side effects

22:01 you need to bind the return value, or it is a noop

22:01 family is immutable, assoc does not change it

22:01 the correct version of that line is to have, inside your let binding block 'family (if family (assoc family ...))

22:01 it needs to be a binding or it might as well not exist

22:02 so you only need one let block

22:02 that binding is just the next binding in the block

22:02 compare:

22:02 ,(let [a {}] (assoc a :b 1) a)

22:02 clojurebot: {}

22:03 justin_smith: ,(let [a {} a (assoc a :b 1)] a)

22:03 clojurebot: {:b 1}

22:03 justin_smith: sineer: do you see the difference?

22:03 sineer: I'm just confused now :(

22:04 justin_smith: sineer: assoc does not mutate its arg, it creates a brand new data structure

22:04 sineer: oh shit yeah I get it now :(

22:04 justin_smith: sineer: you don't need two let blocks

22:04 sineer: sorry

22:04 justin_smith: sineer: don't be sad, I'm trying to help

22:04 I'm not trying to be mean

22:04 sineer: I know, I'm sad because I feel stupid having such a hard time with this

22:05 justin_smith: everything is hard if you haven't learned it yet

22:05 sineer: yeah but it shouldn't be that hard else I'm either stupid or it's too damn hard I havne't fully decided which one it is yet

22:06 TimMc: justin_smith: throw in some commas

22:07 justin_smith: TimMc: in the let blocks?

22:07 TimMc: yeah

22:07 justin_smith: ahh, yeah

22:07 sineer: I just realized the version I pushed print the exception on line 59, I use to just return it that's why I expected -main to catch it..

22:07 justin_smith: ,(let [a {}] (assoc a :b 1) a)

22:07 clojurebot: {}

22:07 justin_smith: ,(let [a {}, a (assoc a :b 1)] a)

22:07 clojurebot: {:b 1}

22:07 justin_smith: sineer: returning an exception is not the same as throwing it

22:08 it might look the same with some printing rules, but it's different

22:08 sineer: ok so I need to rethrow inside go block for -main to catch it?

22:08 justin_smith: yes

22:09 otherwise you just return an exception, which is a value like any other

22:09 sineer: in fact you never even consume the channel returned from that go block

22:09 sineer: no I just assign it so that main don't exit right away

22:10 justin_smith: right, just saying by returning it from the go block, it might get read if someone consumed the chan

22:10 but nobody even does that

22:11 sineer: now I tried replacing that print on line 56 by throw and I see the exception trace but then my program just hang, it doesn't look like -main is caching the exception

22:11 line 59 I mean

22:11 justin_smith: go can be kind of weird about exceptions, it's best to catch them before you exit the scope of a go block and handle them best you can

22:12 basically what happens is your code is running in one of the threads of the go thread pool, and your exception bubbles up to that thread, not to the -main that launched the go block, so you are at the mercy of the default go block error handler, which is pretty much useless

22:13 since it's in a different thread, the exception can't go back up to -main

22:13 sineer: I thought I read somewhere it did so since clojure 1.6?

22:13 I probably missinterpreted something

22:13 justin_smith: probably - how would an exception in one thread interrupt another thread?

22:14 sineer: yeah that doesn't make sense but I thought there was some magic I didn't know about...

23:02 solatis: what do people recommend for mocking stuff in tests?

23:02 specifically, things like message queues

23:03 i am in doubt whether to make my tests just /depend/ upon the availability of those, and create ad-hoc queues

23:03 but on the other hand, i could just as well mock the interface to the queue

23:04 sineer: re

23:04 hiredman: solatis: are you using clojure.test?

23:04 solatis: yep

23:05 hiredman: clojure.test has once (per namespace) and each (per deftest) fixtures

23:05 solatis: yes

23:05 so i'm already doing that for my database

23:05 but now i'm depending upon a lot more things (specifically, Amazon AWS services)

23:05 and wonder what the best strategy for this is

23:06 either using the actual service (albeit self-contained), or mocking the interface

23:06 sineer: er sorry. I have a question about how to build a regex.. I want to (let [regex #"foo[-][_]"]) something like that. but using a var instead of "foo". Basically I need a regex that will match myvar with optional - or _ at the end

23:06 hiredman: it can get kind of complicated

23:06 solatis: yes i know, i don't think there is a "magic bullet" for this and it depends on a case-by-case scenario

23:06 hiredman: you can make all your interfaces to aws services pluggable and use some local plugin when testing

23:07 solatis: i was thinking about this: https://clojuredocs.org/clojure.core/with-redefs-fn

23:07 and put that in a fixture

23:07 or something

23:09 hiredman: you can do that, but in my experience you end up with a sprawl of things you need to redef, and it is hard to track what a test is actually doing

23:09 solatis: right

23:09 so the answer is, pluggable service

23:10 but then that doesn't test the actual integration with the message queue

23:10 *argh*

23:10 hiredman: at my previous job we ended up with a macro we called with-var-roots which was written before with-redefs was added to clojure, and when we had the opportunity to green field another project we tried to avoid that again

23:11 solatis: i can assume so

23:12 ok, then i think what i want to do

23:12 *i think i know what i want to do

23:12 just use the damned message queue

23:12 unless it's really impractical not to do so

23:12 hiredman: mocking is really painful, but sometimes you have to, because you can't test against the actual service for whatever reason

23:13 solatis: yes that is true, *however* when you use something like amazon AWS, you have a complete API to create nearly all services ad-hoc and on-demand

23:13 so that's just what i'm going to do

23:15 ok, so, semi-related question

23:15 clojurebot: I don't understand.

23:15 solatis: https://clojuredocs.org/clojure.test/deftest

23:16 i am using tests, with fixture

23:16 the fixture generates something i want to pass around to all tests

23:16 in this case, a random id for a message queue

23:16 how can i pass this argument to all the tests?

23:17 the test function passed to the fixture appears to be a function that does not accept arguments

23:18 sineer: how do I create a regular expression and assign it to a var by concatenating strings? something like #(str var "[-_]") but that's not what I expected..

23:19 hiredman: ,(doc re-pattern)

23:19 clojurebot: "([s]); Returns an instance of java.util.regex.Pattern, for use, e.g. in re-matcher."

23:20 sineer: thanks!

23:29 any clue how to build a regex with a wildcard - or _ anywhere within a string? I need to match "string" "s-tring" "st-ring" ...

23:48 solatis: ohhhh i understand what i need to do with fixtures now to pass around arguments!

23:48 and the solution is _not_ pretty

Logging service provided by n01se.net