#clojure logs

2015-03-21

00:45arav93Goodnight! :)
02:48aytch#16 is a bit tricky
02:49aytch(= (__ "Dave") "Hello, Dave!")
02:49aytchthe naive response (mine) was: str "Hello, "
02:50aytchbut that doesn't evaluate as true, because it needs the "!" at the end
02:52aytch(= (str "Hello, " "Dave") "Hello, Dave")
02:52aytchtrue
02:52aytch(= (str "Hello, " "Dave") "Hello, Dave!")
02:52aytchfalse
02:52TEttingeryep
02:52TEttingerso you need to define a function there
02:53aytchyeah, I'm realizing that
02:53aytchit's just an exponential leap in difficulty
02:53aytchstrings were only introduced in a question or two before
02:53SeyleriusWhat's this: koans or something?
02:53SeyleriusOr 4clojure?
02:53aytchSeylerius: 4clojure
02:54TEttinger(fn [name] (str "beginning " name " end"))
02:54aytchthe title of the problem is "Hello World"
02:54aytchnot "String Concatenation"
02:54TEttingerheh, hello world usually involves string concatenation as the second step
02:54TEttingerhello yourname
02:55aytchAbsolutely, I agree
02:55TEttinger4clojure definitely gets challenging quickly
02:55TEttingerhave you reimplemented nth yet?
02:55SeyleriusAnnoyingly, 4clojure doesn't let me sign up.
02:56aytchI'm guessing no
02:56TEttingerthat's one of the tasks that comes up around 20-30-something I think
02:56TEttingerit's a good challenge
02:57amalloySeylerius: doesn't let you sign up?
02:58SeyleriusWell, it let me sign up, but it keeps giving me an error on log in, and not a password error.
02:58SeyleriusOkay, the problem seems to have been related to my username being capitalized.
03:26aytchI don't know who _pcl is, but all their answers match up with mine. And other people do some weird voodoo.
04:13SeyleriusRandom but funny bit of dialogue from something I read recently: "Great. That probably means I'll be shooting eyebeams by next week." ;; "That was actually a party trick of your great-grandfather's, if I remember the stories correctly. He used it to incinerate enemies, destroy citadels and open canned goods, for which I am sure that your great grandmother was ever grateful."
04:13SeyleriusTotally off topic, but amusing.
04:42SeyleriusY'know what's weird? Sometimes the 4clojure tests display one of the tests as failed, even though the solution is correct and the problem gets marked as solved.
04:42SeyleriusOnly seems to happen on the multi-test problems.
04:50aytchSeylerius: on the multi-test problems, there is only one correct solution.
04:51aytchthe code will either pass all of the tests, or none of them, but the graphics are misleading.
04:51Seyleriusaytch: Exactly. And I submit the right one, the system marks that I've passed, but one of the tests gets a nice red dot, even though all logic says it should have passed that test too.
04:52SeyleriusIt's very odd.
04:52aytcherrr....there are multiple correct ways to implement the solution, but one solution must pass all tests.
04:52aytchI was asking about this a few days ago.
04:52SeyleriusThere must be some kind of bug in the rendering.
04:53SeyleriusIt can't really be failing that test, because I wouldn't get a "Solved!" result, but it still looks like it failed that test.
04:53SeyleriusVery strange.
04:53aytchWhich #?
04:53SeyleriusI can't remember which one did it last. Maybe 17 or 18? I'll pipe up next time it does it.
04:54Seylerius19 is... interesting.
04:54SeyleriusReimplement last.
05:45Seyleriushttp://sprunge.us/KYef
05:46SeyleriusThat's failing 4clojure #21: Nth Element
05:46SeyleriusOh, wait...
05:46SeyleriusNevermind
06:28anti-freezeHey guys/girls. Does anyone have any issues with mongodb timing out?
06:29deanmHello, can you please suggest an easy reading introduction to Clojure? I've tried a couple like braveclojure.com and "The Joy of Clojure" book but find it they move too fast for my understanding
06:33anti-freezedeanm: Maybe just clojure in action or programming clojure. I hear those are good. There's a new one soon to be released by o'reilly "Living clojure"
06:40deanmThanks anti-freeze, ill have a look at them as well
06:46anti-freezeSorry, my mac went to sleep. Did I miss anything?
06:48deanmanti-freeze: nope, other than me saying thanks for the tips
06:48anti-freezedeanm: Ah, now that I remember. Probably the best intro is clojure for the brave and true
06:48anti-freezedeanm: Its free online
06:49deanmanti-freeze: Yeah i tried that but at some point around destructuring i couldn't follow up and had to look up other references on the net so it occured to me that maybe im too dumb for that and need something more easy
06:50anti-freezedeanm: The thing with clojure is that it needs perseverance. Its frustrating at first
06:50anti-freezedeanm: It was easier for me coming from a ruby background, where it was sort of pseudo functional
06:51deanmanti-freeze: Ok nice to hear that, i come from a Java background although i don't program these days anymore
06:52anti-freezedeanm: That's probably why its frustrating. Check this out: http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html
06:54anti-freezeAnyone with suggestions on the mongodb issue?
06:54anti-freezeT'was working yesterday, I swear it
07:12anti-freezeAlso, how the hell do I access bounded variables from a macro. Say I have a macro that defines found-user from a DB query. I'm currently using found-user# gensyms, but I wan't access it. For example (if-valid-user params (login-success found-user))
07:21Glenjamin,`~'symbol
07:22clojurebotsymbol
07:22Glenjaminanti-freeze: you can use ~'symbol inside the syntax-quote to get a bare symbole
07:23Glenjaminalthough in general it might be worth asking yourself if the macro provides any benefit over a function
07:24anti-freezeGlenjamin: Something like this? https://ideone.com/DjLZHZ I asked myself that, but it seems to provide more clarity
07:26Glenjamin(if-let [user (user-logged-in? params)] ...)
07:26Glenjaminyou should be able to make that work with roughly the same code and no macro
07:26Bronsaanti-freeze: it's usually better to use gensyms rather than doing the ~' trick to get unqualified symbols
07:26Glenjaminmaybe that should be called (logged-in-user params)
07:27anti-freezeBronsa: I know, but i still want to access the found-user value to add his ID to session
07:28Bronsaanti-freeze: also you're trying to get runtime values at constant time
07:28Bronsacompile time*
07:28anti-freezeBronsa: Well shit, how would you do it?
07:28Glenjaminthe macro pasted is just some sugar for an if statement
07:28anti-freezeAh, I give up...
07:29Bronsaanti-freeze: I'm talking about that cred/pass let. you don't seem to actually use those locals though
07:29anti-freezeMongo doesn't work, I can't get simple authentication working...
07:31Bronsaanti-freeze: it's usually a good idea to have a solid understanding of how the language works before trying to write your own macros
07:31anti-freezeBronsa: Yup, makes sense. I was swayed to clojure by all the preaching and what not of how amazing it is
07:32Glenjaminmacros are a funny one, they're a headline language feature, but actually not used particularly often
07:32Glenjamini overused macros quite a bit in my first clojure project
07:33anti-freezeHow do I pass the then else branches then?
07:33Glenjaminjust use a normal if form
07:33anti-freezeGlenjamin: Ah, makes sense
07:33anti-freezemakes cents?
07:36Glenjaminsense is correct
07:36Glenjaminsomething like this: https://www.refheap.com/98698
07:37anti-freezeGlenjamin: Yea, that's what I changed it to. Hold on, let me do some copypasta
07:38anti-freezeGlenjamin: https://www.refheap.com/7c95d4846cc402dccbf87c6c5
07:38Glenjaminyep, you can shrink it down a bit with some destructuring and more if-let, but thats the right idea
07:41anti-freezeGlenjamin: Alright man, thanks a bunch
10:12anti-freezeHi again everyone. I can't seem to access the return values of mongodb insert operations. I just want to get the insert ID. Any ideas?
10:16anti-freezeSimply, is there a way to convert a monger WriteResult to a map?
10:19gfredericksanti-freeze: is a WriteResult a defrecord?
10:22anti-freezegfredericks: Its a java class I think. I can't just reference properties with (:_id rec)
10:22gfredericksbut monger is a clojure library?
10:23gfrederickshave you tried clojure.core/bean?
10:25anti-freezegfredericks: Just did, got me nowhere
10:31justin_smithanti-freeze: unrelated question - what exactly is the :flash key there?
10:31anti-freezejustin_smith: Flash key? There is none. I'm running tests and as part up setup I want to store a newly inserted users ID to check against the user ID stored in session
10:32justin_smithanti-freeze: I mean the :flash key on line 16 of https://www.refheap.com/7c95d4846cc402dccbf87c6c5
10:33anti-freezejustin_smith: a map containing errors and the previously passed parameters for dispatch to the view
10:33justin_smithanti-freeze: is putting stuff like that under a :flash key an idiomatic thing? is this related to the wrap-flash ring middleware?
10:34anti-freezejustin_smith: I don't know. I believe it is, yea
10:42anti-freezeDon't worry about the mongo thing guys, you're supposed to use insert-and-return. I don't know why that's not default behaviour, but ok
10:57gfredericksmaybe insert is async?
10:58gfredericksI don't know nuthin bout mongo so I just assume it defaults to doing the fast-uncertain thing
10:58justin_smithgfredericks: yeah, I think so. Because nosql.
10:59anti-freezeI'm not sure. I'm just using it for the schemaless stuff
10:59anti-freezeOne more question... for now. How would you test macros?
11:00anti-freezeSomething like this: https://www.refheap.com/98704
11:01gfrederickswrite some tests that use them maybe
11:01gfredericksis the whole point of these to be anaphoric?
11:02gfredericksI don't think testing macros is too crucial unless they're really complicated
11:02anti-freezegfredericks: Not really, its just that I was always writing (POST "/route" request (func request))
11:02gfredericksjust test the code that uses them
11:02justin_smithanti-freeze: what's up with ~'request ?
11:03justin_smithoh
11:03anti-freezejustin_smith: I want to use the symbol request. So the result is (REQUEST-POST "/route" func) => (POST "/route" request (func request))
11:04justin_smithright, because you are generating a macro call with your macro
11:04anti-freezejustin_smith: Pretty much. I can't pass macros around unfortunately, or else I would have a REQUEST-* macro, which has the type of the request passed to it
11:05anti-freezegfredericks: I guess the macros work just fine then
11:38anti-freezeIs anyone planning to implement an interactive clojure debugger by the way?
11:43IgorI run "lein uberjar" but it print "compiling" and that's all, jar doesn't appear
12:01not-much-ioHi all, I am trying to complete a HackerRank challenge with Clojure, but unfortunately my code is not cutting it speed wise. Using the time macro also didn't really show any bottlenecks.. Any suggestions? -> https://gist.github.com/KristoKoert/17ad1960ec2058388e63
12:02Glenjaminyou can try using a profiler like Java VisualVM
12:03not-much-ioI suppose it's as good a time as any to learn to use a profiler :)
12:20IgorI found solution - every code must be in functions
12:21not-much-ioWhat do you mean?
12:23not-much-ioIt's purely a performance issue as I see it because about 5 test cases pass, however as the inputs get larger timeouts occur because the program won't finish under the 8s cap.
12:24IgorI try get uberjar, but it doesn't work until I delete code outside funcs declarations
12:25not-much-ioWell yes because input-list isn't defined
12:26not-much-ioI can't really trivially upload a workable uberjarrable example because the input is approx a miljon characters long.
12:26Glenjaminyou're both talking about different problems.
12:27justin_smithisn't hackerrank the one where clojure always performs poorly because they include the clojure bootstrapping time in the perf timing?
12:28not-much-ioScala and Clojure are given extra time for that as I understand it.
12:28justin_smithoh, OK
12:28not-much-ioBut I saw that others had done the challenge in Clojure
12:29justin_smithit's not about jvm overhead though. It's about the clojure compiler bootstrap
12:29justin_smithOK
12:30justin_smithnot-much-io: I think your keyword conversions are not needed
12:30not-much-ioIt's only a 10 point excercise so I was surprised my solution didn't pass the time constraints. Thought I had done something obviously stupid :)
12:30justin_smithjust use the string as the key in the hash
12:31justin_smithnot-much-io: also, yeah, every top level form should be a def/defn or some other similar declaration, not side effects and not regular code
12:31justin_smithfor uberjar reasons, among other reasons
12:31justin_smitheg. loading a namespace should not have side effects
12:32not-much-ioYes I am aware of that, the outer expression was just to feed the results into the HackerRank engine.
12:32not-much-ioMaybe I should not have included it, my bad.
12:32not-much-ioChecking on the keyword conversion thing..
12:32justin_smithahh, right, I was referencing your prior comment "I found solution - every code must be in functions"
12:33justin_smithnot-much-io: only use keywords for literals in code (or what you expect the end user to provide as literals)
12:33not-much-ioNo, that wasn't me :D
12:33justin_smithif it's a string, it can stay a string
12:33justin_smithnot-much-io: oops, my bad :)
12:34not-much-ioOkey, but is it really that expensive of a converion? :O
12:34not-much-ioI did it more for style than anything, but ofcourse it was pointless in this case
12:35justin_smithnot-much-io: well I'd think it's a minus for style unless somebody is using the keywords as literals (which doesn't appear to be the case)
12:35justin_smithand yeah, repeated keyword conversions aren't super expensive, but they are not free either
12:36not-much-ioAgreed that it's a minus
12:37justin_smithoh wow, I found a bug in criterium
12:37justin_smithlol
12:38not-much-ioA bug?
12:38justin_smithExecution time mean : -3.551208 ns
12:38justin_smithI don't think there's such thing as code with a negative runtime
12:38not-much-ioBTW there was a a conversion from char -> str -> keyword going on
12:39justin_smithoh wow, yeah, just use the char!
12:40justin_smithcheck out this silly benchmark https://www.refheap.com/98711
12:44not-much-ioUnfortunately removing the conversions had no effect :(
12:44justin_smithhave you tried profiling? jvisualvm is pretty accessible
12:44justin_smithsometimes just called visualvm
12:44not-much-ioI was in the process of learning to use it, haven't used it before.
12:45justin_smithyou should be able to find the cpu profiling tab
12:45justin_smiththe issue after that is that it will show you stuff in terms of the jvm impl, not the clojure abstractions
12:46not-much-ioDo I need to generate a uberjar to use it? I usually just use the repl for these kind of problems.
12:46justin_smithno, visualvm can connect to your repl
12:46justin_smithturn on cpu profiling, then run your main function
12:46justin_smithor whatever other function you want to profile in detail
12:47justin_smithyou should get a clickable for each running jvm on the left side of the ui
12:47not-much-ioOooooh, thats all?
12:47not-much-ioThat was easy
12:47justin_smithyeah, it's easy, point and click
12:47justin_smithheh :)
12:47not-much-ioThanks! I would probabl have wasted a lot of time trying to use it :D
12:47not-much-iogetMethods() are the mainusage
12:48justin_smithreflection!
12:48justin_smithtry turning on reflection warnings vie project.clj
12:48justin_smithand fix the warnings
12:49not-much-ioBut wont that then show me something different than what runs on HackeRank?
12:49justin_smiththe warnings tell you what you need to fix
12:49justin_smithonce it's fixed, it's fixed regardless of where it runs
12:49not-much-ioDo you mean the leinigen project.clj? Because I don
12:49justin_smithyou use hints so that clojure doesn't need to use reflection to figure out which method to run
12:49not-much-io't even have a separate project
12:50justin_smithin that case, start up the repl with reflection turned on
12:50justin_smithjust make sure *warn-on-reflection* is true, whatever method works for your repl
12:50justin_smithit's just convenient to do that from project.clj
12:51not-much-ioCan I change it in a runnig repl?
12:51justin_smithI'm trying to think of how it's done, I haven't done it recently...
12:52justin_smith(set! *warn-on-reflection* true)
12:52justin_smiththat will work for the current thread, and any agents / futures created from that thread
12:52justin_smithif you use Thread though, it might not propagate
12:53not-much-ioNope, no threading currently
12:53not-much-iookay, much less gets now
12:54justin_smiththen run your code, and where you get reflection warnings, add hints about the actual type that will be seen at runtime
12:55not-much-io1. reflector.getMethods() 2. rule3.invoke() 3. PersistenArrayMap.assoc() 4. rule4.invoke()
12:56not-much-ioReflection still on maybe..
12:56justin_smithnot-much-io: if you have reflection warnings turned on, then defining your functions should make the clojure compiler tell you where the reflection is happening
12:57justin_smith*warn-on-reflection* is about giving you guidance to where type hints are needed to speed up your code
12:57justin_smithit doesn't actually make anything faster by itself
12:57not-much-ioSo you are suggesting I add type hints?
12:58justin_smithnot-much-io: that's how you make clojure not spend time in reflector.getMethods(), yeah
12:58justin_smithand that will often be the biggest perf gain you can get in a clojure program
12:58not-much-ioOkey, now I understand.
12:58not-much-ioMakes sense.
12:58not-much-ioThanks, learned alot. :)
12:58justin_smiththis is especially true for math
12:59justin_smithwhere it can compile direct arithmetic ops for the correct type, instead of a bunch of reflection and generic math methods
12:59not-much-ioStill I am surprised something simple like this requires type hints. EIther my algorithms sucks or the HackerRank people didn't bother with trying clojure. :)
13:00justin_smithnot-much-io: if you want good performance, clojure requires type hints
13:00not-much-ioOkey, so to reiterate: If the profiler shows me a lot of time spent in Reflector.getMethods() it's a reflection thing?
13:00justin_smithyes
13:01justin_smithand you can fix your code so that Reflector.getMethods() never gets called
13:01J_Arcanenot-much-io: I'm finding that some of the online exercises for Clojure are a bit rubbish. Codewars' clj support is a mess.
13:01justin_smithreflection is very expensive
13:01not-much-ioI though as much about the type hints, it's just it hasn't been a problem until now, even with much harder problems.
13:02justin_smithor, to be more explicit - code that requires reflection is very hard for the vm to optimize, and the reflection process itself is slow too
13:04justin_smithnot-much-io: another thing that is going to add up over 100000 calls is the usage of a persistent data structure. If the code path is such that it wouldn't need copying, a simple four element array is going to speed things up a lot since so much of your code is just getting things from / updating values in that four element data structure
13:05justin_smithin general persistent data structures are awesome, but sometimes it can be safe to use a mutable thing, and it can be worth it for the 10x or more perf gain
13:05justin_smiththat would also make your code uglier though
13:06not-much-ioGod damn it, sutpid question, how do you refer to someone in IRC :D
13:06justin_smithmost clients will highlight usages of a nick
13:06justin_smithand will tab-complete a nick too
13:06not-much-iojustin_smith Test
13:06justin_smithright, that highlights in my client
13:07not-much-ioOkey
13:07not-much-ioJ_Arcane Probably the pains of a growing language :)
13:08justin_smithnot-much-io: also the pains of a language that requires the full compiler to be loaded before code can be run
13:08not-much-iojustin_smith Thanks for the tips, I'll certainly keep them in mind.
13:09justin_smithnp - if you can eliminate reflection, and use a simple array in a tight loop when it's safe to do so, there's nothing keeping clojure from being at least as fast as java
13:09J_ArcaneArgh. Could you repeat that? I missed it because my client crashed ...
13:10not-much-iojustin_smith J_Arcane It's probably the pains of a growing language and justin_smith added that it's also a problem of a language that requires loading the full compiler.
13:10not-much-ioIs reflection the main culprid for runtime speed?
13:10J_ArcaneYeah. The Clojure world in general does have a very 'beta' feel at times. :)
13:11justin_smithnot-much-io: yeah, reflection followed by persistent data structure overhead. Never any reason not to eliminate the former, the latter is worth it for correctness unless you need that last 8-10x speed increase.
13:12not-much-ioI wonder if HackerRank took Clojures startup time into account? I doubt it, iflooking at Clojure vs. Scala -> https://www.hackerrank.com/environment
13:13not-much-iojustin_smith Awesome, that is worth knowing. I sort of did, but never really approached the problem :)
13:14justin_smithnot-much-io: and typically your profiling will give you a good lead - whether you are spending a lot of time in reflection, in generic math ops, in persistent data structure allocations...
13:15BronsaI kinda wish one had to allow the compiler to use reflection explicitly
13:15justin_smithBronsa: oh, that's a great idea for a feature
13:15justin_smith(set! *warn-on-reflection* :pedantic)
13:15justin_smithhaha
13:16not-much-ioAs I've looked around, it seems a lot of peole are discontent that clojure is dynamically typed..
13:16hyPiRionI'd like the compiler to detect uniqueness and do transient magic on the persistent data structures.
13:16Bronsajustin_smith: wouldn't make much sense to add that but not make it the default
13:16hyPiRionBut the persistent data structures are actually very good performance wise, really.
13:16justin_smithBronsa: I don't think it would fly unless it was opt-in though
13:17Bronsajustin_smith: right, it's too late to change that in clojure unfortunately, I guess
13:17justin_smithhyPiRion: it's true, but I've also seen the difference a switch to an array in a tight loop can make (because of the mixture of eliminating allocation + cache coherence)
13:18justin_smithfor primitive types that is
13:18Bronsabtw clojure doesn't really need the whole compiler to run code -- when it AOTs it just needs the runtime
13:18justin_smithBronsa: but being able to turn it on for my own code would be great
13:18justin_smithBronsa: but will it actually run without loading the compiler from AOT ?
13:18hyPiRionjustin_smith: yeah, true enough.
13:18Bronsajustin_smith: would it help you more than (set! *warn-on-reflection* true)?
13:18justin_smithBronsa: I thought the compilation stuff would be loaded regardless
13:19justin_smithBronsa: maybe not
13:19justin_smithBronsa: also, in the context of the code challenge there, I don't think they let you submit an uberjar? not sure though.
13:20Bronsajustin_smith: what i mean is, once you AOT compile clojure.lang.Compiler is not necessary anymore as there's no clj compilation involved while loading
13:20not-much-iojustin_smith Not in HackerRank no
13:21justin_smithBronsa: OK. So unless your own code causes it to be loaded at runtime, it won't be.
13:21justin_smithI guess I should have ended that with a question mark, as it was a question :)
13:39not-much-iojustin_smith: Reporting back, with typ hints to Math/abs performance increase of ~8 times :)
13:45gfredericks~reflection
13:45clojurebotExcuse me?
13:47chenglouwhy doesn't this terminate? (def a (range)) (def b (rest a)) (def c (rest a)) (= b c)
13:47not-much-io(range) is a infinite sequence
13:48chenglouyes, but I thought b and c were just pointers to the same "next" slot in a
13:48not-much-ioalthough, you don't seem to be forcing evaluation..
13:49not-much-ioNo, rest takes the whole remaining sequence (infinity - the first) :)
13:49not-much-ioWhen you compare them, they are evaluated
13:49chenglouwell, I thought at one point you'd hit a pointer equality when you compare both streams
13:50chengloujust like you would, trying to deeply compare two trees
13:50not-much-ioClojure does not compare pointers, it compares values
13:51chenglouit does pointer comparison first though
13:51not-much-ioOh, sorry I am misinformed then.
13:51chenglouotherwise (= a a) would get stuck
13:51not-much-ioIs it comparing the pointers of the list or the element?
13:52chenglouI guess the element, which is why my example doesn't terminate
13:52not-much-ioWould seem that way.
13:52chenglouwhich is why I wonder it doesnt do it for the list, since it does something like that for subtrees for the other 3 collection types
13:53not-much-ioIt's actually a lazyseq
13:53not-much-io(type (range))
13:55not-much-iolazyseq might be a special case because it can be infinitely big. However I am just speculating. :)
13:55chenglouit can
13:55chengloubut I guess this example makes slightly more sense:
13:55chenglou(def a (range)) (def b (rest a)) (def c (cons 1 (nnext a)))
13:55chenglouthen (= b c)
13:56chenglouyou'd think that while going through the list it'd compare the list pointer first, hit the element 1, deeply compare, hit the rest of the list
13:56not-much-ioI mean I am speculating about whether or not it is a special case implementation wise.
13:56chenglouthen see the rest of the list point to the same place in a
13:56not-much-ioI would think that (rest myseq) would return a new sequence
13:57not-much-ioClojure data structures are immutable
13:58chenglouyes I get that, but I was wondering why it didn't do it like this: "b's first cell is a new item, b's second third fourth... just point to that chunk in a"
13:58not-much-io(rest a) (conj a 1) etc. all create a new datastructure, though they reuse the old ones elements (for performance) it would make sense to consider them different
13:58chenglouit does, but I'm not explainining this correctly
14:00not-much-ioAs I understand you are surprised that two different datastructures with "shared" (as in under the hood shared) elements are not equal in term of pointers
14:00dnolenchenglou: it could probably behave the way expect, but sequence equality tests is eager on elements of the sequence, it doesn't special case equality testing of the tail
14:01dnolens/the way/the way you expect
14:02chengloudnolen: I see. But does it make sense conceptually to compare the tail? Disregarding the perf benefits
14:02chengloulike, should my above example be allowed:
14:02chenglou`(def a (range)) (def b (rest a)) (def c (cons 1 (nnext a))) (= b c)`
14:02chengloucertainly works for all the other collections
14:05chenglounot-much-io: yeah I guess. I got that expectation from all other collections
14:12Bronsachenglou: the problem there is that calling rest on (range) returns a new value each time
14:14Bronsachenglou: if you replace (rest) with (iterate inc 0), it will terminate
14:15chenglouBronsa: right. But calling (conj a 1) also returns a new value, for a vector a
14:16chenglouIf I'm not mistaken you could do (= (conj a 1) (conj a 1)) and it'll do pointer comparison for the a subtree
14:17Bronsachenglou: clojure will do pointer comparison before doing value checks, this is why (def a (iterate inc 0)) (= (rest a) (rest a)) returns true in constant time
14:19chenglouBronsa: what I was asking for is why lazy seqs didn't do tail comparison before cell comparison. Which dnolen said isn't implemented (yet? Or will never be? Dunno)
14:19Bronsachenglou: because of implementation details in (def a (range)) (def b (rest a)) (def c (rest a)) b and c will never have an identical pointer
14:19justin_smith~range
14:19clojurebotexcusez-moi
14:19Bronsathis has to do with range being a chunked-seq
14:21Bronsa= isn't chunk-aware
14:21justin_smith~range is |reply| because range is a chunked-seq.
14:21clojurebotc'est bon!
14:21justin_smith~range
14:21clojurebotrange is |reply| because range is a chunked-seq.
14:21justin_smithargh!
14:21justin_smithclojurebot: forget range
14:21clojurebotHuh?
14:21justin_smithugh
14:22justin_smith~forget range
14:22clojurebotI don't understand.
14:23Bronsachenglou: what you described is how lazy-seq do work. this is why it works for (iterate inc 0). (range) is a special type of lazy-seq, backed by a chunked-seq as opposed to a normal seq, the tails will never be identical
14:25amalloyclojurebot: forget range is |reply| because range is a chunked-seq.
14:25clojurebotI forgot that range is reply because range is a chunked-seq.
14:25justin_smiththanks
14:25amalloyclojurebot: range is <reply> because range is a chunked-seq.
14:25clojurebotc'est bon!
14:25amalloy~range
14:25clojurebotrange is |reply| because range is a chunked-seq.
14:25amalloyuuuugh
14:25justin_smith~clojurebot
14:25clojurebotclojurebot is a weirdo
14:26amalloyclojurebot: clojurebot is like an elephant: he never forgets a useless factoid
14:26clojurebotRoger.
14:26chenglouBronsa: I see. I'll think a bit more about this, thanks
14:29Bronsachenglou: I just looked at the lazy-seq source and it looks like I'm partially wrong, there's no pointer-equality check on the tails. I apologize
14:30Bronsaagreed this somewhat is surprising
14:31chenglouBronsa: ah. Well tldr: I was wondering if value comparison of infinite lazy seqs should even be allowed (say, for get-in a value with a lazy seq key in a map)
14:31justin_smithBronsa: then why is it that ##(let [n (iterate inc 0)] (= (rest n) (rest n))) works?
14:31lazybot⇒ true
14:31chenglouif it's a map of vector -> int in the worst case I retrieve the int using a different vector and I only pay a small price for deep equality check on the key
14:31chengloubut with lazy seq it's not just a small perf cost. It might loop forever
14:31justin_smithchenglou: well, there is no marker to tell you if a lazy seq terminates
14:32anedoes requiring a namespace with :refer :all not import the defrecords
14:32justin_smithane: require doesn't import classes
14:32Bronsajustin_smith: because = does pointer equality
14:32chengloujustin_smith: yes which is why I was thinking if conceptually you should just claim that you don't guarantee that behaviour at all (retrieving value in a map using a lazy seq, with value comparison)
14:32justin_smithBronsa: oh, OK
14:33Bronsajustin_smith: the issue is with e.g. (let [n (iterate inc 0)] (= (cons 1 (rest n)) (cons 1 (rest n)))
14:33justin_smithane: use :import for classes
14:33justin_smithBronsa: ahh! OK
14:33anejustin_smith: oh yes. what's the best approach in tests? that?
14:33Bronsawhich would work if lazy-seq used = internally, but they don't
14:33Bronsathey just invoke .equals skipping the pointer check
14:33Bronsahttps://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LazySeq.java#L120-L121
14:33justin_smithane: sure, or just use the class fully qualified with package, importing is just a syntax convenience
14:34justin_smithBronsa: thanks, now I get it
14:34anejustin_smith: oh, bloody hell, yes
14:35tolstoyAnyone having issues with the latest cider snapshot? No repl appears.
14:36justin_smithtolstoy: did you delete all your elc files? when you upgrade cider versions your elc files are invalid
14:36justin_smithcommon cause of cider pain
14:36tolstoyYeah, let me double check. My last version was 8.2. Didn't see anything odd over there (8.2 dir is gone).
14:36justin_smithcaused by the fact that cider abi is a moving target, and elisp doesn't compile in a way that handles that nicely
14:37justin_smithtolstoy: this isn't just about cider elc files, it can be effected by eg. clojure mode elc files too in my experience
14:37justin_smithand of course you also need to restart emacs after a cider version upgrade
14:38tolstoyI do that the first sign of trouble. I learned at least one thing from using Windows in 1999 for six months!
14:38justin_smithhaha
14:39tolstoyWorks now (just killed ALL elpa stuff), but get: WARNING: CIDER requires nREPL 0.2.7 to work properly
14:39justin_smithtolstoy: did you upgrade your cider-nrepl dep to match your new cider.el version?
14:40tolstoyAh, probably some other dep is pulling that in.
14:40tolstoyYeah. Snapshot.
14:40justin_smithsnapshots are by default only fetched daily, but there is a way to force update sooner
14:40justin_smithwhich I don't recall off the top of my head...
14:41tolstoyrm -rf ~/.m2
14:41tolstoy:)
14:42justin_smithyes, there is always the nuclear option, but there is a more elegant way to do it as well
14:42tolstoylein -U?
14:43tolstoyWell, I only moved to the 0.9.0-snapshot today, so I'm not sure were the nrepl dep is. tools-nrepl?
14:44justin_smithoh, I don't know then - there is a way to look at the plugin deps tree
14:47tolstoylein deps :tree reveals all, but I do't see a dep for nrepl with cider-nrepl. However, it does show up as a top level dep.
14:47justin_smithtolstoy: could be your lein version injecting it?
14:47tolstoyYeah.
14:48Bronsachenglou: FYI I'm opening a ticket with a patch that introduces the pointer check in seq comparison
14:54tolstoyjustin_smith: Interesting. Although cider-nrepl (according to its project.clj file) requires 0.2.7, lein somehow does something to remove it and inject its own nrepl as a top-level dep.
14:54pandeirotolstoy: you need to specify tools.nrepl in :dev :dependencies
14:54tolstoyMaybe that makes sense.
14:55pandeiroi don't understand lein well enough to know why :dev :dependencies take precedence over :dependencies
14:55justin_smithtolstoy: try providing it as a top level dep in your profiles.clj
14:55pandeiromaybe that is intuitive, i don't know
14:55justin_smithpandeiro: it's because ones a top level dep, and the other is transitive
14:55pandeirothe fix for this is known, hyPiRion posted it
14:55justin_smithtop level takes precedence
14:55pandeiroboth should be top level?
14:56justin_smithpandeiro: not if one is coming from cider
14:56justin_smiththat's why the fix is to explicitly specify the dep on your own top level
14:56pandeirojustin_smith: nope not what i'm saying
14:56pandeirospecifying in your own top level doesn't fix it
14:56pandeirospecifying it in your own top level *:dev* does
14:56pandeirowhich to me is sort of odd
14:56justin_smiththat's weird
14:57tolstoyYeah, making it a dep of the :dev profile "solves" it.
14:57pandeirolink: https://github.com/technomancy/leiningen/issues/1840
14:57pandeiroblack magic
14:57hyPiRionboth are top level, but you shouldn't add tools.nrepl as a project dep only because you need the latest cider
14:57pandeirohyPiRion: adding as non-dev does not fix
14:57justin_smithhyPiRion: profiles.clj :dev dep, of course
14:58justin_smithpandeiro: I think that is because of how profiles are merged and the effective profile is generated
14:58justin_smitha :dev dep overrides a regular dep
14:58pandeirojustin_smith: right, i imagined a merge was happening
14:58hyPiRionoh, yeah no, that's not happening. That'd be bad for repeatability
14:59pandeirohyPiRion: what would be bad for repeatability?
14:59pandeirobeing able to specify a project's tools.nrepl version explicitly?
14:59hyPiRionmerging stuff from .lein/profiles.clj into the project.clj on dupe profiles
15:00pandeirowhich one wins in the case profiles.clj has one :dev version and project has another?
15:00hyPiRionthe most local one
15:01pandeiroproject -> dep is less local than profiles -> :dev ?
15:01tolstoyI think the profiles.clj one wins. I just had that issue with an old lein-ancient.
15:01hyPiRionproject.clj ← local profiles.clj ← user profiles.clj ← system profiles.clj
15:01tolstoySpeaking of which, tools.nrepl "0.2.8" is available.
15:02gfrederickswith one less reflection warning :)
15:03hyPiRionBut there is a regression related to transitive dependencies on tools.nrepl. The fix is going to be in 2.5.2
15:03hyPiRionjust fyi
15:03Bronsachenglou: http://dev.clojure.org/jira/browse/CLJ-1679
15:26chenglouBronsa: woohoo thanks!
15:30seangroveBronsa: Very nice
16:42MandarHello!
16:42MandarI'm playing with transducers.
16:43MandarIs this code idiomatic? http://pastie.org/private/vgbhlsx0ugxpsfdorfajw
16:44Mandaris there any better way to do null punning?
16:50tomjackif I was forced to do that for some reason, I'd consider def'ing a (fn [f] (fn [arg] (if (nil? arg) nil (f arg)))) separately
16:51tomjackthen (map (letting-nils-be f)) or whatever
16:52tomjack(map #(cond-> % (some? %) f)) ?
16:53tomjackbasically it would generally seem un-idiomatic to me to define a special map which just modifies f, instead of passing a modified f to map
16:54Mandartomjack: thank you
16:54tomjackif some particular case comes up a lot in a development, maybe makes sense, though (e.g. I guess keep came up enough in general clojure code to be added)
16:56tomjackI guess your transducer may be dual to keep?
16:56MandarI don't really know. Basically, I'm trying to avoid null pointer exceptions.
16:57tomjack(for amusement, I'm trying to think of an analogous name -- "leave"?)
16:57Mandarit's close to a Maybe, but I'm a FP newbie
16:58Mandarbasically, I tried to reimpliment this behaviour: https://github.com/clojure/algo.generic/blob/master/src/main/clojure/clojure/algo/generic/functor.clj
16:58Mandarbut with transducers
17:03tomjackeither your custom transducer or just modifying the fn passed to map seem reasonable to me. if you go with a custom transducer, I guess it might be idiomatic to also provide the other arities for seqs, like clojure.core/map
17:03tomjackdunno
17:03tomjackmaybe future libs will tend to drop that, and it's just there for backwards compat
17:04tomjackI'd guess people will do it when it's easy
17:04tomjackfor something used not-too-often I'd prefer just calling map, because everyone knows what that means already
17:05gfrederickstomjack: #(cond-> % (some? %) f)) ===> #(some-> % f)
17:05tomjackoya!
17:06tomjackMandar: ^
17:06Mandartomjack, gfredericks: thanks!
17:06tomjackI still am not on great terms with the new arrows
17:06MandarI don't understand this code yet
17:06MandarI rewrote mine with a my-nil-pun fn
17:07gfrederickstomjack: I just yesterday realized I could use as-> at the end of a normal threading form to give the thing a name and do more complex stuff with it
17:07tomjackI think part of the reason I tend to avoid them is that I'm scared of all the unknown possibilities :)
17:07Mandarthe only problem I see with this approach is the need to "protect" all the functions in the comp
17:07Mandar"protect" meaning wrap them with my-nil-pun
17:08Mandardoing a custom transducer lets me avoid that, but I don't know if it's a bad practice
17:08tomjacknah, if you're using it a lot, go for it, I think
17:09gfrederickswell up
17:09gfredericksum
17:09gfredericksI mean
17:09tomjacks/think/opine/ :)
17:09gfredericksyou don't have to think of it as writing your own transducer
17:09gfredericks(defn leave [f & args] (apply map #(some-> % f) args))
17:09tomjack:/
17:09gfredericksit's just a modification of map
17:10tomjackoh, you're targetting 1 and 2-arities?
17:10gfredericksand etc
17:10gfredericks3, 4, even 5
17:10tomjackbut #(some-> % f) is 1-ary
17:11gfredericksokay not 3, 4, nor even 5
17:11tomjackbut yeah, nice :)
17:11gfredericksI wonder if I can pass an infinite number of args to map
17:11Mandargfredericks: your code is not using transducers anymore, is it?
17:11gfredericksMandar: sure it is, because map does
17:12Mandarsorry, doing my best! :)
17:12gfredericks,(apply map #(first %&) (repeat (range 5)))
17:12clojureboteval service is offline
17:12tomjackbetter idea to sacrifice clojurebot than my emacs responsiveness :(
17:12gfredericks&(apply map #(first %&) (repeat (range 5)))
17:12Mandarhaha
17:13oddcullyclojurebot: this is an outrage!
17:13clojurebotIn Ordnung
17:14justin_smith~this
17:14clojurebotthis was discussed in a loud bar
17:15gfredericks~I
17:15clojurebotI will never forgive constantly polluting useful triggers like ~anyone by learning other irrelevant factoids to repeat instead
17:15gfredericks~I
17:15clojurebotI will never forgive dumb
17:15gfredericksman me neither
17:16tomjack:)
17:23Mandarthank you very much guys
17:42benjyz1hi. quick question. how do I get "bar" out of this structure: {"foo" {"bar" 266}}
17:46oddcullybenjyz1: (get-in {"foo" {"bar" 266}} ["foo" "bar"])
17:46TEttingerthat will get the value associated with bar
17:47benjyz1thx. I'm a bit confused. this is an arrayhashmap, correct?
17:47TEttingerit's usually called a map
17:47TEttinger,(def foobar {"foo" {"bar" 266}})
17:47clojurebot#'sandbox/foobar
17:48oddcully,(get-in {"foo" {"bar" 266}} ["foo" "bar"])
17:48TEttinger,(val foobar)
17:48clojurebot266
17:48clojurebot#error{:cause "clojure.lang.PersistentArrayMap cannot be cast to java.util.Map$Entry", :via [{:type java.lang.ClassCastException, :message "clojure.lang.PersistentArrayMap cannot be cast to java.util.Map$Entry", :at [clojure.core$val invoke "core.clj" 1506]}], :trace [[clojure.core$val invoke "core.clj" 1506] [sandbox$eval54 invoke "NO_SOURCE_FILE" -1] [clojure.lang.Compiler eval "Compiler.java" 6...
17:48TEttingerthe error was mine
17:48oddcullynow it belongs to all of us
17:48TEttingerheh
17:49TEttingerif you want to specifically get the key "bar"
17:49TEttingerreturning "bar", without knowing what key is there beforehand...
17:50TEttinger,(-> foobar get "foo" keys)
17:50clojurebot#error{:cause "java.lang.String cannot be cast to clojure.lang.IFn", :via [{:type java.lang.ClassCastException, :message "java.lang.String cannot be cast to clojure.lang.IFn", :at [sandbox$eval95 invoke "NO_SOURCE_FILE" 0]}], :trace [[sandbox$eval95 invoke "NO_SOURCE_FILE" 0] [clojure.lang.Compiler eval "Compiler.java" 6784] [clojure.lang.Compiler eval "Compiler.java" 6747] [clojure.core$eval invo...
17:50TEttinger,(-> foobar (get "foo") keys)
17:50clojurebot("bar")
17:50TEttinger,(-> foobar (get "foo") ffirst) ; if there is only one
17:50clojurebot"bar"
17:51oddcullyi guess you take this way much to verbatimn
17:52TEttingerI've had cases where I want a key out of a data structure before
17:52oddcullyOP was way unclear
17:52TEttingeryep
17:54benjyz1thx, got it.
17:54TEttingerget-in is great though
17:56benjyz1maybe another question :) what would be the easiest way to update a variable via an agent..
17:57benjyz1I have a function which calls a remote resource, and I want to have the update run once every second
17:57TEttingermost of the time clojure code doesn't need agents, though sometimes it really does
17:59TEttingerhttp://clojuredocs.org/clojure.core/agent start here I guess with the examples, I need to refresh my memory on this
17:59benjyz1I see. still trying to wrap my around refs and agents
17:59TEttingeratoms are nice and simple
17:59justin_smithbenjyz1: an agent is a variable
17:59justin_smithbenjyz1: it holds a value, you send it a function that updates it
18:00justin_smithTEttinger: they are simple, but not so great for things that require side effects in generating the value
18:00TEttingerah
18:00benjyz1and starting a thread to update that state would be non-idiomatic?
18:01justin_smithbenjyz1: sending to an agent uses the agent thread pool
18:01justin_smithbenjyz1: in other words, it's already going to do the work in another thread
18:02justin_smithTEttinger: for example, if you were to use a request to a remote resource to update a value in an atom, retries would be a significant cost, so an agent matches that scenario more closely I think
18:03TEttingerah ok
18:04justin_smiththe maximum number of retries, worst case, is the factorial of the overlaps
18:04justin_smithso three overlapping changes could result in 6 calculations, 4 in 24 calculations, etc.
18:05justin_smithI think...
18:34javjarferhi! Anyone can explain me why (map list {:1 1 :2 2} {:3 3 :4 4}) evaluates to (([:1 1] [:4 4]) ([:2 2] [:3 3]))??
18:34lazybotjavjarfer: What are you, crazy? Of course not!
18:35justin_smithjavjarfer: what did you expect it to do?
18:35justin_smith,(map list [:a :b :c] [:d :e :f])
18:35clojurebot((:a :d) (:b :e) (:c :f))
18:36TEttingermaps are unsorted, so that could be one source of confusion
18:36javjarferjustin_smith, (([:1 1] [:3 3]) ([:2 2] [:4 4]))
18:36TEttingertry using sorted-map there
18:37hyPiRionmaps don't have any ordering by default.
18:37TEttinger(map list (sorted-map :1 1 :2 2) (sorted-map :3 3 :4 4))
18:37TEttinger,(map list (sorted-map :1 1 :2 2) (sorted-map :3 3 :4 4))
18:37clojurebot(([:1 1] [:3 3]) ([:2 2] [:4 4]))
18:37javjarferahhhh, i see... thanks you so much, it was driving my crazy
18:37TEttingerthere's also ordered from flatland
18:38TEttinger$google flatland/ordered clojure
18:38lazybot[flatland · GitHub] https://github.com/flatland
18:38TEttingerhttps://github.com/flatland/ordered
18:39javjarferso, i think probably the third example from here: "https://clojuredocs.org/clojure.core/doseq&quot; should be changed
18:42TEttingerjavjarfer, that's a good catch
18:43javjarferTEttinger, thank you! First contribution xD
18:44TEttinger(inc javjarfer)
18:44lazybot⇒ 1
18:44TEttingeryou has a karma, protect it, nurture it
18:44TEttinger(identity dnolen)
18:44lazybotdnolen has karma 21.
18:44TEttinger(identity amalloy)
18:44lazybotamalloy has karma 239.
18:45javjarferTEttinger, ei! love that, there is a long way ahead
18:55justin_smith(identity justin_smith)
18:55lazybotjustin_smith has karma 217.
19:11justin_smith,(->> (all-ns) (mapcat (comp vals ns-interns)) (filter (comp :test meta)))
19:11clojurebot()
19:11justin_smithstill proud of that one-liner
19:12justin_smith(it will list all defined clojure.test tests)
19:15TEttinger&(let[a #(apply str(flatten %))r repeatedly R repeat p #(partition %(a(R %2 %3)))N rand-nth n #(a(N(concat(R %"")(mapcat p[1 1 2 2][13 5 8 2]%&))))v #(n 0"aioe""u""aiioieoa")w(fn[](let[s[(n 0"JYZKVGSMNPRH"""(a(for[V"EA"C"zkbhhmlrd"](str V C)))"")(r(N[1 1 2])#(do[(v)(n 0"zkssgnmpbhhll""dt""shth")]))]](a s)))Y(r 500 w)](a[(mapv(fn[u d](str u" "(N["begat""sired"])" "d". Then "))Y(rest Y))(last Y)" begat Rich, Amen."]))
19:15lazybot⇒ "Mop sired Yib. Then Yib sired Elab. Then Elab begat Posok. Then Posok begat Gais. Then Gais begat Alieth. Then Alieth begat Yab. Then Yab begat Nam. Then Nam sired Zietah. Then Zietah begat Hail. Then Hail sired Sem. Then Sem begat Rioh. Then Rioh begat Koag. Then K... https://www.refheap.com/98743
19:15justin_smithhaha, nice
19:17TEttingerhttp://ideone.com/zwnFAL is less obfuscated, it's used to generate english-like planet names for a friend's scifi game
19:17TEttingerit's meant to generate 10K unique names, but it runs out of memory on ideone if you try 10K there
19:17TEttingerit works fine locally
19:17TEttingerlazyseqs are awesome here
19:18TEttingerI generate an infinite list and call distinct on it, then take 10000
19:28celwellWhat's the best way to deref an atom from another namespace? @(resolve 'purple.dispatch/zq)
19:28gfredericks@purple.dispatch/zq
19:28celwell@dispatch/zq doesn't work
19:29celwellah hmm thanks
19:29gfrederickshow does it fail?
19:29celwellill try the one you said
19:29clojurebotNo entiendo
19:29gfredericksyou can (:require [purple.dispatch :as dispatch])
19:29gfredericksif you want to use dispatch/zq
19:30celwellWell i am requiring dispatch, but @dispatch/zq failed. I'll try again
19:31justin_smithcelwell: what is the error you get
19:32celwelljava.lang.ClassCastException
19:32celwellclojure.lang.PersistentArrayMap cannot be cast to java.util.concurrent.Future
19:32celwellmaybe it's unrelated
19:32justin_smithOK, you tried to deref a map
19:32justin_smith,@{}
19:32clojurebot#error{:cause "clojure.lang.PersistentArrayMap cannot be cast to java.util.concurrent.Future", :via [{:type java.lang.ClassCastException, :message "clojure.lang.PersistentArrayMap cannot be cast to java.util.concurrent.Future", :at [clojure.core$deref_future invoke "core.clj" 2184]}], :trace [[clojure.core$deref_future invoke "core.clj" 2184] [clojure.core$deref invoke "core.clj" 2205] [sandbox$ev...
19:32justin_smithsee, same error
19:32celwelloh, yeah i forgot i changed the strucutre of that atom, let me try again
19:36celwellok, nvm...
19:38Lewixhello
19:39justin_smithgreetings and salutations
19:41arrdem$GREETING
19:42justin_smithTEttinger: "It Came from Planet Cough"
19:44justin_smithTEttinger: I shared your planet generator with a friend, who discovered some dictionary words
19:44justin_smithalso, "Chestoid must be where xenomorphs are from"
19:46TEttingerhaha
19:47justin_smith"it's the fourth planet it the Chan system, best known for the troll-like hominids and their obsession with memes"
19:47TEttingernice
19:47justin_smithanother good one from that list: "Tom"
19:47clojurebotTitim gan éirí ort.
19:48TEttingerI managed to parse out most if not all the swears
19:48justin_smithnice
19:48TEttingerAbbo keeps getting through, which is a slur for aboriginal people, typically australian
19:49justin_smithTed is another one
19:49TEttingerI'm sure there's more ethnic slurs that it generates, clojure is such a racist generator
19:49justin_smith"the journey to planet Suck"
19:50justin_smithoh wow, "Foo" is in there
19:53gfredericksPSA: you can generate things from a regex with https://github.com/gfredericks/test.chuck#string-from-regex
19:54arrdemgfredericks: nice!
19:55TEttingerwow https://github.com/gfredericks/test.chuck/blob/master/resources/com/gfredericks/test/chuck/regex.bnf
19:55TEttinger(inc gfredericks)
19:55lazybot⇒ 124
19:56SeyleriusTEttinger: That a clojure karma system?
19:56arrdemSeylerius: yep
19:56TEttingeryep
19:56SeyleriusShiny.
19:56arrdem(inc gfredericks)
19:56lazybot⇒ 125
19:56arrdem(identity arrdem)
19:56lazybotarrdem has karma 40.
19:56arrdemI need to lurk more
19:56gfredericksTEttinger: I learned a lot of disgusting things about jvm regexes while building that
19:56TEttinger(identity tekacs)
19:56lazybottekacs has karma 0.
19:57TEttinger(identity TEttinger)
19:57lazybotTEttinger has karma 44.
19:57TEttingergfredericks, I remember
19:57TEttingerstuff like the && grouping within [] right?
19:57gfredericksyeah that's the second worst
19:58TEttingerthere's WORSE?
19:58arrdemthere's always something worse
19:59gfredericksthe worst thing I know of is that you can put a \Q\E virtually *anywhere* in a regex and it's a noop, even in the middle of things that should never be broken up
20:00gfrederickse.g.
20:00gfredericks&(re-matches #"\p{Alpha}+" "hello")
20:00lazybot⇒ "hello"
20:00gfredericks&(re-matches #"\p{Al\Q\Epha}+" "hello")
20:00lazybot⇒ "hello"
20:01TEttingeraaaaaagh
20:01hyPiRionomg what
20:02arrdemew
20:02justin_smithgfredericks: oh my god that's an atrocity
20:02justin_smithit's like, war crime level stuff
20:03gfredericksthere are some things you never want to have to tell your kids about
20:04TEttingerit's like \p{Ol} \p{Ot}
20:05justin_smithgfredericks: it seems the only rule is that one \Q\E can't be in the middle of another one
20:06justin_smith,(re-matches #"\p{Al\Q\Q\E\Epha}+" "hello")
20:06clojurebot#<SecurityException java.lang.SecurityException: denied>
20:06justin_smith,(re-matches #"\p{Al\Q\E\Q\E\Q\Epha}+" "hello")
20:06clojurebot"hello"
20:07hyPiRion,(re-matches #"\p{\QAlEpha\E}+" "hello")
20:07clojurebot#<NoClassDefFoundError java.lang.NoClassDefFoundError: Could not initialize class java.util.regex.PatternSyntaxException>
20:07hyPiRion,(re-matches #"\p{\QAlpha\E}+" "hello")
20:07clojurebot"hello"
20:07hyPiRionoh okay then
20:08gfredericksjustin_smith: right
20:08hyPiRiongfredericks: but \Q can be inside a \Q, right?
20:08gfredericksoh I didn't expect that one o_O
20:08gfredericksyes it can
20:09gfredericks,(re-matches #"\p\{\A\l\p\h\a}+" "hello")
20:09clojurebot#<NoClassDefFoundError java.lang.NoClassDefFoundError: Could not initialize class java.util.regex.PatternSyntaxException>
20:09gfredericks&(re-matches #"\p\{\A\l\p\h\a}+" "hello")
20:09lazybotjava.util.regex.PatternSyntaxException: Unknown character property name {\} near index 2
20:09gfredericks&(re-matches #"\p{\A\l\p\h\a}+" "hello")
20:09lazybotjava.util.regex.PatternSyntaxException: Unknown character property name {\A\l\p\h\a} near index 13
20:09gfredericksthat should be equivalent afaik
20:09gfrederickser
20:09gfredericksmaybe I'm confused
20:09hyPiRionwell apparently not
20:09hyPiRionalthough I would agree with you
20:09gfredericksgotta put a baby to bed
20:17underplankHey all. Im using clj-http to build some unit tests. I have a route that Im wanting to make sure it returns a 404, but it seems like clj-http throws an exception. Is there a way I can get clj-http to not throw that exception?
20:18underplankahh found it. {:throw-exception false}
20:18underplankshould probably read the documentation
20:24jeremyheilerunderplank: sometimes i wish that was the default
20:25underplankyeah… coming from python with the requests library where that is the default it is rather nice. I dont really like being forced into throwing an exception. But I guess you could argue that it forces good behaviour.
20:26jeremyheilerunderplank: good behavior? eh. apis do waht apis do. hard to manage servers outside of your control
20:27underplankyeah…. thats very true. Its only good behaviour if you control both ends of the request. I get the feeling its a javaesque thing that managed to work its way into clj-http
20:27underplank*shrugs* at least there is a way out of it.
20:27underplankand apart from the the clj-http library is pretty damn good.
20:28jeremyheileryeah, clj-http is a great lib
20:29gfrederickshyPiRion: it's because \Q...\E actually leaves alpha-ascii characters unchanged
20:29gfredericksit backslashes everything else
20:30arrdemwhy the hell...
20:30hyPiRiongfredericks: oh, so it's like a preprocessing step
20:30gfrederickshyPiRion: exactly
20:30gfredericksarrdem: because [a-zA-Z] normally have special meanings with a backslash but normal meanings without
20:30gfrederickswith the exception of \p{...} that we were just playing with
20:30gfredericksI expect that's the only place where [a-zA-Z] have a special meaning and you can pull off that trick
20:31gfredericks&(re-matches #"\p{Al\Qph\Ea}+" "hello")
20:31lazybot⇒ "hello"
20:31gfrederickshyPiRion: it *is* a preprocessing step
20:32gfredericksit's right here in fact: https://github.com/openjdk-mirror/jdk/blob/2ea10c722507cde99026faa56068e2295bb93f11/src/share/classes/java/util/regex/Pattern.java#L1567-1619
21:11ben_vulpeswhat does ^Foo mean in the context of a (def ... ) form?
21:11ben_vulpesin particular, looking at https://github.com/michaelklishin/pantomime/blob/master/src/clojure/pantomime/mime.clj#L17 - is that some sort of type annotation perhaps?
21:12gfredericksyes, a type hint
21:12ben_vulpesthanks gfredericks.
21:12justin_smith,(meta (fn ^String [] "hi"))
21:13clojurebotnil
21:13justin_smithhrm...
21:13gfredericksben_vulpes: it means e.g. that the call on line 33 can be figured out by the compiler
21:13gfredericksand doesn't have to use runtime reflection
21:13justin_smithgfredericks: it seems odd that the compiler couldn't infer that (Tika.) returns a Tika
21:14gfredericksjustin_smith: it doesn't try very hard
21:14justin_smithyeah, I guess not
21:14justin_smithone k short of delicious
21:14gfredericksI assume the only inference it does is local
21:16gfredericks&(def justin_smith (Integer. 24))
21:16lazybotjava.lang.SecurityException: You tripped the alarm! def is bad!
21:16gfredericksaw go away lazybot
21:26ben_vulpeshttps://github.com/michaelklishin/pantomime/blob/master/src/clojure/pantomime/mime.clj#L29 << regarding this protocol implementation, what sense does it make to extend the protocol for String, File, URL etc when in all of the implementations, everything is just run through a Tika (.detect Tika. *input*) call?
21:26ben_vulpesi ask out of ignorance, not arrogance :)
21:28gfredericksben_vulpes: as opposed to just writing one function with that same implementation?
21:29ben_vulpesright.
21:29ben_vulpesthat's the (naive, perhaps stupid) thing that i'd do.
21:29gfredericksit's the type hints again
21:29gfredericksat the jvm level I assume there are at least four different methods called "detect"
21:29gfrederickseach with different type signatures
21:29ben_vulpesoho
21:30gfredericksand to avoid reflection you have to tell clojure (via type hints) which of those four you want to call
21:30ben_vulpesi think where i fail to grok is how the clojure type hint is conveyed to the jvm for the correct detect call
21:31ben_vulpesbut -- outside of my scope atm. thanks, gfredericks!
21:31gfredericksnp
21:54justin_smithben_vulpes: I think it's more a question of if the clojure compiler can't tell when you compiler your code which class' method is to be called, it generates byte code that figures out the class, finds the method, and calls it
21:55justin_smithben_vulpes: and that series of steps is why typehints make things faster
21:55justin_smiths/compiler/compile
22:35ben_vulpesmakes sense, justin
22:35ben_vulpesjustin_smith:
23:50Lewixcan someone explain to me partial?
23:51justin_smithLewix: it takes a function and N args, and returns a new function taking N fewer args
23:51justin_smith,(def +2 (partial + 2))
23:51clojurebot#error{:cause "First argument to def must be a Symbol", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.RuntimeException: First argument to def must be a Symbol, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6732]} {:type java.lang.RuntimeException, :message "First argument to def must be a Symbol", :at [clojure.lang.Util runtimeEx...
23:51justin_smithoops
23:52justin_smith,(def plus2 (partial + 2))
23:52clojurebot#'sandbox/plus2
23:52justin_smith,(plus2 2)
23:52clojurebot4
23:52justin_smith,(plus2 2 2)
23:52clojurebot6
23:53Lewixjustin_smith: i fail to understand the purpose
23:53Lewixjustin_smith: you could just create a function
23:53justin_smithLewix: that's what partial is for
23:53justin_smithit creates functions
23:54Lewix.(defn plus2 [n] (+ 2 n))
23:54justin_smithLewix: that would break for my second example
23:54Lewixi see. thns
23:54justin_smiththe idea is it is simple to use, and will be exactly like the original function with some arguments pre-provided
23:55justin_smithsee also comp
23:55justin_smithwhich also just creates a function, which you could use defn or fn to create
23:55Lewixjustin_smith: thanks
23:55justin_smithbut comp can be clearer sometimes
23:55justin_smithn
23:55LewixI gotta fo
23:55justin_smitherr, I mean np
23:55Lewixgo*