2015-08-27
| 00:47 | sojacques | Hi guys, I have a little question, is there anything similar to http://tour.golang.org for clojure? A friend of mine is looking for a brief introduction to the language, and I can't really find one that allows you to try as you read |
| 00:47 | jeaye | sojacques: The koans allow you to learn interactively. |
| 00:48 | jeaye | But there's not much ceremony around it all, so you need to be a bit quick on your feet. |
| 00:48 | sojacques | jeaye: is there any way to do the koans in a browser? |
| 00:49 | jeaye | Of course. |
| 00:49 | sojacques | oh, there are clojurescript koans for that. Fantastic |
| 00:50 | jeaye | Right, that's the one. _Basically_ the same, as far as beginners are concerned. |
| 00:51 | sojacques | Thanks a lot, I bookmarked this, it's going to be very convenient to explain my friend what I'm doing all day |
| 00:51 | sojacques | friends* |
| 00:58 | seangrove | For a function that expects keyword args, is there a way to just pass a plain map? |
| 01:00 | seangrove | ugh, (apply concat {}) |
| 01:06 | mange | seangrove: I've seen people use a function like this to do it, (defn mapply [f kwargs] (apply f (apply concat kwargs))) |
| 01:54 | amalloy | ~mapply |
| 01:54 | clojurebot | You have to do something like (defn mapply [f & args] (apply f (apply concat (butlast args) (last args)))), which just goes to show why unrolled keyword args are a bad idea |
| 01:55 | amalloy | seangrove: ^ |
| 01:57 | amalloy | (inc gfredericks) ; for that, iirc |
| 01:57 | lazybot | ⇒ 147 |
| 02:28 | sveri | ambrosebs: ping |
| 02:58 | crocket | How do I convert a data structure into a textual representation readable by clojure? |
| 02:59 | neoncontrails | Define "readable"? |
| 03:00 | neoncontrails | And maybe "data structure" too. What type? |
| 03:07 | dstockton | ,(pr-str {:a 1 :b 2}) |
| 03:07 | clojurebot | "{:a 1, :b 2}" |
| 03:08 | dstockton | ,(clojure.edn/read "{:a 1, :b 2}") |
| 03:08 | clojurebot | #error {\n :cause "clojure.edn"\n :via\n [{:type java.lang.ClassNotFoundException\n :message "clojure.edn"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run "URLClassLoader.java" 366]\n [java.net.URLClassLoader$1 run "URLClassLoader.java" 355]\n [java.security.AccessController doPrivileged "AccessController.java" -2]\n [java.net.URL... |
| 03:17 | neoncontrails | How many of you would use Clojure in an interview setting? Strictly curious |
| 03:18 | oddcully | haha |
| 03:24 | jeaye | What a ridiculous interviewer that must've been. |
| 03:44 | crocket | dstockton, thanks |
| 03:44 | crocket | neoncontrails, ^^ |
| 03:44 | crocket | ,(doc pr-str) |
| 03:44 | clojurebot | "([& xs]); pr to a string, returning it" |
| 03:44 | crocket | (pr-str '(3 4 [:a :b])) |
| 03:44 | crocket | ,(pr-str '(3 4 [:a :b])) |
| 03:44 | clojurebot | "(3 4 [:a :b])" |
| 04:02 | Leonidas | neoncontrails: what's wrong with HashMaps? |
| 04:02 | Leonidas | I feel it's like having an issue with the colour blue. |
| 04:03 | neoncontrails | Nothing. It's strictly not implied by use of me |
| 04:03 | neoncontrails | *map |
| 04:04 | Leonidas | Must've been hilarious, did you get the job? :) |
| 04:04 | neoncontrails | That's precisely what I thought too. I had fun, but I think if an interviewer wants to ding me for using map, we probably won't get along well anyway |
| 04:05 | neoncontrails | It was a practice interview actually, so purely fun and games. But the guy was older than me, and more experienced |
| 04:07 | wasamasa | age doesn't prevent you from sillies |
| 04:07 | neoncontrails | I did get briefly excited nonetheless, like, "Ooh, a chance to talk about how cool map() functions are!" |
| 04:10 | neoncontrails | It did make me wonder though. How common *is* knowledge of map/reduce/filter? |
| 04:11 | Empperi | depends on who you ask |
| 04:11 | Empperi | but if you look at the broad majority of the programmers then not very |
| 04:11 | neoncontrails | It's standard at my university; one can't pass SICP without becoming an expert on functional style |
| 04:11 | Empperi | I'd say 10% of the programmers doing programming for living know those |
| 04:11 | Empperi | or so |
| 04:11 | neoncontrails | !!! |
| 04:11 | Empperi | the skills of an average programmer out there is not exactly dashing |
| 04:11 | neoncontrails | really only 10%?! |
| 04:12 | Empperi | it's just a guess but yeah |
| 04:12 | Empperi | I've done my fair share of code auditing, training etc so I think I have a hunch |
| 04:12 | neoncontrails | Well, that can be forgiven, maybe (I don't think I'm a terribly good programmer) |
| 04:13 | Empperi | and I've interviewed propably hundreds of people for programming jobs |
| 04:13 | neoncontrails | I'm just surprised that it's not common parlance by now... even Java has map now, I heard? |
| 04:13 | Empperi | these days most of the guys I interview do know those but that's because I'm at the last interview and rest have been filtered out already ( |
| 04:14 | Empperi | yeah java has map, filter, reduce, flatmap and so forth |
| 04:14 | Empperi | in java 8 |
| 04:14 | Empperi | the problem is, most of the guys writing java out there don't use java 8 yet |
| 04:14 | Empperi | they can't or are too afraid to upgrade since their code is so brittle |
| 04:15 | Empperi | or their customers are too afraid to allow that |
| 04:15 | neoncontrails | ,(filter (fn [interviewer] (knows? interviewer 'filter)) (map interview interviewer)) |
| 04:15 | clojurebot | #error {\n :cause "Unable to resolve symbol: knows? in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: knows? in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: knows? in t... |
| 04:15 | Empperi | and even if they had java 8 they'd have to know how to use those |
| 04:16 | Empperi | it is wildly different to use java Streams API and build on top of that instead of good ol' mutable variable mess |
| 04:16 | neoncontrails | I have only heard mediocre experiences with it |
| 04:16 | Empperi | it's quite nice |
| 04:16 | Empperi | certainly a huge improvement to Java |
| 04:17 | neoncontrails | For me, the transition from Scheme -> Java 7 was distressing because it lacked both my bread and butter |
| 04:17 | Empperi | anyway, there are people out there writing client-server architecture where their server receives commands in a way that their clients write commands to database "command" table and the server polls that |
| 04:18 | Empperi | and clients when they've written that command start polling that same table and wait that specific line is deleted |
| 04:18 | Empperi | and then both read and write happily to the exact same database |
| 04:18 | Empperi | yes, this is from a real software I audited |
| 04:18 | neoncontrails | I came to appreciate that map/reduce aren't just making my life easier, that they really shape the way I organize my thinking |
| 04:19 | Empperi | the reason they implemented it like that was that they didn't know how to write concurrent software or how to use sockets and they didn't bother to google for ready implementations |
| 04:19 | neoncontrails | Ha, yes. I haven't worked in industry yet where these things start to matter |
| 04:20 | Empperi | that kind of people really do get paid for doing programming work and they can go on doing their work like that for decades |
| 04:20 | neoncontrails | But I hear that when I do have to work with databases, it will be an easier transition from my current way of coding |
| 04:20 | oddcully | Empperi: ppl get creative to get over fences |
| 04:20 | Empperi | indeed |
| 04:20 | Empperi | they had a slight performance and maintanibility problem and bought consultancy from us |
| 04:20 | Empperi | I wonder why they had these problems... |
| 04:21 | neoncontrails | Heh |
| 04:21 | oddcully | and slight is needs alot of quoting fingers, right? |
| 04:21 | Empperi | yup |
| 04:21 | Empperi | there were hundreds of the clients talking to that "server" |
| 04:21 | oddcully | s/is/ |
| 04:21 | Empperi | all accessing the very same database |
| 04:21 | Empperi | writing stuff there |
| 04:21 | Empperi | they also had strange bugs |
| 04:22 | Empperi | turns out they were using MySQL and it's myisam database |
| 04:22 | oddcully | haha |
| 04:22 | neoncontrails | This is kind of a loaded question then, but supposing all of these things are true: |
| 04:22 | Empperi | myisam does not have proper transactions it works in auto-commit mode |
| 04:22 | neoncontrails | That most programmers aren't terribly familiar with functional programming methods |
| 04:23 | Empperi | yes, correct |
| 04:23 | Empperi | functional programming has been gaining in popularity in the last 5 years |
| 04:23 | neoncontrails | That most employers aren't familiar enough with them to really assess your whiteboard solutions written in a functional style... |
| 04:23 | neoncontrails | What then? |
| 04:23 | Empperi | before that it was rare to find anyone who actually knew that stuff |
| 04:23 | Empperi | neoncontrails: then it means you should look elsewhere :) |
| 04:24 | Empperi | you don't want to go to that company where the interviewer doesn't know what map/filter/reduce does |
| 04:24 | Empperi | you'd die in brain hemorrage there |
| 04:25 | neoncontrails | Hahaha. I completely agree, but then I wonder, are the companies that consider FP an asset advertising themselves as such? |
| 04:25 | oddcully | check for the reaction: either they feel dumb and will not hire you or they will have a revelation |
| 04:25 | Empperi | some are, others arent |
| 04:25 | neoncontrails | Where would I find the companies that my problem solving approach fits in, in other words |
| 04:27 | Empperi | hard to say, depends on where you live |
| 04:28 | neoncontrails | California |
| 04:28 | oddcully | an indication also can be companies where the job description does not focus on e.g. one programming languages. like "you know scala, python, ocaml and/or racket"? |
| 04:28 | neoncontrails | with roots in both bay area and Southern CA |
| 04:28 | oddcully | if a shop is already polyglot it will be alot easier to impress them with new stuff |
| 04:29 | neoncontrails | It seems (limited experience) like the language preferences are most often articulated by recruiters |
| 04:30 | neoncontrails | That the same job might have different criteria depending on whether it's posted by HR or a headhunter |
| 04:31 | neoncontrails | When I see a language preference and it's through a headhunter, I usually apply anyway, maybe with a note that I'm happy to learn Ruby or whatever |
| 04:32 | neoncontrails | But I dunno, do you think that it's a red flag when a preference is stated at all? |
| 04:35 | Empperi | my company (in Finland) recruits guys who do not know the languages we use |
| 04:35 | Empperi | if he/she is good then he/she will learn our tech stacks |
| 04:38 | neoncontrails | That sounds like an extremely good attitude to have |
| 04:38 | neoncontrails | Crossing fingers that enough companies in CA agree with that :) |
| 04:43 | Empperi | there aren't that many people who know Clojure for example in Finland |
| 04:43 | Empperi | we are currently the largest company in Finland doing Clojure seriously |
| 04:43 | Empperi | and even we have only like 10% of our projects using Clojure |
| 04:44 | Empperi | so if we wan't new guys into our Clojure projects we usually need to hire someone who doesn't know it yet |
| 04:44 | Empperi | but who wants to learn |
| 04:45 | im_learning | i want to learn |
| 04:46 | Empperi | so your nick says lol |
| 04:47 | im_learning | yea |
| 04:48 | im_learning | I just wanted to get in touch with one fucntional programming language. confused which to choose, haskell or clojure? |
| 04:49 | gilliard | Why not both? |
| 04:49 | Empperi | yeah |
| 04:49 | Empperi | they are both functional but in many ways very VERY different |
| 04:49 | Empperi | you'd be better off learning both |
| 04:49 | gilliard | The differences will teach you a lot about languages. |
| 04:50 | Empperi | the same way one becomes a better Java programmer by learning Clojure one also gets a better Clojure programmer by learning Haskell |
| 04:50 | Empperi | and vice versa |
| 04:50 | im_learning | nice point. |
| 04:50 | Empperi | the further apart from your comfort zone you go when learning a new language the more you'll learn |
| 04:52 | im_learning | I always want to get into serious stuff like this. But the problem is the day-time job? How you guys manage your time to learn these? |
| 04:52 | Empperi | well, right now I don't lol |
| 04:52 | lambda-smith | im_learning: sacrifice the sleep time |
| 04:52 | Empperi | I have a 11 month old daughter who takes all my free time |
| 04:52 | wasamasa | free time is overrated |
| 04:52 | neoncontrails | That question was on my mind, too, a few weeks ago. I decided to go with Clojure first |
| 04:53 | Empperi | but fortunately my employer is very flexible in many ways |
| 04:53 | Empperi | I can learn stuff at work too |
| 04:53 | Empperi | but yeah, do programming at your free time |
| 04:53 | oddcully | im_learning: sell your tv |
| 04:54 | Empperi | pick up a project you'd like to do and which is simple enough you might actually finish it too |
| 04:54 | neoncontrails | A criticism of Clojure, that it's just a thin wrapper around Java, is also somewhat of a benefit in terms of interoperability and ability to use Java's fantastic API features |
| 04:54 | Empperi | and write it in language x |
| 04:54 | Empperi | something like a blogging platform |
| 04:55 | im_learning | how about solving algorithamic questions in language x? |
| 04:55 | Empperi | good way to learn too |
| 04:55 | Empperi | but might not introduce you to the way of thinking in that language |
| 04:56 | gilliard | Yeah if I'm picking up a brand new language I'll usually pop over to projecteuler or similar. Especially if I don't get big chunks of time all at once. |
| 04:56 | neoncontrails | Well all of the languages will give you a solution, some of the languages will give you a great solution |
| 04:56 | Empperi | because well known algorithms are well known anyway |
| 04:56 | Empperi | you'll mostly learn syntax that way |
| 04:56 | Empperi | and that algorithm |
| 04:57 | im_learning | so solving problem will help you learn syntax, doing project will help you learn the insight of that language. |
| 04:58 | im_learning | empperi, what kind of projects you do with clojure? |
| 04:58 | neoncontrails | doing projects helps you define what the problems are, I think |
| 04:58 | neoncontrails | which is a bit easier said than done |
| 04:58 | Empperi | im_learning: mostly stuff with web ui |
| 04:59 | Empperi | but there's a ton of stuff going under the hood |
| 04:59 | Empperi | enterprise stuff and so forth |
| 04:59 | neoncontrails | it's one thing to be handed a little problem, say, "sum of the first 3,000,000 prime numbers" |
| 04:59 | Empperi | right now we are building this system with micro-services architecture with elastic search and very complex search queries and terabytes of input data |
| 05:00 | neoncontrails | which might be a bit tricky, but it's a totally different difficulty than figuring out the problems that you need to solve to get your app to run on an android phone |
| 05:19 | Kneiva | im_learning: I've used my commute time to learn stuff. Like solving these problems: https://www.4clojure.com/ When I got to the harder problems and had to really think about them I could do the thinking while helping my child to fall asleep. |
| 06:10 | ToxicFrog | Huh. |
| 06:10 | ToxicFrog | When I try to lein run, it dies trying to download the leiningen jar from S3. |
| 06:11 | ToxicFrog | When I try to download it manually, I get an XML file saying "access denied". |
| 06:11 | ToxicFrog | Is Lein hosed for anyone else? |
| 06:12 | Empperi | windows? |
| 06:17 | ToxicFrog | Empperi: linux. |
| 06:32 | gilliard | I just tried it & "works for me" |
| 06:44 | vijaykiran | ToxicFrog: proxy ? |
| 06:44 | ToxicFrog | vijaykiran: nope. And it passes the certificate checks fine, it just doesn't subsequently serve me the jar. |
| 06:50 | ToxicFrog | Is it possible that 2.3.1 is just too old? |
| 06:51 | ToxicFrog | Yeah, that's the problem. |
| 06:51 | ToxicFrog | Apparently S3 serves 403 rather than 404 if you try to follow a dead link! |
| 06:51 | gilliard | nice |
| 06:52 | ToxicFrog | And 'lein upgrade' requires the jar to function, so if you wait too long between upgrades your only option is to download the latest script from github by hand. |
| 06:53 | gilliard | How old is 2.3.1? |
| 06:54 | ToxicFrog | Two years, apparently. I could have sworn I did a lein upgrade more recently than that. |
| 07:21 | kungi | Is there no alter-var-root in clojurescript? |
| 07:25 | Empperi | not that long ago there was no vars as you understand them in ClojureScript |
| 07:25 | Empperi | and still they aren't equivalent to what we have in Clojure |
| 07:27 | kungi | Empperi: Ok ... Thank you. Then I have to do it properly :-) |
| 07:35 | spradnyesh | java interop question: i have:- "class A { public enum B {P, Q, R}}" how do i access A.B.P from clojure? i've done [import A :as A], but accessing A.B.P gives "unable to find static field B.P" |
| 07:37 | Empperi | if you have it like that then the enum declaration is instance dependent |
| 07:37 | Empperi | in java terms, this wouldn't work: A.B.P |
| 07:38 | Empperi | this would: new A().B.P |
| 07:38 | Empperi | so same applies to clojure |
| 07:38 | spradnyesh | Empperi: ohh yes, sorry missed it |
| 07:38 | spradnyesh | thanks :) |
| 07:38 | Empperi | np |
| 07:42 | spradnyesh | Empperi: http://stackoverflow.com/a/663849/4329629 (nested enums are implicitly static). ;; in my case i'm using a external library w/ no 0-arity constructor for A() |
| 07:42 | spradnyesh | also, i see a "A.B.P" reference in the java source code (of the library) |
| 07:43 | spradnyesh | but i'm not able to figure out how that translates to clojure world |
| 07:52 | spradnyesh | found: A$B/P |
| 07:53 | spradnyesh | search for "nested" in http://blog.jayfields.com/2011/12/clojure-java-interop.html |
| 07:54 | spradnyesh | actually, for enum, i had to use (com.blah.blah.A$B/P) w/ the function call |
| 08:02 | Empperi | ah true |
| 08:02 | Empperi | instance specific enums wouldn't make sense anyway |
| 08:02 | Empperi | now that I think of it |
| 08:03 | Empperi | I just always write static enum when doing java .) |
| 08:19 | gilliard | Empperi: I don't have a java dev env handy to try it, but you can put fields in enum values can't you? So an instance-specific enum could be used like that? Although I'm not sure what use it would be IRL. |
| 09:01 | justin_smith | spradnyesh: [import A :as A] -- :as isn't valid on imports |
| 09:01 | justin_smith | I think an enum in a class would be an inner class, so you want A$B/P |
| 09:02 | justin_smith | where P is a static member of B, which is an inner class of A |
| 09:03 | spradnyesh | justin_smith: sorry, typo |
| 09:04 | spradnyesh | justin_smith: yes, that's what i found (see above) A$B/P, but doesn't work w/o fully-qualified-name |
| 09:04 | justin_smith | oh, sorry, I didn't see that |
| 09:06 | justin_smith | spacepluk: inside the ns form you want (:import x.yz.A) which allows A$B/P instead of x.yz.A$B/P |
| 09:06 | justin_smith | but that's about as much shortening as you can get in clojure I think |
| 09:06 | justin_smith | sorry, misdirect above |
| 09:06 | spacepluk | np :) |
| 09:13 | justin_smith | actually, I think you can (import A$B) and fix his problem ... seems he left though |
| 09:24 | pseudonymous | Is there an easy way to build a lazy sequence of function calls which I can evaluate at some later point ? (I'm trying to create a form for short-circuit evaluation of incoming requests) |
| 09:27 | snowell | pseudonymous: You could quote the calls (turning them into lists) and then (eval) them at said later point |
| 09:27 | snowell | For all I know, this is a terrible idea/practice, so use with caution ;) |
| 09:28 | pseudonymous | snowell: that's also the only idea I have right now. But it just seems as if there's something with these lazy sequences that may work .. ? |
| 09:30 | justin_smith | pseudonymous: laziness might be less controlled than you need - it isn't recommended to mix laziness and side effects - what about using delay and @ to force the delay? |
| 09:31 | justin_smith | ,(def d (delay (do (prinln "forced") :d))) |
| 09:31 | clojurebot | #error {\n :cause "Unable to resolve symbol: prinln in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: prinln in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: prinln in t... |
| 09:31 | justin_smith | ,(def d (delay (do (println "forced") :d))) |
| 09:31 | clojurebot | #'sandbox/d |
| 09:31 | justin_smith | ,d |
| 09:31 | clojurebot | #object[clojure.lang.Delay 0x2304a617 {:status :pending, :val nil}] |
| 09:31 | justin_smith | ,@d |
| 09:31 | clojurebot | forced\n:d |
| 09:31 | justin_smith | ,@d |
| 09:31 | clojurebot | :d |
| 09:31 | justin_smith | you have very precise control with delays |
| 09:33 | pseudonymous | justin_smith: I basically only intend to use it as a way of getting OR-like functionality - at the first error check which returns non-nil, I want to abort and return the formatted error to the user (thereby not evaluating the other checks) - there's no alteration of program state per se |
| 09:33 | pseudonymous | (But I guess I could wrap each check in a delay clause, it just seems a bit verbose) |
| 09:37 | snowell | pseudonymous: Could you use core.async and have it wait via (alts!) for a message to come over a specific channel? |
| 09:37 | snowell | Or go through the error checks with (some->) |
| 10:01 | gfredericks | amalloy_: I suspect ~mapply came from TimMc |
| 10:01 | gfredericks | ~TimMc is the mapply prophet |
| 10:01 | clojurebot | You don't have to tell me twice. |
| 10:50 | TimMc | can confirm |
| 11:07 | justin_smith | pseudonymous: sounds like you just want every? then |
| 11:08 | justin_smith | or maybe every-pred actually |
| 11:11 | akabander | So... I need to build a distributed app that will communicate with other instances over a network message bus. Must be a fairly typical pattern. Any suggestions for where to start investigations? |
| 11:12 | noncom | akabander: the aleph networking library? |
| 11:12 | noncom | in clojure we have stack traces lost in macros... why is this? will there ever be a better handling of this? is it possible at all? |
| 11:13 | justin_smith | ,(def even-pos (every-pred #(do (print "even ") (even? %)) #(do (print "pos ") (pos? %)))) |
| 11:13 | clojurebot | #'sandbox/even-pos |
| 11:13 | justin_smith | ,(even-pos -1) |
| 11:13 | clojurebot | even false |
| 11:13 | justin_smith | ,(even-pos 2) |
| 11:13 | clojurebot | even pos true |
| 11:13 | Bronsa | noncom: stack traces lost in macros? |
| 11:13 | justin_smith | pseudonymous: that's "lazy" in the way you want |
| 11:13 | akabander | noncom: Thanks, checking it out |
| 11:14 | justin_smith | akabander: I've had decent luck with kafka after a pretty steep ramping up |
| 11:14 | noncom | Bronsa: if i generate a fn in a macros then if there is an exception in this fn, the exception just points at the macros.. no way to get inside the generated fn |
| 11:15 | Bronsa | noncom: do you have an example? I'm not sure I understand |
| 11:17 | noncom | Bronsa: umm, not at the moment. let me then first factor a clear example and then show you. maybe not today. this problem bothers me for a long time but i never fixed it. i will work to resolve this confusion by frist focusing on creating a simple reproduceable example |
| 11:19 | justin_smith | noncom: one thing that makes stack traces that contain anonymous functions much easier to read is to "name" your anonymous functions (fn some-descriptive-name-here [] ...) - the name will be part of the generated class name for that anon-fn |
| 11:19 | noncom | the examples in my original program are big and depend on many things so i cannot just present them, it will be hard to follow |
| 11:19 | noncom | justin_smith: yes! a good advice. i tend to give names to them when i come acros the ones i did not yet name :) |
| 11:21 | seangrove | Bronsa: Is it a monumental task to bring t.a.js up to date with cljs master? |
| 11:23 | ps | Hello all, I’m trying to run some tests with ‘lein cljsbuild test’ using phantomjs. When all tests pass, everything is ok, but if a test fail, phantomjs returns a non zero code, while the invocation of the parent ‘lein cljsbuild test’ returns 0 (no error). I assume lot of people do cljs tests in phantomjs and may be someone knows about a workaround or something I miss |
| 11:25 | Bronsa | seangrove: sorry I was afk yesterday -- the issue you were having was caused by tajs not supporting new cljs version yeah |
| 11:25 | Bronsa | seangrove: not the smallest of tasks I'm afraid |
| 11:27 | akabander | noncom: I may go with jeromq |
| 11:27 | noncom | akabander: yeah, the mq family of libs seems cool, though i never used it |
| 11:28 | akabander | noncom: it definitely seems to be robustly featured. Brings a bit of complexity, but I think I'll need some of the flexibility down the road. |
| 11:29 | noncom | akabander: i've heard only good words in address of zeromq, and jeromq seems to be a java replica |
| 11:29 | noncom | so yeah, that's bright! :) |
| 11:32 | seangrove | Bronsa: No problem being afk, of course! |
| 11:32 | seangrove | Bronsa: And yes, I suspected that between Dec 2014 and Aug 2015 there might have been some big changes, heh |
| 11:36 | seangrove | Bronsa: Well, for what it's worth, it'd be great to have :) |
| 11:36 | Bronsa | seangrove: especially with cljs going bootstrapped |
| 11:41 | seangrove | Bronsa: especially great, or especially big changes? |
| 11:42 | seangrove | Bronsa: The bootstrapped/live-editing aspect is actually what I'm going for here https://www.dropbox.com/s/pvpgprg5kzq8sy4/dato_live_editing_2.mp4?dl=0 - I need t.a.js to properly persist the forms server-side |
| 11:44 | kavkaz | How come if I do (group-by identity (range 10)) I get a sequence which is not in order? I tried playing around with the force evaluation functions but I'm not too familiar with them |
| 11:44 | kavkaz | And to be honest don't quite know what's happening |
| 11:45 | justin_smith | kavkaz: group-by creates a hash-map, hash-maps are not ordered |
| 11:45 | seangrove | t.a.js to figure out the var/def deps graph for the location of the inserts (while minimizing movement to be git-friendly) and additions to the ns-form, and clj-fmt to keep the changes to a minimum, regardless of where the change is coming from (emacs, vim, browser) |
| 11:48 | Bronsa | seangrove: especially bug changes |
| 11:48 | Bronsa | big* |
| 11:53 | kavkaz | justin_smith: Ah okay. I found that it retains the order of the sequence usually, but not with range |
| 11:54 | kavkaz | Well, for any sequence I input by hand and feed it, it retains the order, but not range for example |
| 11:54 | justin_smith | kavkaz: normally = for small inputs |
| 11:55 | kavkaz | justin_smith: Ah, I see. |
| 11:55 | justin_smith | kavkaz: small hash-maps use a different implementation, one that will preserve order |
| 11:55 | kavkaz | Makes a lot of sense now |
| 11:55 | justin_smith | they automatically switch to a non-order-preserving version after hitting a certain size |
| 11:56 | kavkaz | Interesting, I'll find another way to do what I need to do. Thanks for your help justin_smith |
| 11:56 | sdegutis | Is defonce lazy? |
| 11:56 | justin_smith | kavkaz: maybe you want a sorted-map? |
| 11:56 | sdegutis | ,(do (defonce foo (prn :foo)) nil) |
| 11:57 | clojurebot | :foo\n |
| 11:57 | sdegutis | aww |
| 11:57 | justin_smith | ,(into (sorted-map) (group-by identity (range 100))) |
| 11:57 | clojurebot | {0 [0], 1 [1], 2 [2], 3 [3], 4 [4], ...} |
| 11:57 | sdegutis | time for memoize |
| 11:57 | kavkaz | justin_smith: hmm, I'll take a look at that. |
| 11:57 | justin_smith | sorted-map will sort by the keys |
| 11:58 | rasmusto | ,(sorted-set 1 2 3) |
| 11:58 | clojurebot | #{1 2 3} |
| 11:58 | rasmusto | ,(set [1 2 3]) |
| 11:58 | clojurebot | #{1 3 2} |
| 11:58 | rasmusto | that annoys me (the arity difference) |
| 11:58 | justin_smith | ,(hash-set 1 2 3) |
| 11:58 | clojurebot | #{1 3 2} |
| 11:58 | justin_smith | rasmusto: comparing the wrong function :) |
| 11:58 | rasmusto | ah, there's my answer |
| 12:23 | seangrove | Bronsa: I suppose the priority is pretty low for t.a.js? Perhaps you could make some tickets to guide bringing it up to date? I'd like to build some stuff on it for an upcoming talk in Nov. |
| 12:27 | rasmusto | is there a tool that will find all hash-sets in my code? (besides `grep set`) |
| 12:28 | Olajyd | Hi, Bronsa |
| 12:29 | Bronsa | seangrove: the big issue with tajs is that the cljs.core macros do a lot of non-trivial interop with cljs.analyzer and cljs.compiler, in tajs we need to replace that with a custom file that uses t.a internally rather than cljs.analyzer |
| 12:29 | seangrove | Ouch, that does sound tough |
| 12:29 | justin_smith | rasmusto: maybe jvisualvm could show you via profiling? or yourkit, I hear that's even better |
| 12:29 | Bronsa | seangrove: meaning that tajs is bound to support specific versions of cljs and requires constant maintenance to keep it up to date with cljs |
| 12:30 | Bronsa | and I simply don't have the time to keep up with dnolen |
| 12:30 | Bronsa | Olajyd: hi |
| 12:30 | rasmusto | yeah, I've used jvisualvm before. Maybe its overkill for what I need. |
| 12:31 | rasmusto | I'll use some old-fashioned visual inspection for now |
| 12:31 | Olajyd | Bronsa, I have a challenge that has been keeping me busy and cant seem to figur it out |
| 12:34 | Bronsa | Olajyd: don't ask me specifically for general help, please, ask the channel |
| 12:34 | Olajyd | ok |
| 12:34 | Bronsa | I'll help if I know how or if I have time to do so |
| 12:42 | Olajyd | Given sample rows [[“1” “2” “3”][“4” ”” “5”][“6” “” “7”][“8” “9” “10”][“2” “” “3”]] write a function that will return a pair of rows using the last non empty column (here it is col 1), ie [[[“1” “2” “3”] [“1” “2” “3”]] [[“1” “2” “3”] [“4” “” “5”]] [[“1” “2” “3”] [“6” “” “7”]] [[“1” “2” “3”] [“8” “9” “10” |
| 12:42 | Olajyd | [[“8” “9” “10”] [“2” “” “3”]]] :) |
| 12:43 | oddcully | am i having a deja vu? |
| 12:44 | Olajyd | oddcully :), hardly |
| 12:44 | Olajyd | :) |
| 12:45 | Olajyd | oddcully, you remember the problem right, I’m told to solve it by creating a pair like this |
| 12:53 | justin_smith | ,(rest (reductions (fn [prev cur] (map #(or (not-empty %) %2) cur prev)) [nil nil nil] [["1" "2" "3"]["4" "" "5"]["6" "" "7"]["8" "9" "10"]["2" "" "3"]])) |
| 12:53 | clojurebot | (("1" "2" "3") ("4" "2" "5") ("6" "2" "7") ("8" "9" "10") ("2" "9" "3")) |
| 12:54 | justin_smith | oh I think I misunderstood |
| 12:57 | kwladyka | Olajyd, i don't know what you want achive, why are there this ugly chars? |
| 12:57 | justin_smith | kwladyka: certain osx clients do that |
| 12:57 | justin_smith | kwladyka: "smart quotes" |
| 12:57 | expez | Bronsa: any way to get tools.reader and specify the platform? e.g. read like I'm the cljs reader and then reader like I'm the clj reader? |
| 12:58 | Olajyd | Kwladyka, I tried avoiding this smart quotes but they just keep comint up |
| 12:58 | Olajyd | *coming |
| 12:58 | kwladyka | Olajyd, it makes it so unreadable :) |
| 12:58 | akabander | Try using irssi in a console window? |
| 12:59 | kwladyka | Olajyd, anyway what do you want achieve if not what justin_smith show? |
| 12:59 | akabander | You need a non-GUI client that doesn't try to insert "smart quotes" (dumb feature). |
| 13:00 | Bronsa | expez: you men for feature expressions? |
| 13:00 | Bronsa | mean* |
| 13:00 | expez | Bronsa: yes, dealing with cljc files in refactor-nrepl is proving to more tricky than I had hoped |
| 13:01 | Olajyd | kwladyka, I started learning clojure like a month ago and my assignment for the day is `Write a function that Fill in an empty column from the last non-empty value` given a sample row like I gave earlier on |
| 13:02 | kwladyka | Olajyd, is it what justin_smith did? |
| 13:03 | Olajyd | oddcully and some others gave a solution using `reductions` and I tendered it as a soluttion but, wasn’t accepted |
| 13:03 | Olajyd | kwladyka, oh nope :) |
| 13:04 | Bronsa | expez: there are a bunch of endpoints that you need to configure to read cljs sources |
| 13:04 | kwladyka | Olajyd, Is it from 4clojure.com ? |
| 13:04 | Bronsa | expez: https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/analyzer.cljc#L2591 is a good example |
| 13:04 | justin_smith | oh wait |
| 13:05 | Olajyd | so thing I need to make them as a pair like a tuple kind of |
| 13:05 | justin_smith | ,(rest (reductions (fn [prev cur] (if (every? not-empty cur) cur prev)) [nil nil nil] [["1" "2" "3"]["4" "" "5"]["6" "" "7"]["8" "9" "10"]["2" "" "3"]])) |
| 13:06 | justin_smith | (["1" "2" "3"] ["1" "2" "3"] ["1" "2" "3"] ["8" "9" "10"] ["8" "9" "10"]) |
| 13:06 | clojurebot | (["1" "2" "3"] ["1" "2" "3"] ["1" "2" "3"] ["8" "9" "10"] ["8" "9" "10"]) |
| 13:06 | justin_smith | oops |
| 13:08 | Olajyd | such that the first element in the pair vector (tuple), is the vector that is the last non epmty row (based on col 1) and the second pair vector is the normal row with empty or non-empty col :) |
| 13:08 | Bronsa | Olajyd: how do you expect to learn clojure if you ask others to do your assignments though? |
| 13:08 | luxbock | I want to serialize a sorted-map with a custom comparison fn as EDN so that I can use it with both Clojure and CLJS, so I'm wrapping it in a record, giving it a print-method that reads it through its own constructor fn |
| 13:09 | luxbock | so now I'm re-implementing all the protocols/interfaces that Clojure maps use |
| 13:09 | luxbock | does this seem reasonable? |
| 13:09 | Olajyd | I’ve tried an approach already Bronsa, I used an atom to keep track of previous state |
| 13:11 | Bronsa | Olajyd: reduce already keeps track of previous state for you |
| 13:11 | expez | Bronsa: That looks great. Are you keeping this behavior? If I do :features #{:cljs} with the regular reader I still get the clj branch if there are multiple branches. |
| 13:11 | Bronsa | expez: by regular reader you mean LispReader.java? |
| 13:11 | Olajyd | Besides, I want to knw how it can be done right, I could have used stackoverflow u knw, but I want to learn, right :) |
| 13:11 | oddcully | luxbock: wouldn't that mean that you would have to eval the fn? |
| 13:12 | expez | Bronsa: yes |
| 13:12 | Bronsa | expez: if that's the case that would be a serious bug, seems unlikely tbh |
| 13:13 | oddcully | luxbock: or in other words: could i manipulate the edn to make your code execute evil things? |
| 13:13 | luxbock | oddcully: what do you mean by eval the fn? my plan is to add a tag to data_readers.cljc so that it should work the same in Clojure and CLJS |
| 13:13 | Bronsa | expez: oh wow you're right wtf |
| 13:14 | Bronsa | wow |
| 13:14 | Bronsa | ,(read-string {:read-cond :allow :features #{:cljs}} "#?(:cljs 1 :clj 2)") |
| 13:14 | clojurebot | 1 |
| 13:14 | Bronsa | ,(read-string {:read-cond :allow :features #{:cljs}} "#?(:clj 1 :cljs 2)") |
| 13:14 | clojurebot | 1 |
| 13:14 | Bronsa | this is seriously broken |
| 13:14 | Bronsa | puredanger: ^ |
| 13:14 | expez | Bronsa: Could you please keep this as an optional behavior? The default is retarded for use in tooling. |
| 13:14 | Bronsa | expez: no i mean LispReader is broken |
| 13:14 | luxbock | oddcully: I don't think it would be an issue |
| 13:14 | Bronsa | expez: tools.reader implements the expected behaviour |
| 13:15 | expez | Bronsa: They featured it, IIRC. The platform conditional is always present. |
| 13:15 | luxbock | the data the function receives is always trusted |
| 13:16 | expez | Bronsa: However, note that the Clojure reader will always inject the platform feature :clj as well. For platform-agnostic reading, see tools.reader. |
| 13:16 | expez | Bronsa: http://clojure.org/reader#The%20Reader--Reader%20Conditionals |
| 13:17 | Bronsa | wow |
| 13:17 | puredanger | The reader in Clojure is not intended to be platform-generic |
| 13:17 | Bronsa | I see |
| 13:17 | puredanger | Tools.reader is |
| 13:17 | Bronsa | I guess it kinda makes sense |
| 13:18 | Bronsa | LispReader doesn't have the configurable endpoints necessary to correctly read cljs |
| 13:18 | puredanger | Nor should it |
| 13:20 | Bronsa | the order-dependant behaviour might be confusing though |
| 13:22 | puredanger | It's like cond - the first successful test is chosen |
| 13:23 | puredanger | That's why it's reader cond-itionals |
| 13:23 | Bronsa | puredanger: yeah, I meant the cond-like behaviour + the implicit feature |
| 13:24 | Bronsa | puredanger: I think expliciting that :clj is an implicit :feature in the read/read-string docstring would help |
| 13:24 | puredanger | I agree the implicit feature is potentially confusing. The original version was not like that and I don't love it. |
| 13:25 | blake_ | OK, so, I'm using Monger to read some data, and I'm using find-maps which is lazy. As I'm traversing the find-maps result, the lazy chunking kicks in, and one of the records in my block is causing an exception. I mentioned this last week, but I'm still unclear what to do about it. Not just here, but generally. How do I figure out what record, or perhaps more importantly, who do I catch the exception and proceed while only skipping the bad record? |
| 13:25 | Pupeno | With ring/compojure, how can I have an object that is not being used by more than one thread at a time but that it's being re-used over time? http://stackoverflow.com/questions/32255188/ensuring-single-threadness-of-an-object-with-ring-and-compojure |
| 13:28 | expez | puredanger: what was the rationale for constraining the reader in this manner? |
| 13:28 | blake_ | Pupeno: Wouldn't keeping them in atoms do the trick? Atoms are thread safe. |
| 13:28 | blake_ | blake_: Although I guess that doesn't prevent one thread from sharing with another. |
| 13:29 | Pupeno | blake_: atoms are to share data between threads, the opposite of what I want to do. |
| 13:29 | Pupeno | blake_: a dynamic var is the closest to want I want, but I'm not sure *when* I should set it. |
| 13:30 | Bronsa | expez: LispReader is strictly a clojure reader, it technically can't read cljs |
| 13:30 | expez | aha |
| 13:30 | Bronsa | expez: main (probably only) issue is stuff that requires namespace awareness |
| 13:30 | Bronsa | like ::foo or `bar |
| 13:30 | blake_ | Pupeno: How do you know when the thread is done with the engine? |
| 13:31 | Bronsa | tools.reader has configurable endpoints for that, LispReader is hardcoded for clj |
| 13:31 | Pupeno | blake_: I don't and that's what I want, when the thread is re-used, I want the engine to be re-used. |
| 13:32 | blake_ | Pupeno: Oh! Well, couldn't you just map the thread to an engine? |
| 13:33 | Pupeno | blake_: that's more or less what I want to achieve. |
| 13:34 | blake_ | Pupeno: I guess I'm not getting what this would take beyond a regular map. (assoc engine-map thread engine)? |
| 13:34 | blake_ | Maybe make engine-map an atom? |
| 13:35 | blake_ | Why wouldn't that do it? |
| 13:35 | Pupeno | blake_: how do engines ever get removed when a thread is killed? |
| 13:37 | blake_ | Pupeno: When you kill the thread, you take it out of the engine-map? |
| 13:37 | Pupeno | I am not killing the threads, the threads are managed by Jetty or HTTPKit or whatever environment is running my app. |
| 13:38 | Pupeno | I am not creating them either. |
| 13:42 | blake_ | I feel like I'm missing a big piece here. |
| 13:43 | Pupeno | Jetty, HTTPKit, Aleph, whatever web server thingy will create threads, processes, re-use threads, whatever. I don't know. I have to ensure that no scriptengine is ever used by more than one thread at the same time and I want to re-use them because they are expensive and I'm happy to have one per thread so that locking is not a problem. |
| 14:20 | blake_ | Pupeno: Maybe use get-thread-bindings? |
| 14:21 | blake_ | No, I guess that wouldn't help. |
| 14:21 | Pupeno | :) |
| 14:25 | amalloy | Pupeno: you want a thread-local probably |
| 14:26 | amalloy | you can use java's ThreadLocal manually, or flatland/useful has a macro wrapping it |
| 14:26 | Pupeno | amalloy: what do you mean by that exactly? |
| 14:26 | Pupeno | amalloy: ah, ok. |
| 14:37 | blake_ | So...yeah...exception caused somewhere in chunking and I'm trying to figure out how to trap/skip the errant record. Anyone? |
| 15:33 | snowell | Say I have an atom pointing to a collection [1 2 3] |
| 15:33 | snowell | And I want it to be [2 3 4] |
| 15:33 | snowell | Is there a way to swap! the map function there, or can I only do (reset a (map inc @a))? |
| 15:34 | snowell | swap! only seems to work if the function takes the current value as the first arg |
| 15:34 | snowell | s/reset/reset! |
| 15:34 | Bronsa | ,(def a (atom [1 2 3])) |
| 15:34 | clojurebot | #'sandbox/a |
| 15:34 | Bronsa | ,(swap! a (partial mapv inc)) |
| 15:34 | clojurebot | [2 3 4] |
| 15:34 | snowell | Holy crap. It's so beautiful |
| 15:34 | snowell | (inc Bronsa) |
| 15:34 | lazybot | ⇒ 120 |
| 15:35 | snowell | I never remember partial :D |
| 15:35 | tatut | I'm partial to the #(mapv inc %) form (excuse the pun) |
| 15:36 | amalloy | snowell: even if you never remember partial, you can always reorder arguments by just using an intermediary lambda as a middle man |
| 15:36 | amalloy | (which is what tatut is suggesting) |
| 15:36 | snowell | Yeah, which I thought of doing |
| 15:37 | snowell | But when swap! works it always just looks nicer |
| 15:37 | tatut | ,(swap! a #(mapc inc %)) |
| 15:37 | clojurebot | #error {\n :cause "Unable to resolve symbol: mapc in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: mapc in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: mapc in this co... |
| 15:37 | tatut | ,(swap! a #(mapv inc %)) |
| 15:37 | clojurebot | [3 4 5] |
| 15:37 | tatut | typo |
| 15:37 | snowell | Thanks everyone |
| 15:37 | snowell | (inc tatut) |
| 15:37 | lazybot | ⇒ 2 |
| 15:39 | amalloy | snowell: well yes, you absolutely must use swap!. i was not recommending you use reset! |
| 15:52 | ectric | so if I develop an app with luminus using +jetty, then use lein ring uberwar and throw it on tomcat (elastic beanstalk), how does that work? is there a jetty server running in tomcat? or if i used +immutant, an immutant server? |
| 15:57 | justin_smith | ectric: jetty is a local replacement for what tomcat does |
| 15:57 | justin_smith | both are containers that can run your war |
| 15:58 | justin_smith | jetty is used in-process - you don't even start a separate container, but it loads up your code the same way tomcat would when deploying |
| 16:00 | ectric | justin_smith: sorry, i'm the whole java tomcat ecosystem is pretty foreign to me. so in that case, when i upload my war for my app to tomcat, it is still basically using the embedded jetty server? |
| 16:00 | ectric | justin_smith: *new to the java ecosystem |
| 16:00 | justin_smith | ectric: no, not at all |
| 16:00 | ectric | justin_smith: so it is ignored, and tomcat is used |
| 16:00 | justin_smith | ectric: locally, you put something in a plastic bag, on the server it goes in a canvas bag |
| 16:00 | justin_smith | bot hare just bags |
| 16:00 | justin_smith | ectric: on the server, jetty isn't present |
| 16:01 | justin_smith | ectric: tomcat and jetty are containers, the intention is that you can just pick one and it will work |
| 16:01 | justin_smith | you don't want more than one, you just use the one that is convenient for a given environment |
| 16:02 | justin_smith | so on a server you want tomcat (log rotation, hot reload, hosting multiple apps, diagnostics, advanced configuration options) and locally you want jetty (simple, few options, few features, just enough to run your app) |
| 16:02 | justin_smith | or maybe you don't want tomcat, it's a choice |
| 16:03 | expez | Is there a blogpost around describing how to use the new cljs analyzer.api? |
| 16:03 | ectric | justin_smith: ok, that makes a lot of sense thanks.. but like in my app core's -main function, i call a function that ultimately calls like jetty run server. is that somehow stripped out with lein ring uberwar? |
| 16:03 | ttt_fff | does clojure's 'schema' from prismatic provide anything like haskell's GADTS + typeclasses ? |
| 16:03 | justin_smith | ectric: tomact never calls your main |
| 16:04 | ectric | justin_smith: ahhh. what does it call/how does the thing get started? |
| 16:04 | justin_smith | ectric: lein-ring generates the code that tomcat can call to launch your app |
| 16:04 | justin_smith | ectric: based on your telling lein-ring what your handler is, etc. |
| 16:05 | ectric | justin_smith: that was the piece I was missing! makes sense now. |
| 16:05 | ectric | justin_smith: thanks a lot for the explanation |
| 16:05 | justin_smith | np! |
| 16:06 | ectric | justin_smith: is tomcat considered pretty good? |
| 16:07 | justin_smith | ectric: it has some features people like, but it's also a bit of a behemoth |
| 16:08 | ectric | justin_smith: gotcha |
| 16:09 | justin_smith | for example I have used it sometimes just because it's what elastic beanstalk builds on, and it was convenient to use elastic beanstalk |
| 16:12 | ectric | ya, that's why i'm using it. elastic beanstalk seemed like the easiest way to get my luminus app hosted - and it has been easy |
| 16:25 | mikerod | Bronsa: seancorfield I have been hitting up against this complicated issue with AOT vs JIT and clj 1.7.0 changes |
| 16:25 | mikerod | I've tracked through all of the Jira history and google groups to be sure I'm up to speed |
| 16:25 | mikerod | I understand most of it besides this last point "it should not ship AOT versions of other libraries that folks might also be using via JIT " |
| 16:26 | mikerod | I understand it as the danger is having both AOT compiled lib class mixed with the lib coming in as just clj files |
| 16:26 | mikerod | However, wouldn't the compiler prefer loading the class files to the clj files if the class file has a modified time > clj file? |
| 16:27 | mikerod | I can't seem to see the way that I'd get a forced reload of the clj file to cause the conflict with the pre-existing AOT class files |
| 16:28 | mikerod | I understand the 1.7.0 choice of clj class loading to prefer the in-memory version. I just don't see how the JIT happens at all in the presence of the AOTed files |
| 16:28 | puredanger | are you using deftypes? |
| 16:28 | mikerod | puredanger: yes this was a deftype one |
| 16:28 | mikerod | I'm hitting the "Caused by: java.lang.ClassCastException: schema.utils.SimpleVCell cannot be cast to schema.utils.PSimpleCell" |
| 16:28 | mikerod | there was some people complaining about this one when the 1.7.0 stuff was coming along |
| 16:29 | puredanger | I believe the issue is with deftype constructors (which load via the new bytecode) vs other means of loading, which load via Class.forName() through the DynamicClassLoader which takes into account the cached classes |
| 16:29 | mikerod | but I didn't see any concrete answers. It was highly related to the CLJ-1639 and CLJ-979 chain of Jiras though I'm fairly sure |
| 16:29 | puredanger | http://dev.clojure.org/jira/browse/CLJ-1741 |
| 16:30 | mikerod | I've read this Jira and thought it was related as well. |
| 16:30 | mikerod | My main confusion is how am I even getting a dynamic loader class along with the AOT/static loaded class if the namespace isn't being forcefully reloaded? |
| 16:31 | mikerod | I see that the modify time of the class files __init are all later than the schema clj files on the classpath |
| 16:31 | mikerod | so I can't see how the compiler would choose to recompile those files to cause this "duplicate" class definition for the deftype |
| 16:32 | mikerod | I understand the issue with `compile` not checking the `loaded-libs` too |
| 16:33 | mikerod | I'm not calling `compile` anywhere explicitly or something like that though. I'm actually kicking off the compilation chain via a `require` |
| 16:33 | puredanger | there are multiple use cases (that present errors in similar ways) through either AOT or reloading |
| 16:34 | mikerod | hmm.. ok |
| 16:35 | puredanger | sorry, I don't have any of this in my head so it's taking a bit to boot my brain :) |
| 16:35 | mikerod | I'm still baffled at how I can even get two versions of these deftype classes. It should only be compiled once. (brain hurts) |
| 16:35 | mikerod | No problem. This is a complicated trail of issues to sort through indeed. |
| 16:35 | hiredman | mikerod: many times these issues come down to code load order, if you import a deftype before requiring the namespace that generates it and that kind of thing |
| 16:35 | puredanger | well like in CLJ-1741 you end up with two versions because a constructor constructs via one classloader and a class literal is loaded via a different one |
| 16:36 | puredanger | the deftype constructor uses the new bytecode which uses the context classloader, which is typically not a DCL, so won't check the cache |
| 16:37 | hiredman | the loader order stuff will manifest as the project code failing to load if you don't aot |
| 16:38 | puredanger | the changes in 1.7 make class loading more universal across many paths to always be cache-aware (but the new bytecode case falls outside that) |
| 16:38 | puredanger | so it's not even that a recompile is occurring, but just that two classloaders loaded the identical class (which the jvm treats as two different classes) |
| 16:43 | puredanger | have you tried separating the deftype definition into a different namespace than where it is used? that seems to cut down on the most problematic scenarios |
| 16:44 | mikerod | puredanger: At what point do two separate loaders load the class? |
| 16:44 | mikerod | puredanger: no, I think I'm going to remove the AOT entirely because it seems dangerous. It was a lib we don't control - Prismatic schema |
| 16:44 | puredanger | instantiating a deftype instance and loading a class literal |
| 16:44 | mikerod | I was just trying to get some understanding of this issue |
| 16:44 | mikerod | and I couldn't understand where 2 loaders are trying to load the same class |
| 16:44 | mikerod | that is interesting |
| 16:45 | mikerod | I will try playing around with that to understand how those paths go |
| 16:46 | mikerod | My particular case really is a fallout of CLJ-322 I think |
| 16:46 | puredanger | yes, that is the root cause of much pain |
| 16:46 | mikerod | that AOT'ing your own stuff causes all your deps to be AOT'ed and included as well |
| 16:46 | mikerod | that is a sneaky issue |
| 16:46 | mikerod | makes AOT hard to work with |
| 16:46 | puredanger | the solutions are widely varying if you follow that ticket and the related design pages |
| 16:46 | mikerod | especially if I get this double-loader for a class issue with deftype :P |
| 16:46 | puredanger | I think clearly fully-transitive AOT is almost never what you want |
| 16:47 | mikerod | puredanger: yeah, I haven't delved into that entire Jira yet, I intended to get to that next up |
| 16:47 | puredanger | it has tendrils. I have spent many hours reading through all of it and the solution is still not clear to me. |
| 16:48 | puredanger | in Clojure, the granularity of compile is a single ns but in your typical build it is "some or all of my project code" |
| 16:48 | puredanger | those two levels have some impedance mismatch in goals |
| 16:49 | puredanger | it's tricky to describe to the low-level compile function: "just do this much, no more" |
| 16:49 | Bronsa | mikerod: sorry, been a while since I hacked that part of Clojure, can't really help without a minimal reproducible case |
| 16:49 | mikerod | yeah, I can understand that leading to a sticky situation |
| 16:49 | mikerod | Bronsa: fair enough, I certainly don't have one of those |
| 16:50 | mikerod | My case sounds about the same as when core.typed included AOT version of core.cache |
| 16:50 | mikerod | and that was breaking when a lib used core.typed and had the non-AOT core.cache on the path |
| 16:50 | mikerod | that's why I related it directly to that Jira and was curious |
| 16:50 | Bronsa | the unfortunate situation is that there is a disconnect between logic in the classloader, the compiler and the "compiling functions" in clojure.core |
| 16:50 | mikerod | I may have enough to go off of now to try to understand what the compiler is doing in my particular case |
| 16:51 | Bronsa | they handle compiling, loading and reloading in similar but slightly different ways that are not really compatible all the time |
| 16:51 | puredanger | I have compile to believe that having the output directory of the compile function on your input classpath is evil (despite that being stated as a requirement) |
| 16:51 | mikerod | yeah, I've been reading (and rereading) through a stack of Jiras around this a while to follow along with where things are |
| 16:52 | Bronsa | clojurebot: puredanger has compiled to believe |
| 16:52 | clojurebot | Pardon? |
| 16:52 | Bronsa | :( |
| 16:52 | puredanger | heh, come to believe |
| 16:52 | mikerod | haha |
| 16:52 | Bronsa | puredanger: I agree with that argument btw |
| 16:52 | puredanger | when compilation generates classes, it should have effects on the runtime state |
| 16:52 | Bronsa | it shouldn't* ? |
| 16:52 | puredanger | but its outputs should not affect the input classpath |
| 16:53 | Bronsa | ah, right |
| 16:53 | mikerod | that makes sense |
| 16:53 | puredanger | when multiple compiles have in a row in "wrong" orders, they currently trip each other up |
| 16:54 | puredanger | I went back and read all the irc history when Rich was putting this in and things he was trying to do at the time and the realities of where we are now are simply different |
| 16:54 | Bronsa | puredanger: seems like a simple solution would be to change the docs around that and fix the tooling then? |
| 16:55 | puredanger | there are no simple solutions re AOT :) |
| 16:55 | puredanger | I think there are also needs to be a good solution to 322 which is likely to also affect tooling |
| 16:56 | puredanger | but then I think there are still reload use cases with issues (like where this conversation started) |
| 16:57 | puredanger | that needs more research. imho, I do not think we should add more tracking state to the runtime, which is the direction of many of the patches. |
| 16:59 | puredanger | I'm curious how things would change if, for example, deftype constructors didn't use "new", or if we set the context classloader to a different loader around the use of "new" |
| 17:01 | Bronsa | puredanger: we can't really change the classloader used by new |
| 17:01 | puredanger | sure you can |
| 17:01 | puredanger | it'll use the context classloader |
| 17:06 | Bronsa | puredanger: it seems to me that once the classfile is loaded by the system classloader instead of DCL, `new` instructions will instantiate the classes resolved by that same classloader, no matter what the context classloader is |
| 17:06 | puredanger | at least I think it does :) |
| 17:07 | mikerod | I think this is outside of my understanding on how the new is used in the deftype now |
| 17:07 | mikerod | I thought the stack would just have whatever class reference you were going to be new'ing |
| 17:08 | mikerod | guess it is time for me to do more reading in that dept |
| 17:10 | amalloy | my understanding is the same as Bronsa's, but i am not really an expert on the topic |
| 17:10 | puredanger | I believe there is no reason that we cannot control the classloader used to load anything we're doing in Clojure |
| 17:11 | Bronsa | puredanger: say class C causes loading of class D |
| 17:11 | Bronsa | and we load C from a classfile |
| 17:11 | Bronsa | we have no way of having D be loaded from our DCL |
| 17:11 | Bronsa | the jvm will use whatever classloader it was used to load C to load D |
| 17:11 | puredanger | is C code we created the bytecode for? |
| 17:12 | puredanger | if so, then can't we create different bytecode? |
| 17:12 | Bronsa | puredanger: I'm assuming we're in a situation where we want to load C from disk and D from memory |
| 17:13 | Bronsa | puredanger: sure, we just can't use `new` instructions |
| 17:13 | puredanger | well that's what I'm saying |
| 17:13 | Bronsa | ah, missed that then :) |
| 17:14 | Bronsa | I actually thought of trying that a while ago but I was worried about the performance implications of using Class/forName+newInstance vs new |
| 17:17 | puredanger | like I said - needs research |
| 17:17 | puredanger | it might be faster than you think |
| 17:22 | puredanger | iirc there is a buried way to construct things for serialization too that's kind of sneaky |
| 17:40 | sdegutis | What are the benefits and drawbacks of putting :aot :all at the root of your project map in project.clj? |
| 17:44 | sdegutis | I imagine it would terribly mess with dynamic code reloading at runtime right? |
| 17:45 | sdegutis | But are there other hidden disadvantages, such as vars not having metadata available at runtime? |
| 19:24 | hiredman | ob |