2013-09-05
| 00:06 | xeqi | ddellacosta: I'm surprised how little value is placed on a test suite as regression prevention and code explination |
| 00:07 | ddellacosta | xeqi: yeah, the big thing I felt was missing from that article was a coherent appraisal of the value of regression tests--which imho is the *biggest* win when doing testing. |
| 00:07 | ddellacosta | xeqi: and insofar as TDD contributes to that, I feel like it is also a big win. But I recognize that it is not always the right way to approach development |
| 00:07 | clojurebot | Ok. |
| 00:10 | ddellacosta | hear what I'm saying clojurebot? |
| 00:12 | dnolen | ddellacosta: figuring out what to test is hard |
| 00:14 | ddellacosta | dnolen: one thing I really struggle with in Clojure (functional?) -land is understanding how to really distinguish between what may be considered an "integration test" vs. a "unit test." Often times I find myself creating fixtures to write a reasonable "unit" test, and it seems like I'm blurring the lines between the two. Maybe these labels don't apply, and I'm stuck in the old testing modality. |
| 00:15 | ddellacosta | anyways, I'm really interested to hear more of how people have approached this in their real-world Clojure projects. |
| 00:15 | ddellacosta | obviously a lot of folks are doing testing, in any case. |
| 00:15 | sdegutis | ddellacosta: that's not unique to FP, most people I know can't tell the difference. |
| 00:16 | sdegutis | Even in Ruby land. |
| 00:16 | sdegutis | Myself included. |
| 00:16 | ddellacosta | sdegutis: true. It took me a while before I really started to "feel" the difference, although I may be deluding myself--maybe the issue is that I still don't get it! |
| 00:16 | ddellacosta | sdegutis: yeah, haha |
| 00:17 | sdegutis | I stopped worrying about unit tests and now I only focus on highest-domain-level integration tests. |
| 00:17 | dobry-den | all of my clojure projects are toy projects and i like inlining core.assert into source |
| 00:17 | gws | i like to test things that could conceivably go in a spec for the project |
| 00:17 | sdegutis | I only do unit tests when I'm not sure something will work. And I only use integration tests to prevent regressions. |
| 00:17 | gws | not every little mechanical unit of code needs to have a test |
| 00:17 | sdegutis | (inc gws) |
| 00:17 | lazybot | ⇒ 1 |
| 00:18 | sdegutis | I used to test way too much, and my tests were bad, very possibly causing more damage than having no tests. |
| 00:19 | gws | yeah, and causing extra overhead each time you refactored some unit... |
| 00:19 | gws | been there :( |
| 00:19 | sdegutis | I guess we've both learned the hard way. But maybe there's no other way to learn. |
| 00:19 | xeqi | I find the most value at the feature test level |
| 00:20 | gws | ddellacosta: i think you're seeing a pattern :) |
| 00:20 | sdegutis | xeqi: yeah that's what I called "domain level". |
| 00:20 | ddellacosta | gws: yah, maybe so! |
| 00:21 | sdegutis | Basically I write a test for (add-to-cart user item) with an assertion that (items-in-cart user) contains item, and I don't worry about anything it calls internally. |
| 00:21 | xeqi | though I wrote/ported two libraries to let you test ring apps that way, so I might be biased there |
| 00:21 | sdegutis | Even the definition of "user" and "item" are domain-driven and not implementation-driven, so that I can swap out the database at any given time. |
| 00:21 | sdegutis | (For example moving away from MongoDB to Datomic.) |
| 00:22 | ddellacosta | I've had all kinds of experiences testing though. Recently I built a bit of functionality which entailed determining how different clients could access a resource stored in a data structure, basically a tiny little data access protocol I suppose. I wrote it using a TDD approach, and the code turned out quite nice, and the tests I got out of it showed me some other errors I had introduced in the implementation, which were easy to |
| 00:22 | ddellacosta | resolve and fix (I believe) because of the way I had approached it. |
| 00:22 | ddellacosta | but I've also had a lot of experiences like sdegutis where I test too much, my tests become brittle and hard to maintain |
| 00:23 | xeqi | unit tests are best for single functions that you can control with arguments, and even then if there was a way to do property testing for the function it might be better |
| 00:23 | sdegutis | And I've been moving away from writing tests that go through the HTTP "controller". I figure, even if I write those tests, I have to manually test it in my browser at every change anyway, so why do double work? |
| 00:24 | ddellacosta | sdegutis: yeah, that's one area (routing/"controllers") in particular where I've started to feel like I am building "integration" tests rather than "unit" tests. |
| 00:25 | ddellacosta | but yeah, with what xeqi and sdegutis are saying, I'm definitely seeing some trends. |
| 00:25 | sdegutis | ddellacosta: we have an entire suite built up of these, and they make it impossible to add/remove/change features because they're so over-complicated. |
| 00:25 | sdegutis | On one hand those tests are testing *both* feature-level and HTTP-level logic, which violates single-responsibility principle. |
| 00:25 | ddellacosta | interesting. |
| 00:25 | ddellacosta | are you talking specifically about Clojure, or some other platform? |
| 00:25 | sdegutis | Also, they make it really easy to move feature-level code *into* HTTP-level code. |
| 00:26 | sdegutis | Yes, this is for work, which is a Clojure app. |
| 00:26 | sdegutis | I'll tell you guys what it is after I push the redesign, since I'm not proud of the site as it looks right now. |
| 00:26 | ddellacosta | okay, interested to hear |
| 00:26 | xeqi | sdegutis: are you using a lib for your "controller" tests? |
| 00:27 | sdegutis | Not that the website looks bad, it fit in just fine a few years ago. |
| 00:28 | sdegutis | xeqi: Yep, we're using joodo and speclj, because my colleague wrote them, and he wrote the site, and he extracted them out of the site. |
| 00:29 | sdegutis | We're gradually moving away from most joodo features now that the rest of the Clojure-web-ecosystem has matured (he wrote Joodo back when Ring was barely a baby). |
| 00:30 | sdegutis | xeqi: joodo and speclj are tightly integrated, and joodo has "with-mock-rendering" and "with-routes".. http://joodoweb.com/tutorial/controllers |
| 00:32 | ddellacosta | huh, interesting. Never seen joodo but I have a bunch of routing helper functions which do a lot of the same things |
| 00:33 | ddellacosta | and which I feel mixed about. haha |
| 00:34 | sdegutis | I am personally not a fan of the abstractions it provides, which were borrowed heavily from Rails. |
| 00:34 | sdegutis | However, it executes them very well. |
| 00:34 | ddellacosta | yeah, I remember looking at speclj and thinking, "uh, not sure we want Rspec in Clojure..." |
| 00:34 | ddellacosta | I'm sure |
| 00:36 | sdegutis | That's something I'm hoping I can convince him of. But it's hard to come up with empirical evidence that Ruby idioms don't fit well into Clojure. It looks an awful lot like a question of preference. |
| 00:38 | technomancy | "cultural fit" might be more convincing |
| 00:38 | sdegutis | No comprendo amigo. |
| 00:38 | technomancy | you can do it, but everyone will look at you funny |
| 00:38 | technomancy | like putting each paren on its own line |
| 00:40 | xeqi | sdegutis: does that setup require you to specify the middleware stack in each (with-routes ..) ? |
| 00:41 | sdegutis | technomancy: He released gaeshi, which has sub-libs named kuzushi, kake, and tsukuri. He's not afraid to admit that culture-fit isn't a big priority to him. |
| 00:42 | sdegutis | xeqi: with-routes is only used in tests, and he recommends not putting middleware in tests. |
| 00:43 | sdegutis | technomancy: because when you have a message you want to get across to the world, that's more important than conforming to conventions. |
| 00:43 | xeqi | and you can write your "domain level" tests without middleware ? |
| 00:44 | sdegutis | xeqi: I'm not sure how to answer that. |
| 00:44 | clj_newb_2345 | is there an easy way to say : don't auto ":use clojure.core" ? I'm building a dsl, and I'm clashing with the clojure.core/* names |
| 00:45 | xeqi | you previously mentioned what I refered to as "feature tests" might be what you call "domain level" tests, so was just trying to get a feel there |
| 00:46 | sdegutis | To clarify about the gaeshi thing: I'm not saying it's bad that he used those names, just using it as an example of his driving philosophy. |
| 00:47 | xeqi | clj_newb_2345: add (:refer-clojure :exclude [*]) to the ns declaration |
| 00:47 | clj_newb_2345 | for eveyr file? |
| 00:47 | clj_newb_2345 | is there a way to put it into some type of lein config? |
| 00:47 | sdegutis | xeqi: Oh. I mean, I would write a test that does (add-to-cart cart item) and assert that (items-in-cart cart) contains item, and that would be my domain-level test. It wouldn't have anything to do with HTTP or anything else. And it wouldn't know the details of *how* add-to-cart or items-in-cart work. |
| 00:48 | sdegutis | xeqi: In fact even the data structures themselves would be created by other opaque functions like (create-cart ...) and (create-item ...) and they would have domain-driven keys like (:quantity item) etc, rather than being driven by any implementation details. |
| 00:49 | xeqi | sdegutis: ah, I was refering to a test that simulates how a user would interact with the system |
| 00:49 | sdegutis | xeqi: that's what I'm talking about too. Just at another level lower than HTTP. |
| 00:50 | sdegutis | I look at HTTP like a bridge between the user and the code, and that's helping my code a ton. |
| 00:50 | sdegutis | Ideally nothing in my test suite would test HTTP-level code at all. |
| 00:51 | xeqi | sdegutis: so you test your route configuration to non-http-level code elsewhere? |
| 00:51 | sdegutis | xeqi: No, I don't test it. |
| 00:52 | xeqi | ah |
| 00:52 | sdegutis | xeqi: Every time I make a change that could break one of those such tests, I always re-check that route in my browser anyway. |
| 00:52 | sdegutis | xeqi: The tests at that level don't tell me if anything actually works in real life, only that the code I wrote in file A matches the code I wrote in file B. |
| 00:53 | xeqi | "at that level" ? |
| 00:53 | sdegutis | Testing my HTTP-bridging code. |
| 00:53 | sdegutis | The production code that lives inside (defroute ...) and calls (add-to-cart). |
| 00:54 | sdegutis | It might make more sense for a bigger project with a bigger team. But this is a one-man small website. |
| 00:57 | reshpectabiggle | Really? Nobody had this nick? |
| 00:57 | reshpectabiggle | *snatched* |
| 01:00 | xeqi | we are talking pretty close to the same level. I do prefer mine to go through the ring interface, mainly to gain changes from the middleware stack |
| 01:01 | reshpectabiggle | xeqi: That's one of the reasons I don't test at that level, because I don't want my tests to deal with raw user-data. |
| 01:02 | reshpectabiggle | I mean raw incoming data. |
| 01:02 | reshpectabiggle | That encourages things like :packer and :type, in https://github.com/8thlight/hyperion#entities |
| 01:05 | reshpectabiggle | It leads to leaky abstractions, where the first representation of your data that you get from the HTTP level ends up being passed all the way down through your code, instead of being converted right away to something meaningful to your feature-specific-logic. |
| 01:07 | ddellacosta | argh, power died and looks like I missed out on some testing conversation |
| 01:08 | respectabiggle | ddellacosta: http://logs.lazybot.org/irc.freenode.net/%23clojure/2013-09-04.txt |
| 01:08 | respectabiggle | Scroll to the end. |
| 01:08 | ddellacosta | respectabiggle: cool, thanks. :-) |
| 01:08 | respectabiggle | Anyway I would take what I've said with a large dose of salt, I've only been at this for a few years. |
| 01:09 | xeqi | you still have the conversion code right? |
| 01:09 | ddellacosta | wtf does "gaeshi" mean |
| 01:09 | sdegutis | Uhh.. |
| 01:09 | sdegutis | ddellacosta: It's from martial arts. |
| 01:09 | ddellacosta | ah, google app engine pun, clever |
| 01:10 | sdegutis | ddellacosta: ever heard of 8th Light? |
| 01:10 | ddellacosta | sdegutis: yah, but what does it mean? |
| 01:10 | ddellacosta | sdegutis: most definitely, I know Uncle Bob and Colin Jones are there |
| 01:10 | ddellacosta | among others |
| 01:10 | sdegutis | Hmm, where do you know them from? |
| 01:10 | sdegutis | I mean, besides 8L. |
| 01:11 | ddellacosta | sdegutis: I mean, they are not people I know, other than by their writings. |
| 01:11 | ddellacosta | sdegutis: Uncle Bob is of course the grand-old-curmudgeon of TDD and code-cleanliness |
| 01:11 | sdegutis | Yeah. |
| 01:11 | sdegutis | You have any of his cleancoders.com episodes? |
| 01:11 | ddellacosta | sdegutis: and Colin Jones I know from his Clojure contributions, and excellent article on namespaces in Clojure |
| 01:12 | sdegutis | Heh yeah, the canonical namespaces article. |
| 01:12 | ddellacosta | sdegutis: naw, can't justify paying for them as of yet |
| 01:12 | sdegutis | Yeah I hear ya. |
| 01:12 | ddellacosta | yeah, definitely a good one |
| 01:12 | sdegutis | I worked at 8L for a few years. That's where I learned TDD. |
| 01:12 | seangrov` | ddellacosta: Paying for what? |
| 01:12 | technomancy | sdegutis: eh; it's fine to do your own thing, you just can't expect it to get any traction |
| 01:12 | ddellacosta | sdegutis: I mean, I can't buy into any one person's ideas too strongly, especially a pedant like Uncle Bob, not to be derogatory--I like some of what he says a lot. |
| 01:13 | sdegutis | technomancy: wait hold on, what is that in response to? |
| 01:13 | technomancy | literally never heard of anyone using speclj in the wider community |
| 01:13 | sdegutis | Oh right. |
| 01:13 | sdegutis | ddellacosta: I agree with your approach. |
| 01:13 | ddellacosta | seangrov`: oh, I mean, I just don't want to pay for videos on uncle Bob's philosophy right now, since I get as much of it as I need from reading clean code |
| 01:13 | technomancy | lisp in general has a long tradition of cowboy coders striking out and creating their own little worlds |
| 01:14 | sdegutis | technomancy: Oh, is that where Ruby gets it from? |
| 01:14 | technomancy | (because that's practically all you could do in the 80s unless you went to MIT) |
| 01:14 | ddellacosta | technomancy: totally |
| 01:14 | sdegutis | seangrov`: he's talking about cleancoders.com, you should check it out, some of the videos might be helpful |
| 01:15 | sdegutis | A few of us are in Episode 4 a few times. |
| 01:15 | ddellacosta | sdegutis: ah, well for that I'd be interested in checking it out. ;-) |
| 01:15 | sdegutis | I think I called FP "a fad". |
| 01:15 | ddellacosta | ah, haha |
| 01:15 | sdegutis | :D |
| 01:15 | ddellacosta | I mean, it is in some ways. Us developers as a group are pretty faddish |
| 01:15 | sdegutis | I also said temporal coupling was like what Spock did. |
| 01:16 | technomancy | sdegutis: just wait, give Intel another couple years and this multicore thing will be a distant memory |
| 01:16 | sdegutis | (I was trolling Uncle Bob.) |
| 01:16 | technomancy | we'll have our 8GHz chips yet |
| 01:16 | ddellacosta | sdegutis: gotcha. :-) |
| 01:16 | ddellacosta | technomancy: sweet. |
| 01:16 | sdegutis | technomancy: been holding my breath like they said to. |
| 01:19 | sdegutis | ddellacosta: anyway reason I asked about Colin and Bob is cuz I only knew them from 8L and I'm always curious to see how it is that different people I know also know each other. So thanks for letting me know. |
| 01:20 | sdegutis | Also Colin wrote REPLy which is part of Leiningen now, so that's pretty cool :) |
| 01:20 | ddellacosta | sdegutis: sure. I mean, I should be clear I've never met them in person or even exchanged emails, I meant know as in "know of." Although I think Colin did give me a tip on getting fixtures working in clojurescript.test at one point here on IRC. |
| 01:21 | sdegutis | ddellacosta: gotcha |
| 01:21 | ddellacosta | sdegutis: yeah, seems like Colin's written some real good stuff. |
| 01:21 | xeqi | $seen trptcolin |
| 01:21 | lazybot | trptcolin was last seen quitting 8 hours and 56 minutes ago. |
| 01:22 | ddellacosta | xeqi: damn, didn't know about that, very cool IRC command. I'm still such an IRC newb |
| 01:22 | technomancy | colin is great; he should spend more time on IRC =P |
| 01:22 | xeqi | yeah, we wanted him for something the other day... can't remember now tho |
| 01:22 | sdegutis | Yeah I keep pressing "trp[TAB]" every few days and sigh when it doesn't autocomplete. |
| 01:22 | ddellacosta | technomancy: yah, I think the time I was having trouble was the only time I saw him on here, and he was super helpful. |
| 01:22 | ddellacosta | haha |
| 01:23 | sdegutis | Anyway they have open office on Friday afternoons, I should visit them soon. If you're in the Chicago area you should too. |
| 01:23 | sdegutis | Lots of very smart people. |
| 01:24 | ddellacosta | sdegutis: never been to Chicago, would like to go. And would love to drop into 8th Light some day too, and meet those folks. |
| 01:24 | sdegutis | For example this was a nice Friday talk to learn some Haskell: http://vimeo.com/63093231 |
| 01:28 | dissipate_ | sdegutis, why doesn't 8th light mention clojure on their site? |
| 01:28 | sdegutis | dissipate_: they haven't really gotten into it yet. Still doing Ruby mostly. |
| 01:30 | dissipate_ | sdegutis, even though bob martin has been evangelizing clojure? |
| 01:32 | sdegutis | lol... "but who honestly, in their right mind, uses list literals without putting a space after the comma... Yeah, 'nobody', is the answer." -- http://vimeo.com/63093231#t=292 |
| 01:34 | sdegutis | dissipate_: 8th Light has clients and therefore not all their projects are greenfield. But I know that Bob's site uses Clojure. |
| 01:36 | dissipate_ | sdegutis, hmm, sounds like Relevance is a better shop |
| 01:36 | sdegutis | dissipate_: seeing as the guy who literally wrote the book on Clojure works there, then yes, probably. |
| 01:36 | dissipate_ | nevermind, i want to work at 8th light: http://8thlight.com/our-team/angeleah-daidone |
| 01:37 | sdegutis | dissipate_: why? |
| 01:37 | ddellacosta | dissipate_: lame |
| 01:37 | dissipate_ | sdegutis, hot female apprentices ^ |
| 01:37 | dissipate_ | want to touch the hiney! |
| 01:37 | sdegutis | dissipate_: wow. |
| 01:37 | ddellacosta | dissipate_: super lame |
| 01:37 | seabre | Going from cosmetology to software development is super impressive. |
| 01:37 | sdegutis | seabre: very. |
| 01:38 | ddellacosta | wow |
| 01:38 | spjt | i went from digging ditches to software development, but i'm an ugly guy, so who cares. |
| 01:38 | dissipate_ | mmmmm, impressive |
| 01:38 | sdegutis | They're very active in helping people learn from 0 to professional. |
| 01:38 | ddellacosta | spjt: that is also impressive. |
| 01:38 | nightfly | spjt: Still impressive |
| 01:38 | dissipate_ | sdegutis, it had nothing to do with her looks? |
| 01:38 | sdegutis | Colin went from having a master's in trumpet performance to being an 8L apprentice to finally a craftsman. That was pretty cool. |
| 01:38 | sdegutis | dissipate_: let's pretend this conversation didn't happen. |
| 01:39 | dissipate_ | i bet they had a bunch of dudes who wanted to apprentice and they picked her |
| 01:39 | ddellacosta | sdegutis: agreed |
| 01:39 | sdegutis | dissipate_: what do you do for a living? |
| 01:39 | spjt | tbh that picture looks like they were trying pretty hard to make her look better than she actually does |
| 01:40 | sdegutis | spjt: what do you do for a living? |
| 01:40 | dissipate_ | sdegutis, program |
| 01:40 | sdegutis | dissipate_: what language? |
| 01:40 | spjt | sdegutis: code |
| 01:40 | dissipate_ | sdegutis, perl mostly |
| 01:40 | sdegutis | spjt: what language? |
| 01:40 | sdegutis | dissipate_: really? You write Perl for a living? |
| 01:40 | spjt | sdegutis: j2ee, at least when my boss is looking |
| 01:40 | sdegutis | I didn't know there were jobs for that. |
| 01:40 | dissipate_ | sdegutis, correct |
| 01:40 | sdegutis | spjt: Ha. Have you been able to use Clojure at work? |
| 01:41 | dissipate_ | sdegutis, when i was first in the job market there were more jobs for perl than python |
| 01:41 | spjt | sdegutis: yes |
| 01:41 | sdegutis | dissipate_: Cool. How do you like Clojure compared to Perl? |
| 01:41 | dissipate_ | sdegutis, i want to switch to clojure really bad. |
| 01:42 | sdegutis | spjt: Sweet. |
| 01:42 | sdegutis | dissipate_: Why? |
| 01:42 | spjt | dissipate_: you might have better luck than me. |
| 01:43 | dissipate_ | sdegutis, i'm not a fan of syntax heavy languages. i got into perl because i didn't want to do java or .net, and python jobs weren't really available. |
| 01:43 | spjt | I use clojure for one-off things like moving data from one format to another, but I'm not allowed to use it in the application |
| 01:43 | dissipate_ | sdegutis, also, i'm convinced that pure functions and immutable data structures are the way to go after watching Hickey's talks and reading the paper 'Out of the Tar Pit' |
| 01:43 | sdegutis | dissipate_: What about Ruby? |
| 01:44 | sdegutis | spjt: Ah good way to find use out of it. Have you used other languages to do that same thing (besides Java) before Clojure? |
| 01:44 | dissipate_ | sdegutis, not too interested in it. i'm sure is fairly on par with python, but it suffers like all the OO languages: mutable state and non-pure functions. |
| 01:45 | spjt | sdegutis: I tried to learn clojure and gave up before learning scala, then came back and it made sense |
| 01:45 | seabre | You can sorta do immutable data structures in ruby |
| 01:45 | seabre | [1,2,3,4].freeze |
| 01:46 | dissipate_ | i just wish clojure was viable as a scripting language. seems like it is not because of the startup time of the JVM. |
| 01:47 | sdegutis | seabre: true but its stdlib is geared slightly more towards mutation |
| 01:47 | sdegutis | dissipate_: Have you looked into Racket? I hear good things about it. |
| 01:47 | spjt | dissipate_: Have you looked at scala |
| 01:47 | dissipate_ | so for now i'm going with python and clojure. python for scriping, clojure for applications. and C for low level programming. |
| 01:47 | gws | haskell? :D |
| 01:47 | sdegutis | Oh boy, I've heard nothing but bad things about Scala from people I respect. |
| 01:47 | zanes | dissipate_: re: Angeleah Daidone - There would probably be more female programmers if men like us a) stopped objectifying them, and b) stopped ascribing their success to their looks. |
| 01:47 | dissipate_ | sdegutis, no. it is a viable scripting language that has good libs? |
| 01:47 | sdegutis | zanes: what do you do for a living? |
| 01:48 | sdegutis | dissipate_: It's a Scheme dialect which is very similar to Clojure. |
| 01:48 | sdegutis | dissipate_: read this, it's very informative about Clojure compared to Racket: http://technomancy.us/169 |
| 01:48 | spjt | Scala is good if you want to get into FP but you have a job |
| 01:48 | dissipate_ | spjt, i have not looked at scala. it has OO so that's a turn off. plus heavy syntax (so i've heard), another turn off. |
| 01:49 | dissipate_ | i'm also interested in haskell to some degree, but the fact that it compiles to native executables is a big turn off for me. they need to make it compatible with the JVM. |
| 01:49 | sdegutis | spjt: I'm not sure about that. For example I could hear someone saying the same thing about using Ruby "to get into OOP" when you have a job, but I'm not sure I'd recommend Ruby to anyone anymore. |
| 01:50 | s4muel | Scala to me didn't seem removed enough from Java, conversely that's touted as a strong point. But the syntax is verbose and it felt like Java. Clojure (obviously) doesn't. |
| 01:50 | zanes | sdegutis: I'm a software engineer. |
| 01:50 | dissipate_ | zanes, i was just joking about her. her story actually sounds quite interesting, going from cosmetology to software development. |
| 01:50 | sdegutis | zanes: cool, what language(s) do you primarily use? |
| 01:50 | spjt | s4muel: That's why I said "if you have a job". If you know Java you can "learn" it in an hour. |
| 01:51 | sdegutis | dissipate_: I love native executables. They're great! What I don't like about Haskell is the super-strict typing, to the point that you have multiple functions with numbers at the end describing how many args they take, like zipWith3 zipWith4 etc |
| 01:51 | zanes | dissipate_: Fair enough. I just think we need to be careful about the kinds of jokes we make; the tech community is notoriously hostile towards women. |
| 01:51 | spjt | s4muel: You can then gradually transition, eventually you realize you're not using mutable state anymore and then it's much easier to pick up Clojure, etc. |
| 01:52 | sdegutis | s4muel: yeah, I'm actually really surprised and impressed at how well Clojure fits into the JVM while being such a completely different language from Java. |
| 01:52 | dissipate_ | sdegutis, i don't because you have to worry about what machine your code is running on. virtual machines FTW. love or hate the JVM, it beats native. |
| 01:52 | zanes | sdegutis: These days I mostly use Clojure (in the form of Cascalog) and Javascript. |
| 01:52 | sdegutis | zanes: to throw in my 2¢, I don't think the goal is to get more women programmers, but to become more respectful of everyone in general. |
| 01:53 | s4muel | spjt: I see where you're coming from. Yeah, a lot of J2EE folks I know are right at home with Scala. I was never heavy into Java but more into Python/Perl and a little Haskell, so the biggest jump for me was a) state and b) lisp-y syntax |
| 01:53 | dissipate_ | sdegutis, BTW, i'm not saying virtual machines are always better, but if my app can run on a virtual machine, i'll use that every time. |
| 01:55 | s4muel | But working with the libraries on the jvm from clojure has been so easy (so far, at least) that I keep wondering 'is that it?' |
| 01:55 | sdegutis | dissipate_: that philosophy doesn't play well with Mac OS X native apps. |
| 01:55 | sdegutis | dissipate_: using a JVM app on Mac feels so weird compared to a native ObjC app. |
| 01:56 | sdegutis | s4muel: ditto :) |
| 01:56 | scottj | sdegutis: even good jvm apps, like intellij idea? |
| 01:56 | dissipate_ | sdegutis, i don't write native apps, so i wouldn't know. :P |
| 01:57 | sdegutis | scottj: I haven't used IntelliJ. I dunno how it runs. Maybe it has a cool container that makes it less weird. I should look into that since I'm writing a Swing app that I plan to use on my Mac. |
| 01:57 | dissipate_ | sdegutis, as for objective c, i'll try to avoid that as i have avoided java. |
| 01:57 | spjt | s4muel: It doesn't really have that much to do with syntax. Scala only encourages immutable state, it doesn't require it |
| 01:57 | sdegutis | dissipate_: meh, taking the approach "right tool for right job" has worked wonders for me. |
| 01:57 | sdegutis | dissipate_: if I avoided ObjC, I wouldn't have been able to write this window manager I'm using. |
| 01:58 | dissipate_ | sdegutis, i agree. but i avoid the issue by just not doing native app development. |
| 01:58 | sdegutis | dissipate_: for the same reason, I'm writing a GUI app in Swing because Clojure is the right language for this task, not ObjC, even though I plan to use it on a Mac. |
| 01:58 | scottj | sdegutis: is it tiling? released? |
| 01:58 | sdegutis | dissipate_: that's one solution, but it's an awfully boring one isn't it? |
| 01:58 | sdegutis | scottj: yes, yes. |
| 01:58 | sdegutis | scottj: https://github.com/sdegutis/zephyros |
| 01:59 | sdegutis | scottj: well technically it's not tiling, it's *anything* |
| 01:59 | am2605 | I have a bit of a dumb newbie question (sorry)... |
| 01:59 | dissipate_ | sdegutis, why is it boring? |
| 01:59 | zanes | sdegutis: Disagree. There's value in explicitly fostering diversity by making the tech community a welcoming space for women. |
| 01:59 | ahihi | sdegutis, re: zipWithN — in my experience those are used very rarely. and things liftMN are more nicely expressed with the Applicative combinators |
| 01:59 | sdegutis | scottj: you write your own stuff in it. My AppGrid configuration is very much like tiling: https://github.com/sdegutis/zephyros/wiki/AppGrid |
| 01:59 | sdegutis | dissipate_: you're limiting how many fun/cool problems you can solve. |
| 01:59 | zanes | am2605: Don't ask if you can ask, just ask. :) |
| 02:00 | ahihi | s/things/things like/ |
| 02:00 | sdegutis | zanes: making it a welcoming space is fine, but inviting certain people in is really weird and creepy. |
| 02:00 | sdegutis | ahihi: Then maybe I'm being unfair to Haskell. I should probably give it a real chance. |
| 02:00 | zanes | sdegutis: I don't see what's creepy about outreach to an underrepresented minority. |
| 02:00 | s4muel | Or OCaml. |
| 02:01 | am2605 | if I have a list of say '("Joe" "Bloggs" "Jenny" "Citizen") how can I pick off each pair of values and return them as a list such as '("Joe Bloggs" "Jenny Citizen") ? |
| 02:01 | dissipate_ | sdegutis, not really. there are plenty of fun/cool problems that can be solved that can be deployed via the web. i know the web sucks, but coding for native platforms is worse. |
| 02:01 | am2605 | @zanes thanx :) |
| 02:01 | sdegutis | zanes: it's like saying "hey guys, we don't have enough ___ in here.. let's go get some ___ to join us!" |
| 02:01 | sdegutis | I dunno, it's like saying you know what's best for that person. It feels arrogant to me. |
| 02:02 | zanes | Oh, yeah. I never imagined going about it that way. |
| 02:02 | sdegutis | dissipate_: I'm not saying there aren't. I'm just saying that's not all of them. |
| 02:03 | sdegutis | zanes: well "outreach" may seem abstract, targeted at a group, but groups are always made up of real individuals. So at the end of the day, an "outreach" means that some very real individual girl in high school sees an ad that says maybe she should become a programmer and she might be happier that way. |
| 02:03 | sdegutis | And to me that's weird and creepy. |
| 02:04 | zanes | I think it's possible to present the idea in a non-patronizing way. |
| 02:04 | zanes | "Here's an awesome career path you may not have considered." |
| 02:05 | zanes | At this point I'm assuming we're discussing organizations like Black Girls Code (http://www.blackgirlscode.com/). |
| 02:05 | dissipate_ | sdegutis, of course not, i know. i had a stint doing embedded linux development. it was a bit of a pain because each board had it's own architecture, so you couldn't just use gcc out of the box. you had to set up a cross compiler. |
| 02:05 | sdegutis | zanes: I never heard of a concrete organization that does this, no. |
| 02:06 | scottj | zanes: I was actually thinking of the recent Conj extension for women presenters. |
| 02:06 | sdegutis | dissipate_: scary |
| 02:06 | sdegutis | scottj: yeah, see, that's weird. |
| 02:06 | zanes | scottj: Not familiar. What were your thoughts? |
| 02:07 | sdegutis | A call for presenter should be focused on content not on the presenter. |
| 02:07 | sdegutis | I don't care who's presenting, I just want great content. To care about who's presenting feels shallow and unprofessional. |
| 02:07 | scottj | zanes: I think that male/female distinction is not a particularly important one and there are a lot more important aspects of diversity. |
| 02:08 | dissipate_ | sdegutis, another advantage of developing via a virtual machine is collaboration. anyone who wants to contribute to such an open source project can do so on whatever platform has the virtual machine set up properly. |
| 02:08 | zanes | scottj: Go on. |
| 02:08 | scottj | zanes: I don't want to, this topic can too easily offend people :) |
| 02:09 | sdegutis | dissipate_: yeah, that's a great advantage. But it doesn't always apply. For example my Mac OS X window manager only works on Mac OS X. |
| 02:09 | sdegutis | scottj: Oh. Well I hope I haven't offended anyone. |
| 02:09 | zanes | scottj: Fair enough. It's an important problem, though, and, I feel, one that benefits from conversations like this. |
| 02:10 | dissipate_ | sdegutis, that app is for a specific platform, so that i understand. |
| 02:11 | ahihi | I got tired of CS being such a boys' club, so I'm switching to math ;) |
| 02:11 | ahihi | (there are other reasons, but it's certainly a factor) |
| 02:12 | sdegutis | There's a lot of ways the programmer community could stop disrespecting *people in general*. |
| 02:12 | zanes | (This is why explicitly focusing on gender diversity matters — I don't want to lose people like ahihi. ;)) |
| 02:12 | ddellacosta | just popping in to voice agreement with zanes. I want the tech community in general, and Clojure in particular, to be open and welcoming to women, and that includes being conscious of how people receive what you say. |
| 02:12 | sdegutis | For example they could stop having "drinkups" which focus on beer and late evenings, which don't really work well for us family people. |
| 02:12 | zanes | sdegutis: It's worthwhile to focus on specific problem areas. I think it's hard to argue with the fact that the tech community, on average, is fairly hostile towards women. |
| 02:13 | ddellacosta | sdegutis: I've definitely had some of my co-workers complain about drink ups too, although it's more that I just think we should have multiple venues for people |
| 02:13 | sdegutis | zanes: I don't disagree. |
| 02:13 | seabre | am2605, did you ever figure out your problem |
| 02:13 | sdegutis | ddellacosta: makes sense |
| 02:13 | ddellacosta | sdegutis: but definitely, need a space so people can socialize around tech without it being about getting trashed |
| 02:14 | ddellacosta | and on that note, gonna go get lunch for reals |
| 02:14 | sdegutis | :) |
| 02:14 | seabre | ,(map #(str (first %) " " (second %)) (partition 2 (list "Joe" "Bloggs" "Jenny" "Citizen"))) |
| 02:14 | clojurebot | ("Joe Bloggs" "Jenny Citizen") |
| 02:15 | seabre | Probably a terrible way to do it, but I guess that works. |
| 02:15 | dissipate_ | zanes, are you kidding me? the culture is rife with brogrammerism |
| 02:15 | zanes | dissipate_: I don't disagree? |
| 02:15 | sdegutis | On the other hand, there are some people (both men and women) who find a reason to be upset about *everything and anything*. And some of them hide it behind feminism. But that doesn't help the cause either. |
| 02:15 | dissipate_ | sdegutis, 'drinkups'? brogrammers |
| 02:16 | dissipate_ | sdegutis, are you working with brogrammers? |
| 02:16 | sdegutis | dissipate_: https://github.com/blog |
| 02:16 | sdegutis | first big blue words: "Washington DC Drinkup" |
| 02:16 | am2605 | seabre: that does work - thank you! I think the partition is what I was missing. Appreciated! |
| 02:16 | seabre | no prob |
| 02:17 | dissipate_ | sdegutis, yep, brogramming |
| 02:17 | sdegutis | k |
| 02:17 | scottj | women don't drink? |
| 02:17 | sdegutis | What's everyone working on tonight? |
| 02:18 | sdegutis | I'm struggling to decide between making my app for-pay or making it open-source. |
| 02:18 | seabre | I was playing around with overtone. |
| 02:18 | scottj | sdegutis: what platform? |
| 02:18 | sdegutis | JVM. |
| 02:18 | dissipate_ | sdegutis, just got done giving a PhD student some advice on TDD. he got trapped in a project that is a ball of mud, with stuff not working. |
| 02:19 | sdegutis | dissipate_: maybe also suggest he buy some cleancoders.com episodes on testing. |
| 02:19 | sdegutis | Bob's got a lot of good advice on this topic. |
| 02:19 | dissipate_ | sdegutis, i sent him the clean coder's stuff. but he's working with other people who aren't into that. |
| 02:20 | sdegutis | ouch |
| 02:20 | dissipate_ | but he had another problem with his piece of the project |
| 02:20 | sdegutis | seabre: looks neat |
| 02:21 | dissipate_ | he spent a lot of time on some fancy data structure, but he wasn't using generative testing to make sure it was working fast enough. apparently, when he integrated his data structure into the larger project, things got slower than expected. |
| 02:21 | sdegutis | Ah, I had that happen with my music player Mac app. |
| 02:22 | sdegutis | Fortunately the solution for me was to buy into Apple's Core Data framework, and it worked wonders. |
| 02:22 | seabre | Overtone is really cool. It reminds me a lot of Common Music: http://commonmusic.sourceforge.net/ |
| 02:23 | dissipate_ | sdegutis, you would think that academics who are often not brogrammers would practice clean code, but nope, i guess not |
| 02:24 | dissipate_ | industry doesn't do clean code, academia doesn't do clean code, is open source the only hope? |
| 02:25 | sdegutis | Also, emacs package authors need to stop saying "you're using melpa so it's your fault your stuff is broken" and just stop putting broken stuff on master. |
| 02:25 | sdegutis | dissipate_: I've seen a lot of clean open source apps and a lot of very messy ones. Same is probably true in academia and industry. |
| 02:28 | sdegutis | Is the 'respectabiggle' joke lost on everyone? :( |
| 02:28 | Raynes | Yes. |
| 02:28 | respectabiggle | At least not technomancy I bet. |
| 02:29 | respectabiggle | s/joke/reference/ |
| 02:29 | respectabiggle | *in-crowd |
| 02:30 | seabre | wait |
| 02:30 | seabre | Silver Chair |
| 02:30 | respectabiggle | (inc seabre) |
| 02:30 | lazybot | ⇒ 1 |
| 02:30 | Raynes | Golden throne. |
| 02:31 | respectabiggle | (dec Raynes) |
| 02:31 | lazybot | ⇒ 35 |
| 02:31 | Raynes | (gtfo respectabiggle) |
| 02:31 | respectabiggle | (inc Raynes) ;; didn't know it would do something |
| 02:31 | lazybot | ⇒ 36 |
| 02:32 | Raynes | (lols :at respectabiggle) |
| 02:34 | respectabiggle | Is there a bias against open source apps, that they must somehow be inferior to pay-for apps? |
| 02:35 | respectabiggle | Like, "if it was really quality, then they would have charged for it" |
| 02:36 | scottj | respectabiggle: I think there might be in my mind because I was going to suggest that he try to charge for it and if that fails then open source it. |
| 02:38 | scottj | respectabiggle: though I think it might be limited to some domains. I don't think I would have thought that way if it were something server-side/linux. iPhone app, definitely. |
| 02:38 | respectabiggle | scottj: In this case It's a Clojure IDE. |
| 02:40 | respectabiggle | I've always operated on the idea that, if an app is truly worth it, then people will pay for it and spread the word to their colleagues. |
| 02:41 | respectabiggle | But I've not seen that be true with for-pay apps. If it's only barely better than the competition, people won't pay. |
| 02:42 | respectabiggle | Especially if it's already a skeptical field, like IDEs. |
| 02:43 | scottj | is this nightcode or the new version of la clojure? |
| 02:43 | respectabiggle | No. A new one. |
| 02:43 | scottj | ahh, cool. |
| 02:45 | sdegutis | I want to name it Nepenthe but I think that might be taken wrong. |
| 02:45 | seabre | Name it Couture |
| 02:46 | sdegutis | I don't even know how to pronounce that, so I can't name it that :P |
| 02:49 | scottj | sdegutis: so what's special about it? |
| 02:50 | sdegutis | Nothing yet. |
| 02:51 | sdegutis | scottj: its specialness isn't something that can be communicated until it's done, since it has to be experienced |
| 02:53 | sdegutis | Partially because it may never be done, in which case it doesn't matter what features it would have had. |
| 02:55 | scottj | I think a whisker browser-inspired IDE for clojure would be fun to try http://www.maartensz.org/computing/squeak/Helps/Programming/WhiskerBrowser.gif |
| 02:56 | scottj | But of course then you get into all the boring stuff of editors/IDEs and you start to wish it were just an extension for emacs. |
| 02:56 | sdegutis | :) |
| 02:59 | sdegutis | One of the main things I've learned in my short career is that most real-world problems aren't actually hard to solve, it's just the way that people think you should solve them is hard. |
| 02:59 | sdegutis | For example writing a text editor isn't hard, but writing a text editor that works with every single language ever is hard. |
| 03:01 | sdegutis | My IDE won't be good for editing Ruby files. And it probably won't be able to handle files millions-of-lines long. But it'll work great with typical Clojure projects. |
| 03:03 | zanes | sdegutis: Learn from Emacs and expose the language the editor is written in to the user! |
| 03:03 | zanes | That way people can extend it to handle Ruby. |
| 03:05 | sdegutis | zanes: that's been done, it's called emacs :) |
| 03:11 | sdegutis | ,(partition 2 1 [:end] "foo") |
| 03:11 | clojurebot | ((\f \o) (\o \o) (\o :end)) |
| 03:12 | sdegutis | ,(map #(conj %1 %2) (iterate 0 inc) (partition 2 1 [:end] "test") |
| 03:12 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 03:12 | sdegutis | ,(map #(conj %1 %2) (iterate 0 inc) (partition 2 1 [:end] "test")) |
| 03:12 | clojurebot | #<ClassCastException java.lang.ClassCastException: clojure.core$inc cannot be cast to clojure.lang.IPersistentCollection> |
| 03:12 | sdegutis | :) |
| 03:13 | sdegutis | ,(map #(conj %2 %1) (iterate inc 0) (partition 2 1 [:end] "test")) |
| 03:13 | clojurebot | ((0 \t \e) (1 \e \s) (2 \s \t) (3 \t :end)) |
| 03:13 | sdegutis | wooo |
| 03:32 | sdegutis | I think I want reduce. Or maybe iterate. I want apply (f coll) which gives me back [result new-coll] and apply (f new-coll) etc etc, conjing all results into a new vector. |
| 03:33 | sdegutis | How would you do this? Reduce? |
| 03:33 | sdegutis | I'm thinking reduce with a seed of [[] initial-coll] |
| 03:33 | sdegutis | Kind of ugly, but with the right destructuring it shouldn't be too bad. |
| 03:35 | ordnungswidrig | sdegutis: what about reductions? |
| 03:35 | sdegutis | Ah, yes! |
| 03:35 | sdegutis | I always forget about reductions, thanks ordnungswidrig :) |
| 03:36 | ordnungswidrig | sdegutis: you're welcome |
| 03:37 | sdegutis | Ah, neither reduce nor reductions works here. |
| 03:37 | sdegutis | Because the list (f) should operate on next is whatever (f) returns. |
| 03:38 | sdegutis | I think iterate may be close. |
| 03:38 | ordnungswidrig | sdegutis: you have some fn like (fn [coll] [(count coll) (conj coll :foo)]) ? |
| 03:39 | ordnungswidrig | sdegutis: this cries for the state monad :) |
| 03:39 | sdegutis | Not quite. |
| 03:40 | ordnungswidrig | sdegutis: but you f is coll -> [result coll] ? |
| 03:41 | sdegutis | Actually it could just be: (f [results coll]) -> [new-results new-coll] and just keep calling it until the coll it receives is empty. |
| 03:41 | sdegutis | I wonder if I have to resort to recur, or if I can use some seq function(s) for this. |
| 03:42 | ordnungswidrig | yes, I would "lift" your basic fn coll -> [result coll] into a fn [results coll] -> [results coll] which can be used with reductions |
| 03:42 | ordnungswidrig | and take-while #(not (empty? (second %)) |
| 03:42 | sdegutis | Ah. |
| 03:44 | sdegutis | ordnungswidrig: that take-while could be used with iterate instead, right? |
| 03:45 | sdegutis | (take-while #(not (empty? (second %))) (iterate my-fn)) |
| 03:45 | ordnungswidrig | sdegutis: yes, that should work |
| 03:45 | sdegutis | Cool, thanks for the idea of take-while, that was the missing piece all along :) |
| 03:46 | ddellacosta | why do we have both rest and next? |
| 03:46 | sdegutis | ddellacosta: http://clojure.org/lazy |
| 03:47 | ddellacosta | sdegutis: they both return lazy sequences, from the docs |
| 03:47 | sdegutis | That's more of a "Rich's thoughts on paper" type doc though. |
| 03:47 | ddellacosta | sdegutis: oh sorry, I see there is more explanation on that page |
| 03:47 | ddellacosta | sdegutis: thanks! |
| 03:47 | sdegutis | Yes. |
| 03:47 | sdegutis | Any time. |
| 03:48 | sdegutis | Periods at the bottom of the line are overrated· Let's put them in the middle from now on· |
| 03:48 | callen | bottom? |
| 03:49 | sdegutis | Yes• |
| 03:53 | rurumate | How to get the name of var a in clojurescript? in clojure I'd do (name (meta (var a))), but apparently var is not a function in clojurescript..... |
| 03:54 | sdegutis | I thought CljS has no vars. |
| 03:54 | rurumate | oh |
| 03:54 | ddellacosta | yep, no vars. |
| 03:54 | rurumate | hmm |
| 03:54 | ddellacosta | yet. |
| 03:54 | sdegutis | https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure#concurrent-programming |
| 03:54 | ddellacosta | I think seangrov` is working on it. |
| 03:55 | ddellacosta | sdegutis: I like Japanese periods: 。 |
| 03:55 | sdegutis | Oh |
| 03:55 | ddellacosta | heh |
| 03:55 | sdegutis | 😄 |
| 03:56 | ddellacosta | callen: how goes it? |
| 03:56 | rurumate | so the situation is this: I have a buch of functions, say fn0, fn1 and fn2 and now I want to (mapv #(js/alert (format ("result of % is %" (name %) (%)) [fn0 fn1 fn2]) or something |
| 03:56 | rurumate | is that even possible in clojurescript? |
| 03:57 | ddellacosta | rurumate: should be... |
| 03:58 | ddellacosta | rurumate: although I haven't used mapv in CLJS yet, but believe it exists. |
| 03:58 | rurumate | the opening paren after format should not be there.. |
| 03:58 | ddellacosta | rurumate: although, map is lazy so I'm not sure you'll get what you're expecting |
| 03:58 | rurumate | ddellacosta: mapv is eager |
| 03:58 | ddellacosta | rurumate: d'oh, you're right, my bad |
| 03:59 | sdegutis | ddellacosta: I think he's talking about the (name %) part |
| 03:59 | rurumate | sdegutis: aye |
| 04:00 | ddellacosta | rurumate: yeah, there are too many parens is all, methinks |
| 04:00 | sdegutis | yeah, needs more haskell |
| 04:00 | ddellacosta | heh |
| 04:01 | rurumate | off to the day jobs.. |
| 04:01 | ddellacosta | rurumate: cheers |
| 04:05 | sdegutis | Oh hi ucb. |
| 04:10 | TEttinger | so I'm wondering about array processing a la APL in clojure. is this already covered by Incanter's data sorcery? or would it be a worthwhile project for me to implement the standard set of verbs from APL for use from clojure? |
| 04:10 | TEttinger | a lot already is covered, like I don't need to reimplement map. |
| 04:10 | TEttinger | but simple things like array reshaping and rotation |
| 04:12 | TEttinger | I have kinda noticed that 2d primitive arrays are a pain in clojure. ^"[[L" |
| 04:13 | SegFaultAX | I'm pretty sure Mikera is working on a comprehensive matrix library. |
| 04:13 | SegFaultAX | https://github.com/mikera/matrix-api |
| 04:14 | SegFaultAX | TEttinger: If it's useful, maybe you could reach out to him on twitter/github/mailinglist and see if you can contribute there. |
| 04:14 | TEttinger | SegFaultAX, thanks. this looks much more professional than what I could do though |
| 04:14 | Apage43 | see also https://github.com/prismatic/hiphip |
| 04:16 | SegFaultAX | I'm so happy to see prismatic re-opening stuff. |
| 04:17 | shaungilchrist | TEttinger: I am an APL weirdo and a lisp practitioner, this article would be cool to redo for clojure http://archive.vector.org.uk/art10500180 |
| 04:17 | TEttinger | Apage43, heh I've been using hiphip |
| 04:17 | TEttinger | Apage43, did you submit an issue on that? |
| 04:17 | Apage43 | mm? Don't think so. |
| 04:18 | TEttinger | ah, thought the nick sounded familiar |
| 04:18 | TEttinger | there's an issue with AOT compiling hiphip |
| 04:18 | TEttinger | I made a total kludge hack of a fork of hiphip that fixes it |
| 04:20 | Apage43 | interesting |
| 04:20 | TEttinger | https://github.com/tommyettinger/hiphip-aot/blob/master/src/hiphip/double.clj#L10 |
| 04:20 | ddellacosta | shaungilchrist: very cool article, thanks |
| 04:20 | Apage43 | i have a project that indirectly does some array'y stuff |
| 04:20 | TEttinger | shaungilchrist, I'll take a look |
| 04:20 | sdegutis | I think I may actually have a case where loop/recur is the cleanest/clearest solution. |
| 04:20 | Apage43 | at some point i'll probably pull out mikera's matrix stuff and try and make it cleaner/less garbagey |
| 04:21 | sdegutis | This is neat. |
| 04:21 | Apage43 | it's already a dependency, since incanter drags it in and I use a thing from incanter |
| 04:21 | ddellacosta | sdegutis: I don't think it's that uncommon. |
| 04:21 | Apage43 | sdegutis: I have those sometimes. Every so often though I take a second look and it fits into reduce though |
| 04:22 | sdegutis | ddellacosta: I've never had to resort to it before, in about a year of doing Clojure professionally, until now. |
| 04:22 | ddellacosta | sdegutis: whenever I have to retain state over a loop that can't be handled cleanly with reduce, I use it |
| 04:22 | Apage43 | though *those* largely wind up being even *more* nicely expressed with https://github.com/LonoCloud/synthread |
| 04:22 | ddellacosta | or, what Apage43 said |
| 04:22 | sdegutis | Apage43: In this case it won't fit into reduce because the input collection is mutated by the fn itself at each loop and may get shorter than just one element. |
| 04:22 | ddellacosta | Apage43: oooh, didn't know about that, nice |
| 04:22 | sdegutis | Apage43: (by mutated I only mean it may return a shorter collection) |
| 04:23 | Apage43 | synthread.core/for |
| 04:23 | Apage43 | er |
| 04:23 | Apage43 | lonocloud.synthread/for |
| 04:23 | Apage43 | rather |
| 04:23 | Apage43 | =P |
| 04:24 | Apage43 | maybe |
| 04:24 | Apage43 | might not fit there |
| 04:25 | sdegutis | I do know that this is the first time my test passed all night, and the code is much less ugly than it was when I was trying to use sequences. |
| 04:25 | ddellacosta | wow, really going to have to take a close look at synthread, lots of cool stuff there |
| 04:25 | ddellacosta | sdegutis: I hear ya, sometimes it's just easier not to fight the beast, haha |
| 04:25 | TEttinger | shaungilchrist, I didn't see any Common Lisp code? |
| 04:27 | sdegutis | Are there any uppercase symbols that are reserved words or core constants in Clojure? |
| 04:28 | sdegutis | Like "(def SYMBOL 1)" |
| 04:29 | TEttinger | Math/PI |
| 04:29 | TEttinger | but that's java |
| 04:29 | TEttinger | actually I don't even know... ##(+ 1 Math/PI) |
| 04:29 | lazybot | ⇒ 4.141592653589793 |
| 04:30 | Apage43 | ddellacosta: dunno if its a good example as this was stuff I was doing in a hurry last week, but here's some code before/after I synthreadified it https://www.refheap.com/18344 |
| 04:30 | augustl | sdegutis: I don't think so. The only reserved stuff is in clojure.core, which you can un-refer anyways. |
| 04:31 | ddellacosta | Apage43: very cool, thanks. I don't have time to dig into it at the moment, but excited to learn about this library. Thanks for your extra example! |
| 04:31 | Apage43 | less "how do i express this with reduce" more "this is what I am trying to do" |
| 04:32 | Apage43 | it's just one function torn out of a checkers game |
| 04:33 | ddellacosta | Apage43: yeah, it shares that nice quality with the threading operators in that it makes the intention much cleaner |
| 04:37 | sdegutis | TEttinger, augustl: thanks |
| 04:38 | sdegutis | Are vectors efficient at pushing on the end and enumerating from the front? |
| 04:38 | augustl | sdegutis: yes |
| 04:38 | sdegutis | sweet :D |
| 04:39 | sdegutis | So I'm using vectors, case, and loop/recur. This sounds pretty efficient so far. |
| 04:40 | augustl | sdegutis: FYI, if you use conj you'll get the "most efficient behaviour" so to speak |
| 04:40 | sdegutis | awesome, because I already am :) |
| 04:53 | sdegutis | $help |
| 04:53 | lazybot | You're going to need to tell me what you want help with. |
| 04:53 | sdegutis | $help send |
| 04:53 | lazybot | Topic: "send" doesn't exist! |
| 04:53 | sdegutis | $help mail |
| 04:53 | lazybot | sdegutis: Send somebody a message. Takes a nickname and a message to send. Will alert the person with a notice. |
| 04:54 | sdegutis | $mail brehaut Thanks for https://github.com/brehaut/inc-clojure-brush/blob/master/shBrushClojure.js#L64-L385 :) |
| 04:54 | lazybot | Message saved. |
| 04:59 | sdegutis | Is there a less dumb way of doing this? |
| 04:59 | sdegutis | ,(not-any? #{\a \b \c} [\f]) |
| 04:59 | clojurebot | true |
| 04:59 | sdegutis | given #{\a \b \c} and \f |
| 05:02 | benoyst | ah. |
| 05:03 | ddellacosta | sdegutis: what's dumb about that? |
| 05:03 | sdegutis | it creates a vector just to test if a char is in a group of chars |
| 05:04 | ddellacosta | I mean, you could do |
| 05:04 | ddellacosta | ,(some #(= \f %) #{\a \b \c}) |
| 05:04 | clojurebot | nil |
| 05:04 | sdegutis | No other way? |
| 05:04 | ddellacosta | not much less concise though. And it creates a anon function in place of your vector. |
| 05:04 | sdegutis | ,(doc contains?) |
| 05:04 | clojurebot | "([coll key]); Returns true if key is present in the given collection, otherwise returns false. Note that for numerically indexed collections like vectors and Java arrays, this tests if the numeric key is within the range of indexes. 'contains?' operates constant or logarithmic time; it will not perform a linear search for a value. See also 'some'." |
| 05:05 | sdegutis | Hmm. |
| 05:07 | ddellacosta | sdegutis: yep, contains seems pretty good too. |
| 05:07 | ddellacosta | ,(contains? #{\a \b \c} \f) |
| 05:07 | clojurebot | false |
| 05:07 | ddellacosta | ,(contains? #{\a \b \c} \a) |
| 05:07 | clojurebot | true |
| 05:07 | sdegutis | But.. that doesn't make sense. |
| 05:07 | sdegutis | Ah. |
| 05:07 | ddellacosta | sdegutis: ? |
| 05:08 | sdegutis | ,(contains? #{\x \y \z} \x) |
| 05:08 | clojurebot | true |
| 05:08 | sdegutis | Oh, in sets, each element is considered a "key" isn't it? |
| 05:08 | sdegutis | That must be why it works. |
| 05:09 | ddellacosta | ah, yeah, 'cause sets are not ordered I thought |
| 05:09 | ddellacosta | speaking of sets |
| 05:09 | ddellacosta | ,(clojure.set/intersection #{\a \b \c} #{\a}) |
| 05:09 | clojurebot | #<ClassNotFoundException java.lang.ClassNotFoundException: clojure.set> |
| 05:09 | ddellacosta | crap |
| 05:10 | ddellacosta | a well. In any case, could do that too if you wanted to use an unnecessary set instead of an unnecessary vector. ;-) |
| 05:10 | sdegutis | ,(require 'clojure.set) |
| 05:10 | clojurebot | nil |
| 05:10 | sdegutis | ,(clojure.set/intersection #{\a \b \c} #{\a}) |
| 05:10 | clojurebot | #{\a} |
| 05:10 | sdegutis | Nah, contains? works great :) |
| 05:11 | ddellacosta | sdegutis: yah, I was definitely joking. It's just fun to enumerate all the different possible ways to do something. |
| 05:11 | ddellacosta | sdegutis: ah, so you can require just like in repl, cool, dunno why I didn't think of that. |
| 05:13 | sdegutis | ,(drop 1 [7 8 9]) |
| 05:13 | clojurebot | (8 9) |
| 05:13 | sdegutis | Is there short-hand for that, or is that already the short-hand? |
| 05:13 | sdegutis | Oh duh. |
| 05:13 | sdegutis | ,(rest [7 8 9]) |
| 05:13 | clojurebot | (8 9) |
| 05:13 | ddellacosta | sdegutis: I mean, other than rest/next? |
| 05:13 | ddellacosta | right |
| 05:14 | ddellacosta | haha |
| 05:14 | sdegutis | I should go to bed soon. 4am might not be the ideal coding time. |
| 05:14 | ddellacosta | naw, it's hard to connect all these things up in your head. |
| 05:14 | ddellacosta | probably! damn, you are in North America aren't you. |
| 05:14 | ddellacosta | go to bed! |
| 05:14 | sdegutis | Lil bit. |
| 05:14 | ddellacosta | ;-) |
| 05:14 | sdegutis | (re: NAmerica) |
| 05:15 | sdegutis | ddellacosta: lol soon (maybe) but don't worry, I won't keep you from working any longer :) |
| 05:15 | ddellacosta | although, it's nice to have people around this time of day…always gets a bit dull in the afternoons/evenings in here. :-/ |
| 05:15 | ddellacosta | haha |
| 05:15 | ddellacosta | yah, good point. |
| 05:15 | ddellacosta | sdegutis: well, you aren't keeping me from work, *I* am keeping me from work, let's be clear. |
| 05:15 | sdegutis | :P |
| 05:19 | danlentz | ouch I have just been badly bitten by lisp-1-ness |
| 05:20 | sdegutis | how? |
| 05:20 | clojurebot | with style and grace |
| 05:20 | danlentz | really hard to get used to |
| 05:21 | sdegutis | danlentz: care to share? |
| 05:21 | danlentz | sdegutis: i have macros defschema, etc for diatomic which create vars literal, resource, stmt, graph, etc. Also defining many diatomic attributes :resource/uri stmt.scope/global, etc |
| 05:22 | danlentz | but then I foolishly named my constructors literal, stmt, graph as well |
| 05:22 | sdegutis | heh ah yeah, that |
| 05:23 | sdegutis | Hyperion does that too. I've resorted to naming them (new-graph) etc. |
| 05:23 | danlentz | works fine when evaluating things by hand as the schema is only needed at the top of the evaluation, and dodnt notice that these functions overwrote the schema defs |
| 05:24 | danlentz | but of course when loading the whole file in order this is not the case, as the db initialization happens only when you start doing something. thus the schemas are all blown away at that point. |
| 05:26 | danlentz | it is really insidious how frequently one is conditioned to think in lisp2 without even realizing it |
| 05:27 | danlentz | lisp1 is prettier in many ways but it really is a mindfuck at times |
| 05:29 | danlentz | i guess i will have to change the constructors to make-* e.g. make-literal, make-stmt but i don't like it |
| 05:30 | danlentz | because all my entities are interned, so make-* is not quite accurate as well as ugly |
| 05:31 | danlentz | find-or-make-literal….. egads... |
| 05:32 | danlentz | maybe I shouldd use caps. (defschema Literal …) [defn literal ...) |
| 05:34 | danlentz | i really haven't read enough clojure source yet to have soaked up all the common practices such as naming, and lisp1 definitely exacerbates my naivete |
| 05:36 | danlentz | but i do like clojure a lot I'm enjoying learning it I just needed to vent for a moment :) |
| 05:41 | danlentz | iI'm surprised there's not builtin prog1 -- first thing I write for any clojure coding. Calling it "returning" tho, since |
| 05:41 | danlentz | i believe I saw thart somewhere |
| 05:41 | danlentz | prog1 is one of the most useful forms |
| 05:42 | clgv | danlentz: why? you have progn aka `do` |
| 05:44 | sdegutis | I wonder if (do ...) just turns into { ... } in Java |
| 05:44 | danlentz | well its pretty common to compute a value, then do a bunch of other things based on it, whose value is not returned to the caller |
| 05:44 | sdegutis | danlentz: you can do that |
| 05:44 | danlentz | actually I most often use aprog1 which gives you an anaphoric 'it within the body |
| 05:45 | clgv | danlentz: not in functional programming |
| 05:45 | clj_newb_2345 | are there any good examples of mobile html apps built in clojurescript, or is clojurescript just too damn slow? |
| 05:46 | sdegutis | danlentz: yeah a lot of your comments strongly indicate you would benefit from a total paradigm shift instead of transliterating what you're used to into Clojure |
| 05:46 | danlentz | well for example for diatomic queries, initially I compute the entity, which is what I want to return, then I do various things around it which i dont |
| 05:47 | sdegutis | danlentz: btw do you mean Datomic? |
| 05:48 | sdegutis | danlentz: btw you can do that with (let) |
| 05:49 | clgv | sdegutis: in defn it seems like you are right and `(do ...)` just evaluates to {...} |
| 05:49 | clgv | sdegutis: just tried it and looked at the class via jd-gui |
| 05:50 | sdegutis | clgv: neat :) |
| 05:50 | danlentz | yes, it is a paradigm shift. But step by step things are improving… Actually I've been pleasantly surprised that clojure hasn't been too bad to pick up and start writing stuff… IIRC it took me a month to get a workable asdf/package dicipline/etc down in CL and probably a year to really master the finer points |
| 05:50 | clgv | sdegutis: (defn f [x] (do (println "1") 2)) => public Object invoke(Object x) { ((IFn)const__0.getRawRoot()).invoke("1"); return const__1;} |
| 05:50 | danlentz | y datomic |
| 05:50 | clgv | you can guess the constants ;) |
| 05:50 | sdegutis | danlentz: that's the beauty of Clojure, it's simple. |
| 05:51 | Anderkent]away | clgv: a more meaningful test would be to compare (defn f [x] (println "1")) and (defn f [x] (do (println "1"))). I'd expect the same bytecode |
| 05:51 | danlentz | mine is diatomic b/c it looks like dirt :) |
| 05:51 | sdegutis | Common Lisp is "powerful" but very complex (unnecessarily so IMHO). |
| 05:51 | Anderkent]away | i.e. do is just a language construct, it doesnt have a runtime signature |
| 05:51 | clgv | Anderkent]away: hm yeah defn has an implicit do ;) |
| 05:52 | Anderkent]away | but that doesn't mean it puts a do around its body, just that it 'parses the body as if it was in a do' |
| 05:52 | danlentz | common-lisp makes a point of not imposing any particular concept on how you think. clojure makes a point of very specifically doing the opposite |
| 05:53 | clgv | Anderkent]away: no it expands to somewhat containing (fn* ...) ;) |
| 05:54 | danlentz | I love CL a lot but its really exciting how vibrant the clojure community and ecosystem is |
| 05:54 | sdegutis | danlentz: CL may say that it doesn't impose any way of thinking, but it actually imposes a mutable, imperative style of thinking |
| 05:54 | sdegutis | it's just implicit |
| 05:54 | danlentz | not at all. you can program in a functionl style as well as in clojure |
| 05:55 | danlentz | you just don't have to |
| 05:55 | sdegutis | Sure, but it's not nearly as well supported as the mutable/imperative style is. |
| 05:55 | danlentz | supported? |
| 05:55 | sdegutis | Just like you can do imperative and mutable code in Clojure, it's just not nearly as easy or pleasant. |
| 05:55 | danlentz | what's missing? |
| 05:56 | scottj | danlentz: does CL have immutable hash maps built-in? |
| 05:56 | danlentz | actually you can do immutable CLOS even very nicely. have a look at the project parallel for a sterling example of this style |
| 05:57 | danlentz | well plists would be the equivalent |
| 05:57 | danlentz | you cons to the front of them to use them immutability |
| 05:58 | danlentz | a lists can be used this way as well. |
| 05:59 | danlentz | actually though I wrote my own weight-balanced tee collections lib and also a impelmentation of the ctrie ds with quite a bunch of stuff http://github.com/danlentz/cl-ctrie |
| 06:01 | scottj | danlentz: and how do you remove something from the plist without messing with a "copy" elsewhere? See, this is what people mean by CL doesn't support functional very well. |
| 06:01 | danlentz | ctrie is a really interesting example of a careful blend of functional and mutable approach that takes a lot of the benefits of both approaches |
| 06:02 | danlentz | if you removed it, that would be mutating it.. |
| 06:02 | danlentz | [cdrr plist) would just remove a newley consed entry at the head w/o mutating |
| 06:02 | danlentz | cddr i mean |
| 06:02 | scottj | ,(let [a {:a 1 :b 2} b (dissoc a :a)] [a b]) |
| 06:03 | clojurebot | [{:a 1, :b 2} {:b 2}] |
| 06:03 | scottj | in CL? |
| 06:03 | scottj | so long as [:b 2] is at the front and you don't need fast lookup then CL is functional, right? |
| 06:04 | sdegutis | scottj: what are you working on these days |
| 06:04 | danlentz | ( let ((a (list :a 1 :b 2))) (values a (cddr a))) |
| 06:05 | sdegutis | ahhh i remember (values) well |
| 06:05 | sdegutis | I'm glad Clojure was able to ditch the legacy of CL. |
| 06:06 | danlentz | actually one would usually use plist-remove a common short utility function that would give you the same semantics as dissoc |
| 06:07 | scottj | danlentz: anyway, I think a wide array of immutable (not immutable by convention) data structures built-in is one thing people mean by CL not supporting functional as well as it could. |
| 06:07 | scottj | I don't see plist-remove in hyperspec |
| 06:08 | scottj | oh, people write their own version of the the common missing functional utility functions :) |
| 06:08 | danlentz | well I'm glad that clojure is being successful, although I think many of the perceptions of CL are just from being misunderstood. But, its partially to blame for that, since it is extremely easy to misunderstand it. learning CL for me at least was unbelievably hard |
| 06:10 | sdegutis | danlentz: I don't think it's misunderstood, in fact that's the perception I have: it's unbelievably hard. And that's a symptom of the problem with it: it's unnecessarily complex to the point of being convoluted and detrimental to productivity. |
| 06:10 | danlentz | there are 738 built-in symbols, and 1135 pages of spec. It is not unreasonable to have users write a few 3 or four line utile. That is exactly the clojure approach as well. You can't argue that clojure.core is nearly as replete as cl. |
| 06:11 | sdegutis | danlentz: You can get good at the language, but that doesn't mean the language is good. Such a steep learning curve is often a sign of a poorly designed language. |
| 06:12 | danlentz | y it is unbelievably hard to learn. I never in a million years expected it to take 4-5 years to get fluent. My experience before that was a few weeks to master the basics of a new lang, with the gaps filling in after that while working. |
| 06:13 | sdegutis | danlentz: a few weeks is reasonable. |
| 06:13 | sdegutis | 4-5 years is unreasonable, and I blame the language. |
| 06:13 | danlentz | common lisp is not truly just one language, it is a fluid environment for developing a language that suits your problem |
| 06:14 | danlentz | common lisp has no philosophy -- the only thing that binds us together is a shared disgust for all the alternatives. (scott burson) |
| 06:14 | sdegutis | heh |
| 06:15 | sdegutis | Whoa, this Clojure lexer is only about 50 (readable) lines. |
| 06:16 | danlentz | maybe.. having gone through the process in retrospect it was extremely rewarding and I think it helped me think about programming in a fundamentally different way. So I am grateful for the experience. But it was indeed painful for a long time. |
| 06:18 | danlentz | there is nothing in clojur that couldn't be done better in common lisp IMO. but, the barrier to entry and learning curve is just never going to be suitable to most people. |
| 06:21 | sdegutis | Guys, |
| 06:21 | danlentz | and the community is somehow broken. no two cl programmers can ever agree on anything. collaboration is almost unheard of. There are very academic minded enthusiasts who debate endlessly the finest details. It is a social problem to a large extent. |
| 06:21 | danlentz | everybody rewrites everything independently form the ground up |
| 06:22 | sdegutis | What approach would you take, given a sequence of chars beginning with a double-quote, if you wanted to find the end of the string (ignoring escaped double-quotes)? |
| 06:22 | danlentz | called the NIH (not invented here) syndrome |
| 06:22 | danlentz | subseq |
| 06:22 | sdegutis | danlentz: barrier to entry is itself a feature of a language that can't be ignored or dismissed. |
| 06:22 | sdegutis | danlentz: It's one reason CL is not mainstream but Clojure is getting there. |
| 06:23 | danlentz | well I'm not disagreeing about that at all. |
| 06:23 | sdegutis | Okay. Maybe we should stop bikeshedding. |
| 06:23 | sdegutis | :) |
| 06:24 | danlentz | :) i needed a break and Its really the first conversation I've had in #clojure so I've enjoyed it :) |
| 06:25 | danlentz | i've never understood the schism of CL with other lisps. e.g. emacs-lisp seems quite hostile to cl and there is little code sharing or cross pollination. rms is in particular CL-hostile |
| 06:26 | danlentz | but i'm glad to see a lisp on the rise, and if its clojure then i'm on board |
| 06:27 | danlentz | i do also hate these [] though…. :) |
| 06:27 | sdegutis | danlentz: everyone else here's asleep, you should come back in about 5 hours for a better conversation :) |
| 06:27 | danlentz | homogenous parens are so easy... |
| 06:27 | devn | false |
| 06:27 | devn | im around |
| 06:27 | ddellacosta | sdegutis: you're still up?? |
| 06:27 | lazybot | ddellacosta: Definitely not. |
| 06:27 | sdegutis | devn: hullo! |
| 06:27 | devn | danlentz: it reads better |
| 06:27 | sdegutis | ddellacosta: sure |
| 06:27 | ddellacosta | heh |
| 06:27 | sdegutis | only been what, an hour? |
| 06:27 | devn | danlentz: it's a matter of taste, but it reads better |
| 06:28 | devn | IMO |
| 06:28 | sdegutis | danlentz: it reads way better. |
| 06:28 | sdegutis | danlentz: to me it has the same purpose and benefit as syntax highlighting |
| 06:28 | danlentz | y I need to finally make peace with paredit. |
| 06:28 | ucb | I'm around too |
| 06:28 | bamford | people, newb speaking: I'm trying to generate the sequence \a...\z. Best I can do is (map char (range (int \a) (inc (int \z)))) |
| 06:28 | sdegutis | I think it's a matter of taste, in the same way that pizza is a matter of taste: everyone I know agrees with me about it. |
| 06:28 | bamford | Surely there's a better way? |
| 06:28 | ucb | I know I'm quiet, but CMON |
| 06:28 | devn | ,(map char (range 97 123)) |
| 06:29 | clojurebot | (\a \b \c \d \e ...) |
| 06:29 | sdegutis | ucb: hullo! |
| 06:29 | ucb | sdegutis: ! |
| 06:29 | Anderkent]away | ,(map char (range (int \a) (int \z))) |
| 06:29 | clojurebot | (\a \b \c \d \e ...) |
| 06:29 | sdegutis | danlentz: okay you may get a better conversation any minute at this rate. |
| 06:29 | devn | ,(int \z) |
| 06:29 | clojurebot | 122 |
| 06:29 | Anderkent | ah right thats what oyu had |
| 06:29 | devn | ,(map char (range 97 122)) |
| 06:29 | clojurebot | (\a \b \c \d \e ...) |
| 06:30 | sdegutis | ,(doc range) |
| 06:30 | ddellacosta | ,(map char (range 97 123)) |
| 06:30 | clojurebot | "([] [end] [start end] [start end step]); Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step, where start defaults to 0, step to 1, and end to infinity." |
| 06:30 | clojurebot | (\a \b \c \d \e ...) |
| 06:30 | devn | I think Raynes made a range which will let you do char ranges |
| 06:30 | ddellacosta | doh, devn beat me to it |
| 06:30 | bamford | devn: assuming the dear reader knows \a == Ascii 97 ... |
| 06:30 | sdegutis | end is exclusive, bamford is right for (inc)ing it. |
| 06:30 | Anderkent | well |
| 06:30 | sdegutis | bamford: I like your solution best. |
| 06:30 | Anderkent | (seq "abcd...z") |
| 06:30 | Anderkent | :D |
| 06:30 | bamford | :) |
| 06:30 | Anderkent | ,(seq "abcdefghijklmnopqrstuwxyz") |
| 06:30 | clojurebot | (\a \b \c \d \e ...) |
| 06:30 | Anderkent | totally not error prone |
| 06:31 | sdegutis | Anderkent: ha |
| 06:31 | devn | heh |
| 06:31 | sdegutis | (inc Anderkent) |
| 06:31 | lazybot | ⇒ 4 |
| 06:31 | ddellacosta | actually, I agree w/sdegutis, it's nicer to see explicitly what you're ranging over |
| 06:31 | sdegutis | I'm *almost* done with my Clojure lexer (ignoring edge cases like weird numbers and stuff). |
| 06:31 | bamford | ok, thanks |
| 06:31 | Anderkent | yes, I prefer the (int \a) version too |
| 06:31 | sdegutis | All I have left is strings, and it's getting weird. |
| 06:32 | danlentz | with all parens there is no issue with mismatching and the structure is made clear by the indentation. clojure is convenient for brevity but some of the deterministic structuring of code is sacrificed and there is constant need to match what kind of delimiter you're closing. not a huge problem, but the idea that [] makes things easier is a little misguided, imo. But there are a lot of people who get turned off immediately when see |
| 06:32 | danlentz | )))))))))) so I appreciate that clojure is attempting to appeal to a wider audience. which is the whole point anyway. |
| 06:33 | devn | danlentz: https://github.com/Raynes/morphin |
| 06:33 | ddellacosta | danlentz: I think it's mostly the question of visual signaling, but it seems like you're talking about writing code |
| 06:33 | ddellacosta | danlentz: I feel like I get a very quick read with stuff like [] and {} so I can tell what I'm working with very easily. That said, I've never written CL or any other Lisp variant to the degree I've done Clojure, so it may totally be because I'm used to it. |
| 06:34 | devn | (morphin/range \a \z) |
| 06:34 | sdegutis | Man I'm hitting tons of 1-off errors. Thank goodness for these tests! |
| 06:34 | devn | where is marick to congratulate you? |
| 06:35 | devn | ;) |
| 06:35 | sdegutis | danlentz: paredit makes that a non-issue |
| 06:35 | sdegutis | devn: heh im using attest |
| 06:35 | sdegutis | its pretty crappy right now, needs lotsa fixin up |
| 06:35 | sdegutis | https://github.com/sdegutis/attest |
| 06:35 | danlentz | devn: the seq concept of clojure is fantastic. |
| 06:36 | devn | i love brian, fwiw, just having some fun because whenever someone takes something to an extreme, we owe it to the world to be critical |
| 06:36 | devn | danlentz: sure is :) |
| 06:36 | sdegutis | devn: ha, I love how he says "on a growing number of types" and there's like 2 |
| 06:37 | sdegutis | not that it isn't true, just unexpected |
| 06:37 | danlentz | well i'm sure at some point it was 1 :) |
| 06:37 | devn | he's a sly writer |
| 06:37 | ddellacosta | devn: you missed our conversation about Uncle Bob earlier, if you want to talk about extremes |
| 06:37 | devn | i have no interest in building a resume off of testing |
| 06:37 | devn | it's a valuable skill |
| 06:38 | ddellacosta | devn: agreed and agreed |
| 06:38 | devn | just not my area of interest |
| 06:38 | danlentz | did you guys see the posting of clojure v .000001a -- written in common lisp. just saying... |
| 06:38 | devn | heh, no i missed that |
| 06:38 | devn | if it's in CL then... what about JVM interop? |
| 06:38 | danlentz | i think it was on reddit. either in /r/lisp or /r/clojure |
| 06:39 | ddellacosta | what is .000001a (not sure I got the right # of 0s) |
| 06:39 | ddellacosta | ? |
| 06:39 | sdegutis | devn: I don't understand your resume comment. |
| 06:39 | danlentz | it was a very early prototype i don't know the real version |
| 06:39 | devn | sdegutis: oh, just that i dont have a desire to build a career on TDD or whatever |
| 06:39 | danlentz | and there is a full cl implementation with MOP that runs on jam -- abcl |
| 06:39 | ddellacosta | sdegutis: my interpretation was that "testing" being the defining feature of one's expertise is unappealing as a career strategy |
| 06:40 | sdegutis | danlentz: he should have named it Lava |
| 06:40 | ddellacosta | at least, that's my take |
| 06:40 | danlentz | jvm rather |
| 06:40 | devn | ddellacosta: that's the gist of it from my perspective, yeah |
| 06:40 | danlentz | maybe larvae might have been apropos |
| 06:40 | sdegutis | Ah. |
| 06:40 | ddellacosta | let me just take the opportunity to say that I hate writing CoffeeScript. |
| 06:40 | ddellacosta | that is all. |
| 06:41 | devn | i find the whole "everything is about testing" to be a worldview that is limiting, rather than freeing |
| 06:41 | devn | it's reductive |
| 06:42 | danlentz | writing good tests is more arduous than writing the code itself it seems to me a lot of times |
| 06:42 | ddellacosta | devn: I will say that TDD has proven itself to be a viable way for me to work through *some* design problems and provide nice regression tests simultaneously. I'm not saying it's the be-all end-all though. |
| 06:42 | devn | ddellacosta: it's especially rad when people ask you to write coffeescript when they don't know it |
| 06:42 | danlentz | and more arduous to maintain and manage |
| 06:42 | ddellacosta | devn: I don't know it either, is the problem |
| 06:42 | devn | ddellacosta: sure. no one is arguing there. i like to have good, informed tests, so i know whether or not im regressing |
| 06:42 | ddellacosta | danlentz: it can definitely be a challenge |
| 06:43 | ddellacosta | devn: yeah, mostly I was just stating that 'cause I think TDD has its place, and I think a lot of people take an either/or interpretation with it. The recent article by Alex Miller felt that way regarding TDD. |
| 06:43 | sdegutis | So, I'm finding myself just changing numbers randomly and hoping the test passes. This is probably a sign of poor design. |
| 06:43 | devn | but the cult of testing produces a lot of garbage |
| 06:43 | devn | which im apparently supposed to admire |
| 06:43 | ddellacosta | devn: regression tests, however, are pretty much unequivocally awesome and necessary, imho |
| 06:43 | sdegutis | On the other hand, "it's almost done I just need to make it pass then I'll never have to touch it again!" |
| 06:44 | ddellacosta | sdegutis: or it's a sign you're tired. |
| 06:44 | sdegutis | devn: I've seen great results and horrible results. Depends on who's doing it and how good they are at programming without tests. |
| 06:44 | sdegutis | ddellacosta: mayhaps |
| 06:44 | devn | "check out this sweet stubbed and mocked stub which is a mock that i stubbed with a mock and then asserted that the crap i put in is the crap i get out" |
| 06:44 | devn | ^---lots of ruby projects due to the cult of testing |
| 06:44 | danlentz | lein is really nice and test-is has been pretty easy to get along with so far. I don't want to ooh at the other testing libs so I won't get the wants for whatever cool features i don't know i'm missing... |
| 06:45 | devn | green tests, however silly, become a requirement |
| 06:45 | ddellacosta | devn: yes, to the n-thousandth degree, re: rails (specifically within ruby, which is not all that way) cult of testing |
| 06:45 | devn | patches will be accepted as long as they have tests, whether or not those tests matter |
| 06:45 | devn | marick had some comment on twitter the other day that got my blood boiling about ruby's superior testing culture |
| 06:45 | ddellacosta | even though I disagree with the way some people think about tests in the Clojure community, I *can* disagree without someone looking at me like I'm trying to poop on the floor |
| 06:46 | sdegutis | I have a seq of chars that make up "test\"ing" if you join them together, and I want to get the length of the whole string from it, which is 8, even though there are more chars after it. |
| 06:46 | danlentz | the spec english style testing seems ridiculous to me |
| 06:46 | devn | ruby's testing culture is like watching someone cut themselves |
| 06:46 | ddellacosta | hahaha |
| 06:46 | devn | then you hear talks about fast tests and what-not |
| 06:46 | devn | the quest for fast tests |
| 06:46 | devn | gee, i wonder why |
| 06:47 | ddellacosta | devn: I think some of it grows out of the insanity you can inflict with Ruby's object model, and finding ways to mitigate it…combined with a highly normative culture. |
| 06:47 | sdegutis | devn: some people are Rubyists at heart |
| 06:47 | devn | maybe because a lot of it is unecessary and indicative of poor design |
| 06:47 | devn | ddellacosta: fair assessment i think |
| 06:47 | sdegutis | At 8th Light they trained us in the ways of TDD before we were put on client projects. |
| 06:48 | devn | Rubyist at heart seems to mean a lot of copying and pasting for a living |
| 06:48 | ddellacosta | danlentz: kind of agree re: making tests into English. Breaks down quickly |
| 06:48 | sdegutis | They've got like 45 programmers now. |
| 06:48 | sdegutis | (Including apprentices.) |
| 06:48 | ddellacosta | sdegutis: it's probably helpful in some ways, but people also need to be able to develop outside of that paradigm. |
| 06:49 | devn | you can train TDD all day, but in my experience there is careful assesment that ought to take place with each line written in a changeset |
| 06:49 | sdegutis | ddellacosta: I'll withhold my opinion on TDD for now. |
| 06:49 | ddellacosta | sdegutis: damn, that sounds like there's something interesting there though... |
| 06:49 | devn | "do i care about testing this? what is the value? is this exercised elsewhere?" etc. |
| 06:49 | sdegutis | devn: I've found TDD leads to an alternative to that approach. |
| 06:50 | danlentz | there are some nice CL facilities that allow contract-driven development -- it is a very useful supplement/alternative to legions of small tests that must be independently written and maintained. |
| 06:50 | ddellacosta | devn, sdegutis: I think that TDD can provide some of the same benefits to that careful assessment. They are different methods for providing the same kind of focus on the problem at hand, if you are doing them right |
| 06:50 | sdegutis | Also I should stop communicating right now. Nothing's coming out right. |
| 06:50 | ddellacosta | sdegutis: I thought that last statement was right on |
| 06:50 | ddellacosta | (with caveats) |
| 06:50 | devn | sdegutis: i work at a TDD shop, but im about producing value first and foremost. value is a careful balance of maintainability, performance, and verifiability |
| 06:50 | ddellacosta | most def |
| 06:50 | sdegutis | ddellacosta: I meant that in practice, I've seen that TDD often seems to lead people away from the aforementioned approach. |
| 06:51 | danlentz | the idea comes from eiffel, but the cl implementation is really seamlessly integrated into the generic function metaclasses and is pleasant to use |
| 06:51 | sdegutis | (inc devn) |
| 06:51 | lazybot | ⇒ 9 |
| 06:51 | ddellacosta | sdegutis: oooh, whoops. haha |
| 06:51 | sdegutis | devn: where? |
| 06:51 | sdegutis | danlentz: in Clojure we have :pre and :post methinks |
| 06:51 | devn | I think Rich hit a nail on the head with his design, performance, and composition talk |
| 06:51 | ddellacosta | um, so, what is the inc <handle> thing? I'm embarrassed to say I still don't get it. |
| 06:51 | ddellacosta | devn: loved that one |
| 06:51 | sdegutis | ddellacosta: on IRC it's convention to do this when devn makes a good point: |
| 06:52 | sdegutis | devn++ |
| 06:52 | ddellacosta | devn: as a music guy originally with a special love for Coltrane though, I was a bit biased I think |
| 06:52 | sdegutis | ddellacosta: but that's C/C++ style, and we're Clojure |
| 06:52 | ddellacosta | sdegutis: gotcha! thanks. |
| 06:52 | devn | there's really a failure on lots of ruby projects where people lean on their iterative TDD testing strategy to provide insight into the larger design |
| 06:52 | devn | it rarely bears fruit though |
| 06:52 | ddellacosta | (inc devn) |
| 06:52 | lazybot | ⇒ 10 |
| 06:52 | ddellacosta | got it. |
| 06:52 | ddellacosta | ;-) |
| 06:52 | sdegutis | ddellacosta: also Raynes and amalloy_ et al. made clojurebot actually keep karma |
| 06:52 | sdegutis | $karma devn |
| 06:52 | lazybot | devn has karma 10. |
| 06:53 | sdegutis | (inc devn) |
| 06:53 | lazybot | ⇒ 11 |
| 06:53 | devn | heh |
| 06:53 | sdegutis | er I mean lazybot |
| 06:53 | ddellacosta | huh, I think I probably have 0 |
| 06:53 | ddellacosta | $karma ddellacosta |
| 06:53 | lazybot | ddellacosta has karma 0. |
| 06:53 | ddellacosta | heh |
| 06:53 | sdegutis | $karma sd |
| 06:53 | lazybot | sd has karma 0. |
| 06:53 | sdegutis | $karma sdegutis |
| 06:53 | lazybot | sdegutis has karma 1. |
| 06:53 | sdegutis | Oh nice. |
| 06:53 | sdegutis | $karma futile |
| 06:53 | lazybot | futile has karma 2. |
| 06:53 | sdegutis | Heh. |
| 06:53 | devn | anyway, i am not trying to hate on ruby, but the culture there, while it might be "more focused on testing" is broken |
| 06:53 | devn | the tests are to prevent stupid ideas from creeping in |
| 06:54 | danlentz | its called quid-quo-pro IIRC |
| 06:54 | devn | that's easy if you just..you know..sit down and think about what you're trying to accomplish |
| 06:54 | danlentz | quid-pro-quo rather |
| 06:54 | sdegutis | devn: I'll say that I agree that there are some cultural issues that lead to technical issues in the broader technical community as well as some subcommunities. |
| 06:55 | devn | sdegutis: there are issues with this in every community |
| 06:55 | ddellacosta | argh, now I have to figure out how to call a javascript function generated by coffeescript in clojurescript. WTF |
| 06:56 | devn | im just very much against calling the ruby community "exemplary" |
| 06:56 | devn | it's a total lie |
| 06:56 | sdegutis | devn: wait who says that? |
| 06:56 | devn | oh, this is going back to marick's tweet the other day |
| 06:56 | ddellacosta | devn: link? |
| 06:56 | sdegutis | Oh. He's *in* the Ruby community. That doesn't count. |
| 06:56 | devn | he claimed that ruby's testing culture was "strong" or some nonsense |
| 06:56 | ddellacosta | ah, gotta run. Ya'll take care. |
| 06:57 | devn | ddellacosta: ciao |
| 06:57 | devn | sdegutis: well, so am i |
| 06:57 | sdegutis | ddellacosta: cya |
| 06:57 | devn | but i have the sense not to make such a blanket assertion |
| 06:57 | sdegutis | You have to dismiss an active member of a community's opinion of that community. |
| 06:57 | danlentz | devn: well thats what happens when the barrier-to-entry means of assessing the value of a particular language is followed to the extreme |
| 06:58 | devn | danlentz: well said |
| 06:58 | sdegutis | devn: or maybe it's just blanket statements that we all know to dismiss. |
| 06:58 | cmdrdats | is there a better way to tranform a hashmap's values than something like (into {} (map (fn [[k v]] {k (f v)}) m))? |
| 06:58 | devn | sdegutis: if there's some kind of subliminal message or hidden "juicing" in order to get a rise and spark a discussion |
| 06:59 | devn | i find that distasteful |
| 06:59 | sdegutis | devn: did you say that to him on twitter? |
| 06:59 | devn | come to think of it, no |
| 06:59 | sdegutis | cmdrdats: that's the best way I know of |
| 06:59 | sdegutis | devn: try it |
| 06:59 | sdegutis | cmdrdats: actually yeah, use for instead |
| 07:00 | devn | sdegutis: he will reply either with something profound and topc-shifting |
| 07:00 | cmdrdats | sdegutis: (into {} (for [k v] {k (f v)})) ? |
| 07:00 | devn | topic* |
| 07:00 | sdegutis | cmdrdats: (into {} (for [[k v] m] [k (f v)])) |
| 07:00 | devn | or it will be an affirmation that i am correct, with no plan to change |
| 07:00 | devn | maybe the solution here is to just not follow him |
| 07:00 | devn | eureka. |
| 07:01 | sdegutis | devn: I just plain don't have a twitter anymore. |
| 07:01 | sdegutis | devn: So you know where I stand on this issue. |
| 07:01 | cmdrdats | sdegutis: ah, lol - forgot the m :) It just bugs me that I'm first creating a whole list, and then pushing into a map |
| 07:01 | sdegutis | cmdrdats: it's what you'd be doing anyway, since it's an immutable lang |
| 07:02 | sdegutis | cmdrdats: but to be fair, it's not that inefficient, with structural sharing and all that |
| 07:02 | sdegutis | probably lightning fast too, compared to Ruby 1.8 |
| 07:02 | sdegutis | *zing!* |
| 07:02 | devn | MRI |
| 07:02 | devn | "Matz' Ruby Interpreter" |
| 07:02 | devn | how do you ever convince people to use something named like that? |
| 07:03 | devn | a weak argument, but... man, that' like saying DIHMIHB |
| 07:03 | devn | Devn's Interpreter He Made In His Basement |
| 07:03 | sdegutis | devn: to be fair, nobody knows where Matz made that interpreter |
| 07:04 | devn | hahaha |
| 07:04 | sdegutis | devn: to be fair, Clojure is also a lame name compared to Lava |
| 07:04 | devn | Ruby 2.0 got a little bit better |
| 07:04 | sdegutis | (Lisp in Java) |
| 07:04 | devn | I'm just bored with Ruby. it's a big playground where you can do whatever you want. |
| 07:04 | cmdrdats | sdegutis: i suppose - I imagine (reduce (fn [a [k v]] (assoc a k (f v))) {} m) would be a bit more direct? |
| 07:05 | devn | Carmack's assertion that in any language, any and all syntactic variations in a sufficiently large codebase, will eventually find a home, seems correct |
| 07:05 | sdegutis | devn: it's an easy way to shoot yourself in the foot and not realize you're bleeding perfusely until after about 6 months |
| 07:05 | devn | Clojure makes it harder |
| 07:05 | devn | because the blood is real |
| 07:06 | cmdrdats | (time (doseq [x (range 1000000)] (hmap #(+ 10 %) {:n1 10 :n2 20 :n3 30}))) |
| 07:06 | cmdrdats | "Elapsed time: 2838.800182 msecs" |
| 07:06 | cmdrdats | (time (doseq [x (range 1000000)] (hmap2 #(+ 10 %) {:n1 10 :n2 20 :n3 30}))) |
| 07:06 | sdegutis | *and* to think you're a huge success during those 6 months and even move on to "bigger and better" opportunities |
| 07:06 | cmdrdats | "Elapsed time: 811.519061 msecs" |
| 07:06 | cmdrdats | hmap2 = reduce version |
| 07:07 | devn | sdegutis: yeah, totally true |
| 07:07 | devn | ive seen this a lot |
| 07:07 | devn | it's not a language thing, it's a people thing |
| 07:07 | devn | there needs to be a consistent amount of doubt cast on whatever has been done to-date |
| 07:07 | devn | not so much that it's toxic |
| 07:08 | devn | a healthy amount |
| 07:08 | sdegutis | Welp, about to pass out. |
| 07:08 | sdegutis | Gotta finish this string tokenizer. |
| 07:08 | devn | sdegutis: cheers |
| 07:08 | sdegutis | Then pass out. |
| 07:08 | TEttinger | sdegutis, more complex than clojure.string/split ? |
| 07:08 | sdegutis | TEttinger: kinda |
| 07:08 | devn | ["Then", "pass", "out", "."] |
| 07:09 | sdegutis | [\" \f \o \o \\ \" \space \b \a \r \" \space \q \u \u \x] |
| 07:09 | sdegutis | (f that) => 11 |
| 07:10 | sdegutis | Gimme f. |
| 07:10 | clgv | cmdrdats: better use criterium for a thorough measurement |
| 07:11 | TEttinger | ##(filter (partial not= "") (clojure.string/split "Then pass out." #"\b\s?")) |
| 07:11 | lazybot | ⇒ ("Then" "pass" "out" ".") |
| 07:11 | cmdrdats | clgv: thanks - i'll do that |
| 07:12 | sdegutis | or: (f [\" \a \\ \" \b \" \c]) => 6 |
| 07:12 | sdegutis | What's f? :) |
| 07:12 | clgv | cmdrdats: pro tip: put criteroium in your user profile in ~/.lein/profiles.clj ;) |
| 07:13 | cmdrdats | clgv: haha, thanks - good idea :) |
| 07:13 | TEttinger | sdegutis, I have no idea what that is supposed to do |
| 07:13 | sdegutis | Look for the second non-escaped double-quote and tell me what position it's at. |
| 07:14 | sdegutis | (first one is always at index 0) |
| 07:14 | TEttinger | isn't there a find function for sequences? |
| 07:15 | sdegutis | I should hope so. |
| 07:18 | TEttinger | ##(second (keep-indexed #(if (= %2 "\"") %1) [\" \f \o \o \\ \" \space \b \a \r \" \space \q \u \u \x])) |
| 07:18 | lazybot | ⇒ nil |
| 07:18 | TEttinger | hm |
| 07:18 | TEttinger | ##(second (keep-indexed #(if (= %2 \") %1) [\" \f \o \o \\ \" \space \b \a \r \" \space \q \u \u \x])) |
| 07:18 | lazybot | ⇒ 5 |
| 07:18 | TEttinger | sdegutis, does that do the trick? |
| 07:18 | sdegutis | :D |
| 07:19 | sdegutis | Thanks TEttinger. |
| 07:19 | TEttinger | no prob, glad to help |
| 07:20 | sdegutis | Phew, my lexer is done. |
| 07:21 | sdegutis | With many thanks to #clojure |
| 07:21 | sdegutis | (inc #clojure) |
| 07:21 | lazybot | ⇒ 6 |
| 07:28 | cmdrdats | clgv: criterium is awesome :) the reduce version is still somewhat faster |
| 07:29 | clgv | cmdrdats: which two versions did you compare? I did not read that before. |
| 07:29 | cmdrdats | (into {} (for [[k v] m] [k (f v)])) vs (reduce (fn [a [k v]] (assoc a k (f v))) {} m) |
| 07:29 | clgv | cmdrdats: you should try out reduce-kv |
| 07:30 | clgv | cmdrdats: and transients of course |
| 07:31 | clgv | cmdrdats: try that one (persistent! (reduce-kv (fn [a k v] (assoc a k (f v))) (transient {}) m)) |
| 07:32 | cmdrdats | hmm |
| 07:32 | cmdrdats | ClassCastException clojure.lang.PersistentArrayMap$TransientArrayMap cannot be cast to clojure.lang.Associative clojure.lang.RT.assoc (RT.java:702) |
| 07:32 | cmdrdats | seems a bit odd :P |
| 07:33 | cmdrdats | busy sampling wihout transient for now, I imagine there should be a bit of a speedup using reduce-kv, thanks :D |
| 07:34 | clgv | oh sorry. try assoc! |
| 07:34 | clgv | cmdrdats: try that one (persistent! (reduce-kv (fn [a k v] (assoc! a k (f v))) (transient {}) m)) |
| 07:34 | cmdrdats | aha, of course xD |
| 07:35 | cmdrdats | Execution time mean : 2.509337 µs for the into {} version |
| 07:35 | clgv | cmdrdats: happens to me in 50% of the cases where I switch to transients ;) |
| 07:35 | cmdrdats | Execution time mean : 802.129138 ns for normal reduce |
| 07:35 | cmdrdats | hehe |
| 07:35 | cmdrdats | Execution time mean : 343.686788 ns fore reduce-kv |
| 07:36 | cmdrdats | still sampling the transient version |
| 07:36 | cmdrdats | Execution time mean : 408.096108 ns transient |
| 07:36 | clgv | huh? how big is your map? |
| 07:37 | cmdrdats | oh, in this case, tiny |
| 07:37 | cmdrdats | there's a lot of them |
| 07:39 | clgv | usually transients pay off starting from a suprisingly small number of elements |
| 07:40 | TEttinger | clgv, I wasn't sure if when returns nil for false conditions |
| 07:40 | cmdrdats | clgv: I'll try slightly bigger maps |
| 07:40 | clgv | cmdrdats: I tried with 10 k-v-pairs |
| 07:41 | cmdrdats | i tried with 3 |
| 07:41 | cmdrdats | :P |
| 07:42 | clgv | non-transient 4.155826 us vs transient 3.225121 us |
| 07:44 | cmdrdats | non-transient 2.604713 ms vs transient 978.255599 µs |
| 07:44 | hhenkel | Hmm, calling (map keyword (clojure.string/split .....)) seems to give me clojure.lang.LazySeq which can't be processed with "get-in". Is my assumption correct? |
| 07:44 | cmdrdats | for maps with 5000 k-v's |
| 07:45 | cmdrdats | hhenkel: ye - get-in works through vectors, but not lists |
| 07:45 | ordnungswidrig | hhenkel: get-in is only for assocs |
| 07:45 | ordnungswidrig | vectors are associative, lists are not |
| 07:46 | ordnungswidrig | hhenkel: you can use nth |
| 07:46 | clgv | cmdrdats: `into` uses transients under the hood where possible |
| 07:47 | cmdrdats | clgv: cool, but it still needs the overhead of some kind of transformed list of k-v pairs |
| 07:47 | cmdrdats | clgv: that's where my intuition says it's slower |
| 07:47 | hhenkel | cmdrdats: ordnungswidrig: okay, so how to translate the list to a vector then? I don't understand how nth would help me here? |
| 07:47 | clgv | cmdrdats: in your case you had a lazy-seq and the overhead of the k-v-pairs and destructuring |
| 07:48 | ordnungswidrig | ,(nth '(1 2 3 4 5) 4) |
| 07:48 | clojurebot | 5 |
| 07:48 | hhenkel | Or is it better to use something different then map? |
| 07:48 | cmdrdats | clgv: ye |
| 07:48 | cmdrdats | hhenkel: you can (vec (map …)) if you really need to use get-in |
| 07:48 | ordnungswidrig | hhenkel: ,(nth (map keyword ["foo" "bar" "baz"]) 2) |
| 07:49 | ordnungswidrig | ,(nth (map keyword ["foo" "bar" "baz"]) 2) |
| 07:49 | clojurebot | :baz |
| 07:49 | cmdrdats | ~botsnack |
| 07:49 | clojurebot | botsnack is newline |
| 07:50 | hhenkel | ordnungswidrig: my idea was to split a string and use the parts I get as keywords to look something up with get-in. |
| 07:51 | cmdrdats | clgv: thanks for your help :) |
| 07:51 | hhenkel | I see how vec would help me there but I don't get it how returning one specific value with "nth" would help me here. |
| 07:51 | ordnungswidrig | what is the "key" for lockup? An numerical index? |
| 07:52 | hhenkel | ordnungswidrig: it is a keyword in a nested datastructure (tree with keys (keywords) and values (string or longs) |
| 07:52 | clgv | cmdrdats: your welcome |
| 07:53 | clgv | *are ;) |
| 07:53 | ordnungswidrig | hhenkel: where does (map keyword ...) into play? |
| 07:56 | hhenkel | ordnungswidrig: I got a string somewhere in the tree, it is something like ${level1.level2.value12} and points to a value in the same tree. I want to fetch it and replace the "variable string" with the actual values. |
| 07:57 | hhenkel | ordnungswidrig: therefore I split strings that match that form at the dot and then use "map keyword" to use these parts to address the keywords. |
| 07:57 | hhenkel | I thought it would be a good idea to "translate" the strings to keywords. |
| 07:58 | ordnungswidrig | hhenkel: ah, so you need (get-in tree (map keyword (split ...))) |
| 07:58 | hhenkel | so the described "variable" points to something like {:level1 {:level2 {:value12 "Test-Text"}}} for example. |
| 07:59 | hhenkel | ordnungswidrig: yes, I got (get-in collection (map keyword (clojure.string/split (clojure.string/replace variable-string #"\$\{(.*)\}" "$1") #"\.")))) |
| 08:00 | ordnungswidrig | like that, yes. |
| 08:01 | hhenkel | But it allways gives me nil or a null pointer exception and I don't fully understand why not the "real" value is set. |
| 08:01 | ordnungswidrig | is collection a sequence or a map? |
| 08:02 | hhenkel | map |
| 08:03 | ordnungswidrig | hhenkel: do you know how to use trace? |
| 08:03 | ordnungswidrig | hhenkel: I think that would be helpful here |
| 08:03 | hhenkel | I first thought the variable points to the wrong part and the actual value is not found but I tested that and it seems to work. I tried to catch the exception.... |
| 08:03 | hhenkel | ordnungswidrig: Nope, but I'm willing to learn. |
| 08:04 | ordnungswidrig | hhenkel: second, how do you want to handle transient dependencies? like {:a "${b}" :b "${c}" :c "foo"}? |
| 08:04 | hhenkel | ordnungswidrig: Any docs you recommend? Or a short introduction? |
| 08:04 | ordnungswidrig | https://github.com/clojure/tools.trace |
| 08:04 | ordnungswidrig | wrap any form with (trace) and get some nice trace output, like (get-in collection (trace "keys" (map keyword (split ...)))) |
| 08:05 | ordnungswidrig | so you can see the intermediate results |
| 08:05 | hhenkel | ordnungswidrig: currently I just ignore them...in the longterm maybe multiple runns. |
| 08:05 | hyPiRion | What is #"\$\{(.*)\}" supposed to match, anyway? |
| 08:05 | Anderkent | hhenkel: I'd assume your splitting is wrong :) |
| 08:05 | hyPiRion | oh derp. |
| 08:06 | Anderkent | because the get should work |
| 08:06 | hyPiRion | This is why I need coffee in the morning. |
| 08:06 | Anderkent | ,(get-in {:a {:b {:c :d}}} (map keyword ["a" "b" "c"])) |
| 08:06 | clojurebot | :d |
| 08:07 | hyPiRion | oh riiight |
| 08:07 | hyPiRion | hhenkel: ##(clojure.string/replace "${a}.${b}.${c}" #"\$\{(.*)\}" "$1") |
| 08:07 | lazybot | ⇒ "a}.${b}.${c" |
| 08:07 | hyPiRion | versus ##(clojure.string/replace "${a}.${b}.${c}" #"\$\{(.*?)\}" "$1") |
| 08:07 | lazybot | ⇒ "a.b.c" |
| 08:08 | hyPiRion | I make no sense today, ignore me for 15 minutes |
| 08:08 | hhenkel | hyPiRion: plan is to have only ${test.test1} |
| 08:09 | hyPiRion | yeah, I realized in hindsight |
| 08:11 | ordnungswidrig | hhenkel: (if-let [path (re-matches #"\${.*}" expr)] (get-in collection (map keyword (clojure.string/split path #"\.")))) |
| 08:11 | hhenkel | ordnungswidrig: trace is really helpful....seems like it is working as expected... |
| 08:11 | Anderkent | hhenkel: I'd expect you're getting back a nil because the keyword chain does not exist in the map |
| 08:11 | ordnungswidrig | hhenkel: aah, add path as else clause |
| 08:11 | Anderkent | but it's hard to say without seeing all of your code |
| 08:11 | ordnungswidrig | (if-let [path (re-matches #"\${.*}" expr)] (get-in collection (map keyword (clojure.string/split path #"\."))) expr) |
| 08:12 | ordnungswidrig | so the expr is returned unless the re matches |
| 08:12 | hhenkel | TRACE keys: {:cycle 3600, :action "read", :mbean "java.lang:type=OperatingSystem", :attribute "FreeSwapSpaceSize", :option "ignoreErrors=true"} |
| 08:12 | Anderkent | you want .+ |
| 08:12 | hhenkel | Is what I get when I add trace in front of the get-in |
| 08:12 | Anderkent | right, and what's the string you're trying to look up? |
| 08:12 | Anderkent | ${cycle} or sth like that? |
| 08:13 | Anderkent | wait, that trace is your collection, not the keys, right? |
| 08:14 | hhenkel | Anderkent: Nope, that is the actual result. I would like to replace the string value with all of that if possible. There are two possible cases string replaced by string or string replaced by datastructure. |
| 08:15 | hhenkel | Anderkent: actually it is result not collection or keys, by accident I putted it up in front and forget to rename it - and was surprised seeing the values I was looking for. |
| 08:15 | Anderkent | right, so it seems that bit is working |
| 08:16 | Anderkent | this will be much easier if you post your code to refheap with an example of what gives you nil/npe |
| 08:18 | hhenkel | https://www.refheap.com/18356 contains the whole mess... ;) |
| 08:20 | fredyr | ,(keyword (str '- (aget (Character/toChars 80) 0))) |
| 08:20 | clojurebot | :-P |
| 08:21 | Anderkent | hhenkel: right, you can't use clojure.string/replace with non-string values |
| 08:21 | Anderkent | ,(clojure.stirng/replace "foo" "f" {:a 1}) |
| 08:21 | sheldonh | does clojure have a fold function? |
| 08:21 | clojurebot | #<ClassNotFoundException java.lang.ClassNotFoundException: clojure.stirng> |
| 08:21 | Anderkent | ,(clojure.string/replace "foo" "f" {:a 1}) |
| 08:21 | clojurebot | #<ClassCastException java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to java.lang.CharSequence> |
| 08:22 | Anderkent | ,(clojure.string/replace "foo" #"f" {:a 1}) |
| 08:22 | clojurebot | #<NullPointerException java.lang.NullPointerException> |
| 08:22 | Anderkent | you just want to return (get-value collection %) instead of putting it to clojure.string/replace |
| 08:23 | Anderkent | sheldonh: reduce is foldl I think |
| 08:23 | hhenkel | Anderkent: I get a NullPointerException java.util.regex.Matcher.quoteReplacement |
| 08:23 | Anderkent | hhenkel: as I said. (clojure.string/replace % ... (get-value ...)) makes no sense |
| 08:24 | hhenkel | I'll test with just returning... |
| 08:24 | Anderkent | clojure.string/replace is for replacing parts of a string with something else, you just want to return the new object instead of the original stirng |
| 08:24 | Anderkent | and of course you must return the old one if you're not changing it |
| 08:25 | Anderkent | sheldonh: also, reducers have fold, and it's potentially parallel |
| 08:26 | Anderkent | it's a little different than reduce |
| 08:28 | hhenkel | Anderkent: you're right...now it works...seems like I'm still to much into "altering defined variables" instead of having functions returning the right stuff... |
| 08:30 | Anderkent | hhenkel: yes, you can't alter anything in clojure :) clojure.stirng/replace also doesnt alter anything, just gives you a new string back |
| 08:30 | Anderkent | (well ok, the you can't alter anyhting is not *quite* true) |
| 08:30 | Anderkent | the walk function already does the 'replacing' for you, that's why you have to return the original value if you dont want to replace anything |
| 08:35 | sheldonh | Anderkent: hmmm. maybe not fold. i want to traverse a list with a function that takes successive pairs of elements, returning the first logical true value |
| 08:36 | sheldonh | definitely not fold :) |
| 08:37 | Anderkent | is that 'takes a vector of 2 elements' or 'takes 2 arguments'? |
| 08:39 | Anderkent | for the first, you want (some my-condition-fn (partition my-collection 2 1)) |
| 08:39 | sheldonh | Anderkent: i could live with either (it's a cheap transform). if filter is lazy and first is lazy, then it's just a partition |
| 08:40 | sheldonh | first calls seq on its argument. that means it doesn't defeat laziness, right? |
| 08:40 | Anderkent | for the second it's more like (first (filter identity (map my-fn collection (next collection)))) |
| 08:40 | Anderkent | seq realizes lazyseqs |
| 08:41 | sheldonh | oh dear |
| 08:41 | sheldonh | that's crazy. how do i get the head of a lazy sequence without realizing it? |
| 08:41 | Anderkent | sosrry, I mean seq realizes the first element |
| 08:42 | sheldonh | phew |
| 08:42 | Anderkent | ,(let [foo (take 5 (repeatedly #(do (println "boo") 1)))] (println "foo") (let [bar (seq foo)] (println "bar"))) |
| 08:43 | clojurebot | foo\nboo\nbar\n |
| 08:43 | Anderkent | that's less useful than it was in my head ;_; |
| 08:43 | sheldonh | Anderkent: okay, then all is well. not exactly what i asked, but https://www.refheap.com/18357 |
| 08:43 | sheldonh | Anderkent: you just described everything i ever typed :) |
| 08:43 | Anderkent | argh |
| 08:44 | sheldonh | Anderkent: that's always what you want to hear after a crack a 4clojure. "argh" :) |
| 08:44 | Anderkent | i think you just want to use reduce there :P enumerating all subsequences is... suboptimal |
| 08:44 | Anderkent | :P |
| 08:45 | sheldonh | Anderkent: i deleted (i think) 3 reduce-based attempts. maybe after a break :) |
| 08:45 | Anderkent | the basic algorithm shuold be: for each element, if it's larger than previous one, append it to 'current subseq'. If not, check if 'current subseq' is longer then 'longest seen subseq', if so save it as longest seen subseq |
| 08:45 | clgv | Anderkent: but gets a good golfing score ;) |
| 08:45 | Anderkent | alternatively |
| 08:45 | Anderkent | take it in two steps |
| 08:45 | Anderkent | first, split it into increasing subsequences |
| 08:45 | Anderkent | then find which one is longest |
| 08:46 | Anderkent | obviously they can't overlap, so this should be simple |
| 08:46 | sheldonh | i thought that's what my for/partition did |
| 08:46 | Anderkent | no, you generate all subsequences then check which of them are increasing |
| 08:47 | sheldonh | that is true. i was hoping, though, that since i start with the longest subsequence, i would only test for increasingness (and so realize) as many as absolutely necessary |
| 08:48 | sheldonh | anyway, it felt like a reduce problem when i started, and i should totally take another shot at it once my circulation returns to normal :) |
| 08:49 | sheldonh | "what do i do if i come up nil?" was a smell. it should have taken me back to the initial value for reduce (since 4clojure wants [], not nil) |
| 08:53 | sheldonh | Anderkent: the real pig in that exercise is that the minimum eligible subsequence length is 2 |
| 08:59 | clgv | sheldonh: ##(or nil []) |
| 08:59 | lazybot | ⇒ [] |
| 08:59 | clgv | ;) |
| 09:03 | sheldonh | clgv: yeah, that's what i did. but usually when i have to do that at the outermost layer, my design sucks :) |
| 09:03 | Anderkent | tbh I think the nicest solution to this is either reduce or loop/recur |
| 09:04 | clgv | well 4clojure encourages code golfing ;) |
| 09:05 | clgv | that way you'll often end up with solutions you should not use in projects |
| 09:05 | Anderkent | I'm not familar with that term |
| 09:05 | clgv | "trying to get the smallest solution in terms of character count" |
| 09:06 | Anderkent | ah |
| 09:06 | Anderkent | I went the opposite direction |
| 09:06 | clgv | there is a chart where you can see where your solution landed after you completed the excercise |
| 09:06 | Anderkent | 'write a solution that's actually easy to understand' :P |
| 09:06 | clgv | shortest runtime would be a nice contest as well |
| 09:06 | sheldonh | i start with "write a solution that goes green". that is usually enough of an achievement :) |
| 09:07 | clgv | too many people already have all solutions solved. I didnt do 4clojure since a long time and almost dropped out of the top100... |
| 09:10 | borkdude | How can I turn of the fancy f displaying in emacs? |
| 09:10 | borkdude | for example, it displays incorrectly when I type #_ |
| 09:11 | Anderkent | (remove-hook 'clojure-mode-hook 'esk-pretty-fn) |
| 09:11 | Anderkent | says stack overflow |
| 09:23 | mathiasp | Hi all, I'm trying to use shoreleave-remote with a non-default uri inside a go block. Sadly, rebinding shoreleave.remotes.http-rpc/*remote-uri* shows no effect inside a go block - it works just fine outside it. See my small experiment here https://gist.github.com/mathiasp/6448753 The call to shoreleave in line 45 succeeds, the one in line 32 tries in vain to reach the standard /_shoreleave url. Any ideas how I can further investigate this? |
| 09:23 | mathiasp | I'm a clojure novice, so maybe, hopefully I've forgotten something simple? |
| 09:26 | TEttinger | mathiasp, it's an unfortunate time of day right now, but soon people will be more active I think. has to do with time zones. |
| 09:26 | Anderkent | mathiasp: looking at it, but don't get your hopes up :) |
| 09:26 | mathiasp | TEttingen, thanks, I assumed so, it's not really urgent. Thanks for looking! |
| 09:27 | clgv | mathiasp: that's because your `binding` exist only when you define those functions in its body and not at runtime |
| 09:28 | Anderkent | clgv: well, the go should run within the binding |
| 09:28 | clgv | mathiasp: "runtime" = when your functions are called |
| 09:28 | clgv | oh the `go` is not in the function? |
| 09:28 | sheldonh | bwahahahaha! i just evalled my code to examine the data structure my first stab produces, and it turns out the function's done! |
| 09:28 | Anderkent | yeah it's a top level loop afaik |
| 09:28 | clgv | is that on purpose? |
| 09:29 | clgv | the other rpc call is in a function |
| 09:29 | ToxicFrog | Aren't dynamic (binding)s threadlocal? |
| 09:29 | Anderkent | I believe it's just ment to be a continuously running listener |
| 09:30 | Anderkent | ToxicFrog: yes, but core.async carries your bindings with you |
| 09:30 | ToxicFrog | Aah. |
| 09:30 | clgv | I'd rewrite that with a startup function... |
| 09:30 | ToxicFrog | Oh, and this is cljs. I've got nothing. |
| 09:30 | clgv | ToxicFrog: threadlocal bindings are inherited to child threads as initial values |
| 09:31 | clgv | oh right. no idea if there is some non-standards cljs-thing at work^^ |
| 09:31 | Anderkent | https://www.refheap.com/18359 seems to imply the bindings work |
| 09:31 | Anderkent | but don't know about cljs obviously |
| 09:31 | julienXX | Hi I'm having trouble with something really trivial. I'd like to replace the first "[" in a string with "\[". What would be the best way to do it? |
| 09:32 | julienXX | str/replace complains with "Unsupported escape character: \[" |
| 09:32 | Anderkent | julienXX: you need to escape the backslash, i.e. "\\[" |
| 09:32 | clgv | julienXX: "\\" |
| 09:33 | Anderkent | hm |
| 09:33 | Anderkent | actually |
| 09:33 | Anderkent | doesn't seem to work the way I thought it would |
| 09:33 | Anderkent | ouch, painful |
| 09:34 | julienXX | Anderkent clgv thanks! |
| 09:34 | Anderkent | ,(print (clojure.string/replace "foo[bar" #"\[" (clojure.string/re-quote-replacement "\\["))) |
| 09:34 | clojurebot | foo\[bar |
| 09:34 | Anderkent | ,(print (clojure.string/replace "foo[bar" #"\[" #"\\\[")) |
| 09:34 | clojurebot | #<ClassCastException java.lang.ClassCastException: java.util.regex.Pattern cannot be cast to clojure.lang.IFn> |
| 09:34 | Anderkent | hm oups |
| 09:35 | Anderkent | ,(print (clojure.string/replace "foo[bar" #"\[" "\\\\[")) |
| 09:35 | clojurebot | foo\[bar |
| 09:35 | Anderkent | right |
| 09:36 | Anderkent | that's... pretty awful |
| 09:44 | Anderkent | mathiasp: sorry, no idea. If you can reduce it to a minimal example (one dynamic variable being bound in different places, I assume) that doesn't work on cljs, you could check if it also doesnt work in normal clojure |
| 09:45 | Anderkent | if it does work, it's a cljs async bug, otherwise it might be something in your code |
| 09:47 | mathiasp | clgv, Anderkent, ToxicFrog: thanks for the ideas, I created a function making the rpc insde the binding, and called that within the go block, now it works fine. |
| 09:47 | mathiasp | I have no idea why, though ;) |
| 09:49 | clgv | mathiasp: having a start funciton for that `go` block is cleaner anyway |
| 09:50 | mathiasp | clgv: I really don't know what you mean by the start function for the go block... |
| 09:51 | clgv | mathiasp: oh, I misread you. you just moved binding and rpc into the function... |
| 09:51 | mathiasp | jep |
| 09:52 | mathiasp | clgv: and it's ok for now, this will probably be throwaway code, running just for a few days or so. Good enough for now. Again, thanks! |
| 10:02 | mathiasp | cglv: if you thought of something like this, it still doesn't work. And just for my understanding of go blocks: this should work, shouldn't it? https://gist.github.com/mathiasp/6450181 |
| 10:03 | clgv | mathiasp: well maybe bindings in cljs work differently with go blocks or there is a bug |
| 10:03 | Anderkent | mathiasp: can you make an example that just prints from a dynamic variable? It's hard to tell because we don't know what srm does. |
| 10:03 | clgv | mathiasp: might be worth a mailing list post |
| 10:04 | mathiasp | clgv: ok, will do |
| 10:06 | Anderkent | mathiasp: does https://www.refheap.com/18361 work for you? |
| 10:11 | gdev | ,(let [slash (char-escape-string \\) re-bracket #"\[" ] (print (clojure.string/replace "foo[bar" re-bracket (str slash "\[")))) |
| 10:11 | clojurebot | #<RuntimeException java.lang.RuntimeException: Unsupported escape character: \[> |
| 10:11 | gdev | ,(let [slash (char-escape-string \\) re-bracket #"\[" ] (print (clojure.string/replace "foo[bar" re-bracket (str slash \[)))) |
| 10:11 | clojurebot | foo\[bar |
| 10:17 | gdev | ,(let [slash (char-escape-string \\) re-bracket #"\[" bracket \[ target "foo[bar" replacement (str slash bracket)] (print (clojure.string/replace target re-bracket replacement))) |
| 10:17 | clojurebot | foo\[bar |
| 10:17 | gdev | well that was a fun little exercise |
| 10:20 | gdev | I've been trying to convert Sussman's scheme code to Clojure all morning so a string replace problem was a lot easier |
| 10:23 | mathiasp | clgv: very funny, even though I've refer'd it, I get [15:57:35.070] TypeError: cljs.core.async._GT__BANG__BANG_ is undefined @ http://localhost:8080/opnenablement/javascripts/opnenablement.js:31887 |
| 10:24 | Anderkent | >31887 |
| 10:24 | Anderkent | :D |
| 10:24 | Anderkent | :D |
| 10:24 | mathiasp | clgv: I have to go now, will look into this later... |
| 11:00 | no7hing | what am i doing wrong when (map #(str "A" %) (range 1 (:a entry))) gets serialised as lazyseq when spitting to a file? doall didn't help.. |
| 11:01 | sdegutis | no7hing: map is lazy. |
| 11:01 | sdegutis | ,(doc map) |
| 11:01 | clojurebot | "([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & ...]); Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments." |
| 11:01 | sdegutis | no7hing: You have to realize it via doall, but a better solution is to just use doseq. |
| 11:01 | no7hing | doesn't do all force it? |
| 11:01 | sdegutis | ,(doc doseq) |
| 11:01 | clojurebot | "([seq-exprs & body]); Repeatedly executes body (presumably for side-effects) with bindings and filtering as provided by \"for\". Does not retain the head of the sequence. Returns nil." |
| 11:02 | sdegutis | Actually let me stop giving advice, I have a baby in my lap that's kicking my desk and shaking things, and that's distracting enough to let me give wrong answers. |
| 11:02 | clgv | no7hing: what is your goal? |
| 11:02 | hyPiRion | no7hing: use pr-str instead of str |
| 11:03 | no7hing | i want a list of strings that then get used in a (format "…" ..) |
| 11:03 | no7hing | ah |
| 11:03 | mathiasp | Anderkent, cglv: the test case does not work (e.g. shows OUPS BAD ASYNC). I've put this on the mailing list. |
| 11:03 | sandbags | afternoon |
| 11:03 | hyPiRion | you can also wrap it in a `(seq ...)` before str-ing it |
| 11:05 | clgv | no7hing: example function call and expected output? |
| 11:12 | no7hing | kind of embarrassing but the seq was wrapped in another seq as there was still a left-over '&' in the function arguments |
| 11:12 | no7hing | thanks for helping |
| 11:33 | sdegutis | Given [\a \b \c] what's an efficient way to create a string from it? |
| 11:33 | sdegutis | I bet there's something smarter than (apply str coll). |
| 11:35 | clgv | sdegutis: (apply str coll) is pretty good since it uses stringbuilder internally which is the fastest way to build strings on the jvm |
| 11:35 | sdegutis | clgv: oh nice :) |
| 11:38 | sdegutis | Thans |
| 11:38 | sdegutis | Thanks |
| 11:38 | clgv | np |
| 11:44 | sdegutis | Whoa, the JVM must be doing cool stuff, cuz when I run my benchmarks multiple times in a row, it goes from 9msec to 3msec in about 5 iterations and stays at 3msec pretty consistently thereafter. |
| 11:44 | rigger | yeah, called warming up the vm |
| 11:45 | sdegutis | Ah I've heard of that. |
| 11:45 | rigger | JIT |
| 11:46 | gdev | the JVM runs on diesel |
| 11:46 | rigger | http://4groundtechsolutions.com/jvm-warmup/ |
| 11:46 | sdegutis | My only experience with Java or JVM before using Clojure was ranting that Java's stupid and Ruby's better. |
| 11:47 | gdev | sdegutis, common mistake lumping the language and the VM in the same basket |
| 11:47 | hhenkel | There is a reason why the call it hotspot jvm... |
| 11:47 | nDuff | sdegutis: Heh. Whereas I've seen folks using Ruby in large-scale production abandon it for Erlang due to issues with the Ruby VM. |
| 11:48 | sdegutis | nDuff: :D |
| 11:48 | sdegutis | nDuff: Elixir? |
| 11:48 | nDuff | sdegutis: Opscode's big rewrite of the Chef server for 0.11 |
| 11:48 | sdegutis | That'd seem less random :) |
| 11:48 | sdegutis | nDuff: ah |
| 11:48 | sdegutis | We're using Chef. But I've heard good things about ansible, have to look into it.. |
| 11:49 | sdegutis | Ok time to do some premature optimization. |
| 11:49 | sdegutis | I bet (partition 2 1 [:end] string) is probably much slower than just using loop/recur with an index. |
| 11:52 | callen | sdegutis: you're supposed to use things like criterium for benchmarking for a reason. |
| 11:52 | callen | it warms the JIT and is very meticulous about it in order to get accurate benchmarks. |
| 11:52 | sdegutis | callen: Oh. Nice. I'll look into that. |
| 11:53 | sdegutis | Yep looks perfect. Thanks callen. |
| 11:55 | gdev | dgrnbrg, saw your talk on piplin, looks interesting |
| 11:55 | rigger | url? |
| 11:55 | clojurebot | something |
| 11:56 | clgv | &(let [... 42] ...) |
| 11:56 | lazybot | java.lang.ClassFormatError: Illegal field name "..." in class sandbox91102$eval133977 |
| 11:56 | hyPiRion | ,(let [… 42] …) |
| 11:56 | clojurebot | 42 |
| 11:56 | clgv | but lazybot is right ;) |
| 11:56 | callen | rigger: http://www.infoq.com/presentations/piplin?utm_source=dlvr.it&utm_medium=twitter |
| 11:56 | rigger | thx |
| 11:57 | clgv | &(clojure-version) |
| 11:57 | lazybot | ⇒ "1.4.0" |
| 11:57 | callen | rigger: could always google. |
| 11:57 | clgv | ,(clojure-version) |
| 11:57 | clojurebot | "1.6.0-master-SNAPSHOT" |
| 11:57 | callen | because, you know, that's what I did. |
| 11:57 | clgv | ui |
| 11:57 | hyPiRion | clgv: psh |
| 11:57 | hyPiRion | &(let [… 42] …) |
| 11:57 | lazybot | ⇒ 42 |
| 11:57 | rigger | callen, not sure dgrnbrg piplin would have yielded much |
| 11:57 | xeqi | sdegutis: +1 for criterium when benchmarking. Also be careful of lein's default options for faster startup / less optimization |
| 11:58 | rigger | ah, nm, thanks anyway |
| 11:58 | clgv | hyPiRion: :P |
| 11:58 | callen | rigger: ...yeah...yeah it would've. |
| 11:58 | rigger | oh shit, this is cool |
| 11:59 | rigger | dgrnbrg: you work in the hardware industry? |
| 11:59 | rigger | researchmethodologist |
| 11:59 | rigger | hmm |
| 12:00 | rigger | we wrote a dsl in python for describing memories |
| 12:01 | rasmusto | I need to try piplin, I said I would after I the talk... |
| 12:01 | rasmusto | But I ended up rolling my own libraries instead |
| 12:04 | Balveda | Where can I learn to engineer software using Clojure? I can't wrap my head around structuring a program in it yet |
| 12:06 | rigger | be curious to see how this scales against RTL |
| 12:07 | coventry | Balveda: Pick a project in a rough approximation to your problem domain, and read the source code for it. If you can't find anything related, the clojure source itself is pretty representative. |
| 12:07 | rkneufeld | Balveda: I'd say probably similarly to other disciplines: Read other people's functional software and practice. |
| 12:07 | rkneufeld | coventry: As best I know the Clojure source itself is not always recommended reading for idiomatic Clojure. Tread with care ;) |
| 12:08 | Balveda | Coming from a Java/C++/C# background Clojure is so weird but it calls out to me. |
| 12:08 | Balveda | Is that weird? Am I going nuts? |
| 12:09 | clgv | Balveda: books are a good start. |
| 12:09 | nDuff | Balveda: It takes a while to wrap your head around FP after spending that much time in OO land. It's well worth it, though. |
| 12:09 | nDuff | Balveda: If you haven't read Joy of Clojure, I recommend it. |
| 12:09 | clgv | better start with "Clojure Programming" and then read "Joy of Clojure" after that ;) |
| 12:09 | hyPiRion | It's hard to program stuff in the beginning, but it comes easier with practise |
| 12:10 | hyPiRion | it's not only a new language, you have all the different new concepts |
| 12:10 | sdegutis | xeqi: cool |
| 12:10 | dgrnbrg | rigger: hey! |
| 12:10 | sdegutis | Balveda: what about it calls out to you? |
| 12:10 | rigger | howdy |
| 12:10 | dgrnbrg | rigger: I work at a hedge fund, and in school and in the past I worked on hardware/low latency systems |
| 12:11 | coventry | Repeating my question from last night, anyone know why catch, finally and "&" have null entries in the clojure.lang.Compiler/specials dispatch map, and what that means for the analysis of those forms? |
| 12:11 | dgrnbrg | now, I'm doing large scale distributed systems |
| 12:11 | rigger | dgrnbrg: i'm a design tools guy at AMD |
| 12:11 | dgrnbrg | rigger: cool! |
| 12:11 | dgrnbrg | I have been thinking a lot about pipline recently |
| 12:11 | Balveda | It just seems right, sdegutis. |
| 12:11 | sdegutis | Balveda: why? |
| 12:11 | sdegutis | Balveda: or in what way? |
| 12:11 | dgrnbrg | since I used a model of time in piplin that makes sense for very low level abstractions |
| 12:12 | dgrnbrg | but I think that core.async is a great basis for concurrent hardware development |
| 12:12 | dgrnbrg | I've been designing the next version of piplin, that'll be even closer to clojure's semantics, because core.async makes modules better to express |
| 12:12 | Balveda | Hard to say. I guess the syntax, the REPL and potential to overcome everything else. And even tough I barely started I feel eventually one could be very productive, very quickly with it. |
| 12:12 | coventry | Oh, I get it now. They are all subordinate forms to other special forms, which handle them directly without the need for dispatch. |
| 12:12 | rigger | we "replaced" six guys writing skil code for memories with a python dsl and compiler |
| 12:13 | rigger | so the design engineers are now just constructing the design in the dsl, run it through the compiler (still generating skil), but saves a ton of time |
| 12:14 | dgrnbrg | that sounds awesome! is it myhdl, or something custom? |
| 12:14 | rigger | it's home grown |
| 12:14 | rasmusto | rigger: skil? |
| 12:14 | rigger | skill |
| 12:14 | rigger | from Cadence |
| 12:15 | rigger | very lispy |
| 12:15 | rasmusto | rigger: ah, will have to check it out. |
| 12:15 | sdegutis | Balveda: ah, cool, I know the feeling |
| 12:16 | Balveda | I'm going to be working in automatized QA so I want to incorporate the language, as well |
| 12:17 | Balveda | I've been trying out clj-webdriver and it seems good, trying things out in the console is just a blast. |
| 12:17 | Balveda | in the REPL, sorry. heh. |
| 12:19 | sdegutis | :) |
| 12:19 | sdegutis | Exciting times. |
| 12:22 | sdegutis | What's a fast way to find the first occurrence of a char that's not in a given set, within a string, starting at an index? |
| 12:22 | sdegutis | Like, given "abc " I want to find the index of the first non-alphanum char starting at 0 which would return 3 |
| 12:24 | sdegutis | Maybe regex is the fastest way after all. |
| 12:25 | functionform | whoever dbyrne is (4clojure.com) thank you for blowing my mind. i'm always surprised at how much i learn from doing one of his "easy" problems |
| 12:25 | hyPiRion | ,(let [matcher (.matcher #"[^A-Za-z]" "abc ")] (if (.find matcher) (.start matcher))) |
| 12:25 | clojurebot | 3 |
| 12:26 | hyPiRion | well, that was just alpha, you could probably guess how to add in nums |
| 12:26 | justin_smith | functionform: my theory is that David Byrne has given up pop-world-beat for computer science |
| 12:26 | justin_smith | hyPiRion: aren't there unicode friendly character classes? |
| 12:27 | hyPiRion | justin_smith: sure thing, I just randomly grabbed the thing I already knew |
| 12:27 | sdegutis | hyPiRion: ok then I'll stick with regex for now. |
| 12:27 | sdegutis | Thanks. |
| 12:27 | justin_smith | \w is "word constituent", should catch things like ü (had to look it up just now, but I knew it existed) |
| 12:28 | justin_smith | oh, never mind |
| 12:28 | justin_smith | ,(re-find #"\w" "ü") |
| 12:28 | clojurebot | nil |
| 12:28 | justin_smith | ,(re-find #"\w" "u") |
| 12:28 | clojurebot | "u" |
| 12:29 | justin_smith | maybe there is a locale setting that affects these things? |
| 12:30 | grandy | question: i want to take a map of keywords and regexes, and apply the regexes in succession to a long string, and return a map of the keywords to the parts of the string matched by each regex ... the reason for the ordered application of regexes is to remove ambiguity from the string... any recommendations for idiomatic clojure ways to write this ? |
| 12:30 | ToxicFrog | justin_smith: lua string library is not utf8 aware. You need a utf8 library. |
| 12:30 | justin_smith | ToxicFrog: lua? |
| 12:30 | ToxicFrog | Oh whoops |
| 12:30 | ToxicFrog | Got confused about what channel I'm in |
| 12:30 | mtp | grandy: that sounds like you actually want, like, a grammar. |
| 12:31 | mtp | instead of this kludgey regex contratption you're envisioning |
| 12:31 | hyPiRion | Yeah, that sounds like a task for instaparse |
| 12:31 | grandy | hmm |
| 12:31 | coventry | What does it mean when the symbol fn* has {:once true} in its metadata? |
| 12:32 | grandy | ok going to read up on instaparse :) |
| 12:32 | mtp | good idea :) |
| 12:37 | justin_smith | coventry: I thought maybe it was a defonce thing, but nope, defonce does not add :once to the metadata, at least not from the repl |
| 12:37 | technomancy | coventry: I think it means the return value is cached |
| 12:40 | justin_smith | an egrep -r in clojure core source finds the keyword used twice in such a context, as metadata to a clojure.lang.LazySeq object and a clojure.lang.Delay |
| 12:43 | justin_smith | fn.onceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), Keyword.intern(null, "once"))); ... later fn.onceOnly gets used as the final arg to fn.compile |
| 12:43 | justin_smith | |
| 12:45 | rasmusto | justin_smith: the docstrings in clojure.core imply that the result is cached after the first invokation. I'm not sure where the metadata fits into all of this |
| 12:45 | coventry | I don't fully understand it, but the last opcode generated by ObjExpr.emit when onceOnly is true puts something currently on the stack in a nonstatic field, which may be the caching technomancy is talking about. https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L4796 |
| 12:46 | justin_smith | rasmusto: it seems like the metadata is what tells it to do this (if I understand what you are saying) |
| 12:46 | rasmusto | justin_smith: that's what it looks like, I don't know any more detail than that |
| 12:47 | rasmusto | justin_smith: I'm looking up fn* source atm |
| 12:47 | justin_smith | AFn.java? |
| 12:48 | justin_smith | never mind, clearly not that |
| 12:48 | rasmusto | justin_smith: it's always fun to look at the java source though :) |
| 12:49 | justin_smith | java conventions are weird |
| 12:49 | justin_smith | but then again, every non-lisp looks weird to me, so I guess that should be taken under advisement |
| 12:52 | rasmusto | justin_smith: I think I'm in over my head: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java |
| 12:53 | coventry | No, actually, that snippet is clearing the locals (sticking null in that field.) Still consistent with technomancy's interpretation, though I don't know where the caching is happening. |
| 12:55 | justin_smith | rasmusto: line 297: static public interface LOLOL |
| 12:55 | justin_smith | so apropriate :P |
| 12:57 | sdegutis | I can't imagine writing Ruby anymore. "else" and "end" seem so unnecessary now. |
| 12:58 | ToxicFrog | justin_smith: speaking as someone who is still in the lua headspace more than the clojure one most days - it's not just you, Java is full of spiders. |
| 13:00 | Raynes | sdegutis: I wrote some Haskell the other day. I can't imagine writing Clojure anymore. All the ( and ) seem so unnecessary now. |
| 13:00 | sdegutis | Raynes: you really feel that way? |
| 13:00 | Raynes | No. |
| 13:00 | ambrosebs_ | lol |
| 13:01 | sdegutis | Oh. |
| 13:01 | mdrogalis | I kind of had a similar sarcastic though. The syntax is surface level |
| 13:01 | mdrogalis | thought* |
| 13:02 | rasmusto | lisp has absolutely no syntax |
| 13:03 | callen | well that's clearly not true, but it's a cute thought. |
| 13:03 | sdegutis | ,(iinc 1) |
| 13:03 | clojurebot | #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: iinc in this context, compiling:(NO_SOURCE_PATH:0:0)> |
| 13:03 | technomancy | if that were true we would be writing our code in clojure.jvm.analyzer format |
| 13:03 | sdegutis | Is there a shorthand for (+ 2 i) ? |
| 13:03 | mdrogalis | Yeah uh, I'm gonna go get some coffee. Later. |
| 13:03 | technomancy | which is pretty hideous |
| 13:03 | technomancy | sdegutis: commonly referred to as dinc, the elusive double-inc |
| 13:03 | callen | ##(inc (inc 1)) ##(+ 1 2) |
| 13:03 | lazybot | (inc (inc 1)) ⇒ 3 |
| 13:03 | lazybot | (+ 1 2) ⇒ 3 |
| 13:03 | clojurebot | *suffusion of yellow* |
| 13:03 | sdegutis | ,(doc dinc) |
| 13:03 | clojurebot | Pardon? |
| 13:03 | sdegutis | heh |
| 13:03 | rasmusto | ,((comp inc inc) 1) |
| 13:03 | clojurebot | 3 |
| 13:03 | sdegutis | :) |
| 13:04 | TimMc | sdegutis: He *said* it was elusive. :-P |
| 13:04 | sdegutis | I'll stick with + 2 |
| 13:04 | TimMc | &((apply comp (repeat 2 inc)) 5) |
| 13:04 | lazybot | ⇒ 7 |
| 13:04 | TimMc | sdegutis: ^ There's your shortcut. |
| 13:05 | rasmusto | ,(-> 1 inc inc inc inc) |
| 13:05 | clojurebot | 5 |
| 13:05 | sdegutis | I was thinking more like: &(last (take 2 (iterate inc 4))) |
| 13:05 | sdegutis | ,(last (take 2 (iterate inc 4))) |
| 13:05 | clojurebot | 5 |
| 13:05 | sdegutis | ,(last (take 3 (iterate inc 4))) |
| 13:05 | clojurebot | 6 |
| 13:05 | sdegutis | Yeah that. |
| 13:06 | llasram | That's the *easy* way to use `iterate`: ##((second (iterate (partial comp inc) inc)) 1) |
| 13:06 | lazybot | ⇒ 3 |
| 13:06 | callen | now just write a macro that checks for the number of "i"s in iiiiiinc to implement this. |
| 13:06 | sdegutis | I wonder if the "+1" function in Common Lisp was named +1 to make people who used it feel ashamed that they're trying to take shortcuts in an already-terse language. |
| 13:06 | sdegutis | (+1 i) ... (+ 1 i) |
| 13:06 | callen | (s iiiiiinc 5) => 11 |
| 13:07 | callen | yeah, should write that macro. |
| 13:07 | callen | it'd complete the circle of time-wasting. |
| 13:07 | rasmusto | and a ddddddddddec one too |
| 13:07 | TimMc | (dwim (inc8 5)) => 13 |
| 13:08 | sdegutis | Reminds me of my nomnomnom lib for Ruby: http://rubydoc.info/gems/omnomnom/0.0.1/frames |
| 13:08 | rasmusto | TimMc: haha, this is so pointless now |
| 13:08 | TimMc | ToxicFrog: And when you say "Java is full of spiders", I assume you mean this kind http://i.imgur.com/BVSvL7Q.jpg, not this kind: http://i.imgur.com/CZldxjjh.jpg |
| 13:09 | callen | Raynes: in honor of the channel's multi-segment namespace argument, my @work clojure project's namespace is ${PROJECT_NAME}.is.awesome |
| 13:09 | callen | TimMc: both kind of terrifying. |
| 13:09 | Raynes | callen: Reasonable name. |
| 13:10 | bja | we went with #{COMPANY_NAME}.lib and #{COMPANY_NAME}.app (for the clj/cljs frontend app) |
| 13:10 | callen | I prefer to have more fun with it :) |
| 13:11 | bja | although also #{COMPANY_NAME}.storm |
| 13:11 | callen | my namespace is designed to brainwash users into liking it. |
| 13:11 | callen | "YOU WILL LIKE THIS CODE" |
| 13:12 | bja | my coworkers are still a little edgy about using code that we keep under CI because it either doesn't have a release or has very few releases |
| 13:12 | bja | I just like getting notifications when changes happen in some of my libraries |
| 13:12 | bja | third-party code that is |
| 13:14 | TimMc | callen: The second one looks like a Tachikoma. |
| 13:16 | callen | TimMc: I haven't seen that in ages. |
| 13:24 | rasmusto | justin_smith: ah, I get it now, LOLOL |
| 13:29 | sdegutis | Woo, just made my tokenizer 14x faster. |
| 13:30 | sdegutis | It's also more readable now. |
| 13:33 | callen | is there a better verb than canonicalize? |
| 13:33 | sdegutis | callen: intern, according to Java strings |
| 13:33 | llasram | canonize |
| 13:33 | sdegutis | What's a good way to get the first index of an element in coll that satisfies (f)? |
| 13:33 | callen | canonize is our winner so far. |
| 13:33 | callen | intern is not it. |
| 13:33 | hyPiRion | (first (filter |
| 13:33 | sdegutis | It was a joke. |
| 13:33 | llasram | callen: Ha, I was joking |
| 13:34 | callen | I just want something less awkward/shorter |
| 13:34 | callen | it's going to be a namespace unto itself. |
| 13:34 | rigger | http://piplin.deviantart.com/art/Archery-17657627 |
| 13:34 | hyPiRion | callen: (def ffilter (comp first filter)) |
| 13:34 | sdegutis | hyPiRion: that only gives the element. I was thinking of using that with a mapped coll zipped with (iterate inc 9( |
| 13:34 | sdegutis | *0) |
| 13:34 | hyPiRion | ops, wrong |
| 13:34 | llasram | c10n |
| 13:35 | llasram | Oops, c10e |
| 13:35 | llasram | There we go |
| 13:35 | callen | it would be nice if it was a little more readable too P |
| 13:35 | callen | :P |
| 13:35 | hyPiRion | ah, right. There's no elegant way for that, you'd have to do some magic with map-indexed I suppose |
| 13:36 | rasmusto | what's wrong with 'some'? |
| 13:36 | sdegutis | rasmusto: how would you use it here? |
| 13:36 | sdegutis | rasmusto: it doesn't give the index |
| 13:36 | sdegutis | Right now I'm using recur to call fn on each element and return the index where fn passes. |
| 13:37 | rasmusto | (some (fn [[i v]] (if (pred v) [i v]) (map-indexed vector coll)) ... or something |
| 13:37 | xeqi | callen: awesomize |
| 13:37 | sdegutis | rasmusto: ah ok |
| 13:37 | rasmusto | I didn't proof read that btw |
| 13:38 | llasram | sdegutis: In the absence of something compact, I think a function using `recur` is pretty reasonable |
| 13:38 | sdegutis | llasram: okay, cool |
| 13:38 | sdegutis | thanks |
| 13:38 | technomancy | ~(doc keep-indexed) |
| 13:38 | clojurebot | excusez-moi |
| 13:38 | technomancy | ,(doc keep-indexed) |
| 13:38 | clojurebot | "([f coll]); Returns a lazy sequence of the non-nil results of (f index item). Note, this means false return values will be included. f must be free of side-effects." |
| 13:39 | technomancy | hrm |
| 13:39 | hyPiRion | sounds reasonable |
| 13:39 | xeqi | ,(doc filter-indexed) |
| 13:39 | clojurebot | It's greek to me. |
| 13:39 | xeqi | blah |
| 13:39 | llasram | Hmm, so like (first (keep-indexed (fn [i x] (when (pred? x) x)) coll)) |
| 13:39 | llasram | Not bad |
| 13:39 | rasmusto | much nicer |
| 13:39 | llasram | well, with `i` for that last `x` |
| 13:40 | technomancy | except for the when |
| 13:40 | hyPiRion | and with if for the last when |
| 13:40 | technomancy | hyPiRion: o/ |
| 13:40 | hyPiRion | \o |
| 13:40 | rasmusto | what's wrong with when? I've heard people say it's only used for side effects, but I don't get that |
| 13:40 | llasram | Eh. I prefer when even for non-side-effects, which I know puts me in the minority, but so there I stand :-p |
| 13:40 | rasmusto | is it the implicit do? |
| 13:41 | technomancy | rasmusto: yeah, and if does the job nicely in this case |
| 13:41 | rasmusto | technomancy: gotcha |
| 13:41 | technomancy | I don't believe the fact that you can omit `if`'s else arg is a design flaw, which seems to be implied by people who use `when` for the return value |
| 13:41 | sdegutis | Cool thanks technomancy and llasram |
| 13:44 | llasram | technomancy: That's fair. I think it's something I just need to get over. When I see `when` I think "returns nil when false," which isn't the first thing I think when I see an `if` |
| 13:45 | technomancy | variadic macros: how do they even work? =) |
| 13:45 | llasram | Yeah yeah :-p |
| 13:52 | ToxicFrog | TimMc: quite. |
| 13:54 | sdegutis | What's the auto-runner for Expectations? |
| 13:56 | sdegutis | Ah, https://github.com/jakemcc/lein-autoexpect |
| 14:02 | coventry | Where is the metadata shorthand (^{}) parsed? |
| 14:03 | clgv | for datomic is there a guide how to get fast queries? which constructions should be ommited? |
| 14:04 | coventry | Oh, LispReader.java, of course. |
| 14:07 | sdegutis | Which is preferred when using defrecord, (->Record) or (Record.)? |
| 14:08 | sdegutis | Is one more efficient than the other or something? |
| 14:09 | rigger | use the source, luke! |
| 14:11 | jkkramer | sdegutis: ->Record is easier to work with, since it's just a function and can be required as usual from other namespaces. for the latter, you have to import the class |
| 14:11 | clgv | are there no datomic users around right now? |
| 14:11 | sdegutis | Good point. |
| 14:11 | sdegutis | clgv: try #datomic |
| 14:12 | sdegutis | Oh you did. |
| 14:12 | clgv | same.. |
| 14:15 | clgv | its pretty strange I do not manage to use my cpus up to 100% but I do not why |
| 14:31 | rasmusto | clgv: my code uses 6000% cpu |
| 14:31 | sdegutis | I'm slightly concerned that maybe I'm jumping to loop/recur too often now. |
| 14:31 | sdegutis | Then again, this is a parser. That's probably okay. |
| 14:31 | clgv | rasmusto: certainly not per cpu or your server is on fire now ;) |
| 14:31 | clgv | or per core to be more specific ;) |
| 14:38 | mklappstuhl | want to setup some database stuff that might change later, what are you guys using for migrations? or is there something conceptually different I didnt think of? |
| 14:38 | SegFaultAX | There are lots of migrations libraries available. |
| 14:39 | SegFaultAX | Migratus is a good place to start. |
| 14:39 | sdegutis | is (def foo 'foo) dumb? |
| 14:39 | mklappstuhl | found drift & lobos so far |
| 14:39 | SegFaultAX | mklappstuhl: Those are also things, yes. |
| 14:40 | sdegutis | mklappstuhl: I like technomancy's approach |
| 14:40 | SegFaultAX | mklappstuhl: Find the one that suits you. They are all functionally similar (as are most migration frameworks) |
| 14:40 | sdegutis | https://github.com/technomancy/syme/blob/master/src/syme/db.clj#L68-L125 |
| 14:40 | mklappstuhl | sdegutis: what does that approach look like? |
| 14:40 | sdegutis | mklappstuhl: https://github.com/technomancy/syme/blob/master/src/syme/db.clj#L68-L125 |
| 14:40 | SegFaultAX | sdegutis: Any particular reason you want to def a single symbol? |
| 14:41 | sdegutis | SegFaultAX: basically want to emulate C's enum, ie I want a unique value that only compares truly to itself and is fast to compare |
| 14:42 | sdegutis | I think :foo would work too but then I lose type safety. And they're probably just as efficient. |
| 14:42 | technomancy | didn't we tell you to use a gensym yesterday? |
| 14:42 | sdegutis | technomancy: I was using it up until 2 minutes ago |
| 14:42 | tylere | Does clojure use deferred name resolution? e.g. I define functions a and b, can I call b from a even if a comes first in the source file? |
| 14:42 | amalloy | sdegutis: that doesn't sound much like C's enum :P |
| 14:42 | sdegutis | technomancy: then I wanted to use the constant in a case statement |
| 14:42 | SegFaultAX | sdegutis: Are you using it as a sentinel value? |
| 14:42 | amalloy | tylere: no |
| 14:43 | coventry | tylere: ##(source declare) |
| 14:43 | lazybot | java.lang.RuntimeException: Unable to resolve symbol: source in this context |
| 14:43 | coventry | ,(doc declare) |
| 14:43 | clojurebot | "([& names]); defs the supplied var names with no bindings, useful for making forward declarations." |
| 14:43 | sdegutis | technomancy: and it said "no matching clause for BLAAERGGGBLLAAA" |
| 14:43 | technomancy | lame |
| 14:43 | sdegutis | technomancy: no, fast. |
| 14:43 | technomancy | sdegutis: if you use read-time gensym it should work though |
| 14:44 | sdegutis | technomancy: case doesn't even eval, it's constant time lookup, so (def foo 'foo) works great here |
| 14:44 | technomancy | ,genned-sym# |
| 14:44 | clojurebot | #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: genned-sym# in this context, compiling:(NO_SOURCE_PATH:0:0)> |
| 14:44 | technomancy | ,:genned-sym# |
| 14:44 | clojurebot | :genned-sym# |
| 14:44 | technomancy | huh |
| 14:44 | technomancy | I guess that would require wrapping the whole thing in a ` |
| 14:44 | sdegutis | technomancy: but I don't need it to be super unique, only unique to the others, which means typos is the only real worry, and that's a one-time problem |
| 14:48 | coventry | technomancy: The # syntax doesn't seem to work with keywords: ##(list `(:genned-sym# genned-sym#)) |
| 14:48 | lazybot | ⇒ ((:genned-sym# genned-sym__134041__auto__)) |
| 14:48 | technomancy | coventry: huh; must have been thinking of something else |
| 14:49 | sdegutis | So, what's wrong with (def foo 'foo)? |
| 14:50 | sdegutis | Hmm, it should be thread-safe. And it doesn't cause a stackoverflow. |
| 14:50 | SegFaultAX | sdegutis: It's probably entirely unnecessary. |
| 14:50 | sdegutis | SegFaultAX: Why's that? |
| 14:50 | SegFaultAX | sdegutis: Do you intend to use identical? somewhere? |
| 14:51 | sdegutis | SegFaultAX: I have (case ... foo ...), does that count? |
| 14:51 | SegFaultAX | sdegutis: Are multimethods not an option? |
| 14:51 | sdegutis | Now I'm confused. |
| 14:52 | SegFaultAX | sdegutis: Me too, I have no idea what you're doing. It's hard to determine exactly why defing a symbol is useful for you. |
| 14:53 | sdegutis | Oh. |
| 14:53 | mklappstuhl | sdegutis: technomancy's approach is indeed quite interesting, especially since it's so simple :) |
| 14:54 | sdegutis | SegFaultAX: I'm writing a tokenizer/parser. And I want a fast/efficient way to represent a token's type, and later in the parser I want to switch off on token-types using case. So I need a way to represent token types that works both as a value and a constant suitable for case. |
| 14:54 | sdegutis | SegFaultAX: (def sym 'sym) seems to solve that, but I'm concerned there might be hidden caveats |
| 14:55 | coventry | If you're writing this tokenizer for educational reasons, now would probably be a good time to back away from the keyboard and think about the design for a while. Maybe look at how other people have done it and compare. |
| 14:55 | SegFaultAX | sdegutis: Still don't understand why that's useful, but what caveats do you think there could be? Symbols are stable values just like any other. |
| 14:56 | sdegutis | Dunno, that's why I was asking you guys :) |
| 14:56 | sdegutis | coventry: why do you say that? |
| 14:57 | coventry | You've been stuck on this point for a while, and the solution you're considering is strange and ugly. There might be a better way. |
| 14:57 | sdegutis | It is? I didn't realize it is. |
| 14:58 | SegFaultAX | sdegutis: Everyone objecting wasn't a dead giveaway? |
| 14:58 | coventry | You want to mess around with the namespace programmatically. Unless you are making a quarantined namespace for that purpose, that is ugly. |
| 14:59 | sdegutis | coventry: ah that's an interesting way to look at it |
| 14:59 | callen | it's not interesting at all, it's pretty obviously a bad idea. |
| 14:59 | sdegutis | callen: why? |
| 15:00 | coventry | Well, sometimes it's not ugly. Adding a function name, or whatever is OK. :-) Adding a bunch of tokens for the purpose of speeding up a switch is way out of balance, though. |
| 15:00 | callen | if you don't know why mucking around with namespaces programmatically is a bad idea, then I can't tell you either. |
| 15:00 | callen | coventry: yeah. |
| 15:00 | sdegutis | I guess I don't really look at this like too heavy a use of metaprogramming. |
| 15:01 | sdegutis | Mainly because it's very simple: foo refers to foo. |
| 15:01 | llasram | Which is exactly what keywords are for? |
| 15:01 | TimMc | sdegutis: Oh wait, you also go by the nick "futile", right? |
| 15:01 | TimMc | I thought I recognized this conversation. |
| 15:01 | callen | TimMc: yeah, same bloke. |
| 15:01 | callen | TimMc: lots of conversation about bad ideas, no actual usable code at the end. |
| 15:02 | callen | I wonder how much programmer time he's wasted in total. |
| 15:02 | callen | between his own efforts and everybody else he sucks into his pointless bullshit. |
| 15:03 | coventry | If I hadn't procrastinated making that suggestion, I probably would have procrastinated some other way. But yes, this is improving no one's life. Back to work for me. :-) |
| 15:03 | callen | I have Datomic queries to write - I'm out too. |
| 15:24 | sdegutis | Well so much for trying to discuss design philosophies. Didn't expect so much condescending dismissiveness from #clojure. |
| 15:25 | callen | sdegutis: http://i.imgur.com/Zoc8zR7.jpg |
| 15:25 | sdegutis | That was probably uncalled for, sorry. |
| 15:25 | gdev | sdegutis, sorry I was out to lunch, what did I miss? |
| 15:25 | rigger | just need to find the right person, right time |
| 15:26 | gdev | I like design discussions =) |
| 15:26 | callen | gdev: #RUBY_DRAMA |
| 15:26 | callen | gdev: namespace munging. |
| 15:26 | mklappstuhl | getting errors like this: ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol clojure.lang.RT$1.invoke (RT.java:224) |
| 15:26 | mklappstuhl | how can I get some better errors? |
| 15:26 | mklappstuhl | like line numbers and these sorts of things |
| 15:27 | sdegutis | gdev: I have a tokenizer/parser where the tokenizer returns tokens with types and the parser has to switch off on them. I came up with the solution (def RParen 'RParen) so that I could use RParen as the token type, and use (case) to switch off on it. |
| 15:27 | coventry | mklappstuhl: I generally (use 'clojure.repl) and then (pst) to get the full stacktrace. |
| 15:27 | alejandro_ | mklappstuhl: or http://richhickey.github.io/clojure/clojure.stacktrace-api.html |
| 15:28 | sdegutis | gdev: I was going to use keywords, but this solution gives me a little more type safety. What do you think of that solution? Do you think it's bad on account of messing with the namespace? |
| 15:28 | coventry | mklappstuhl: It's a lot of spew, (don't think the stacktrace api will save you from that), so you have to scan the output for references to your source files. |
| 15:29 | mklappstuhl | coventry: how exactly would I use pst? |
| 15:29 | mklappstuhl | coventry: nevermind :) |
| 15:29 | mklappstuhl | http://clojuredocs.org/clojure_core/clojure.repl/pst |
| 15:30 | mklappstuhl | haha, it doesn't list any of my source files though :D |
| 15:31 | gfredericks | why would (range 100000000) be twice as slow with (reduce +) than the same thing in a vector? |
| 15:32 | nDuff | gfredericks: because it can't seek, and thus can't parallelize. |
| 15:32 | nDuff | gfredericks: ...I'm actually surprised it's only twice as slow. |
| 15:32 | gdev | sdegutis, can you refheap the code? I'm bad at word problems =( |
| 15:32 | nDuff | Oh, wait, this isn't core.reducers? |
| 15:32 | nDuff | Don't know, then. |
| 15:32 | gfredericks | nDuff: reduce + can't parallelize anyhow |
| 15:32 | gfredericks | k |
| 15:33 | gfredericks | ,(time (reduce + (range 1000000))) |
| 15:33 | clojurebot | "Elapsed time: 187.122121 msecs"\n499999500000 |
| 15:33 | gfredericks | ,(let [v (vec (range 1000000))] (time (reduce + v))) |
| 15:33 | clojurebot | #<OutOfMemoryError java.lang.OutOfMemoryError: Java heap space> |
| 15:34 | gdev | that was faster |
| 15:34 | gfredericks | that is a small jvm. |
| 15:34 | gfredericks | I was doing mine 100 times as big |
| 15:34 | gfredericks | &(time (reduce + (range 1000000))) |
| 15:34 | lazybot | ⇒ "Elapsed time: 257.85282 msecs" 499999500000 |
| 15:34 | gfredericks | &(let [v (vec (range 1000000))] (time (reduce + v))) |
| 15:34 | lazybot | ⇒ "Elapsed time: 1376.893624 msecs" 499999500000 |
| 15:34 | coventry | gfredericks: You aren't including the construction of the vector in the time. Isn't it likely that it's the increments by range which are slowing things down? |
| 15:35 | callen | ##(time (apply + (range 10000))) |
| 15:35 | lazybot | ⇒ "Elapsed time: 10.051635 msecs" 49995000 |
| 15:35 | callen | ##(time (apply + (range 1000000))) |
| 15:35 | lazybot | ⇒ "Elapsed time: 349.833382 msecs" 499999500000 |
| 15:35 | callen | ##(time (apply + (range 10000000))) |
| 15:35 | lazybot | ⇒ "Elapsed time: 3344.378229 msecs" 49999995000000 |
| 15:35 | sdegutis | gdev: https://www.refheap.com/18374 |
| 15:35 | callen | ##(time (reduce + (range 1000000))) |
| 15:35 | lazybot | ⇒ "Elapsed time: 269.19041 msecs" 499999500000 |
| 15:35 | callen | marginal. cool. |
| 15:38 | gdev | sdegutis, thanks, lemme have a look at it |
| 15:39 | hiredman | I would suspect vectors are faster for sequential access in general, because they pack values in nice cache filling arrays |
| 15:39 | mklappstuhl | I get an error 'ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol' when switching into a namespace I'm working in & (pst) doesnt give me any hint about where I made the mistake. Is there anything else I could do? |
| 15:40 | hiredman | mklappstuhl: are you doing (ns 'foo) ? |
| 15:40 | mklappstuhl | hiredman: |
| 15:40 | mklappstuhl | yes |
| 15:40 | hiredman | ns is macro it doesn't need the quote |
| 15:41 | callen | ##(time (reduce + (vec (range 1000000)))) |
| 15:41 | lazybot | ⇒ "Elapsed time: 4546.920025 msecs" 499999500000 |
| 15:41 | mklappstuhl | hiredman: ok, thats good to know. should that also change whats printed by (pst) ? |
| 15:41 | mklappstuhl | (it doesn't for me) |
| 15:41 | ztellman | callen: you're timing the conversion to a vector, too, in that benchmark |
| 15:41 | callen | I know |
| 15:41 | callen | I just caught it. |
| 15:41 | mklappstuhl | code is here btw: https://github.com/mklappstuhl/goldman.clj/blob/master/src/mklappstuhl/stock_utils/db.clj |
| 15:42 | callen | ##(let [v (vec (range 1000000))] (time (reduce + v))) |
| 15:42 | lazybot | ⇒ "Elapsed time: 2281.862622 msecs" 499999500000 |
| 15:42 | ztellman | "benchmark", I should say |
| 15:42 | callen | ztellman: it's not serious, I'm just being idle. |
| 15:42 | callen | I know to use criterium in things I care about :P |
| 15:42 | callen | ##(let [v (vec (range 1000000))] (time (reduce + v))) |
| 15:42 | lazybot | ⇒ "Elapsed time: 1857.035772 msecs" 499999500000 |
| 15:42 | ztellman | callen: oh, sure, but if I don't keep the benchmark snootiness torch burning, who will? |
| 15:43 | callen | ##(let [v (vec (range 1000000))] (time (apply + v))) |
| 15:43 | lazybot | ⇒ "Elapsed time: 2516.47335 msecs" 499999500000 |
| 15:43 | callen | ztellman: well, I was, earlier. |
| 15:43 | callen | told futty to use criterium, haha. |
| 15:43 | TimMc | sdegutis: Anything beyond preconditions that check inputs for membership in a set is going to be pretty ugly. |
| 15:43 | ztellman | by the way, you guys know you can use scientific notation with range, right? |
| 15:43 | ztellman | way easier to visually parse |
| 15:44 | callen | well it's not specific to range. |
| 15:44 | sdegutis | TimMc: how so? |
| 15:44 | ztellman | callen: yes, but specifically with range it's almost always what you want to do |
| 15:44 | TimMc | sdegutis: Because if you want more than that, you're probably using the wrong language. |
| 15:46 | coventry | sdegutis: Why not dispatch off the token characters themselves? https://github.com/clojure/tools.reader/blob/master/src/main/clojure/clojure/tools/reader.clj#L543 |
| 15:47 | sdegutis | coventry: hmm that's an interesting solution. I didn't think it'd work on account of the dispatch # char, but this solution is neat. |
| 15:48 | coventry | That's all good reading, if you want to write a parser. |
| 15:50 | gfredericks | hiredman: but (range n) is also chunked in 32s, is it not? is it somehow less cache-optimal than a vector? |
| 15:53 | gfredericks | coventry: oh that's an interesting point about the increments. When I (doall (range n)) first, so the whole thing is in memory, it is faster. |
| 15:53 | gfredericks | faster than the vector even, at first glance |
| 15:55 | hiredman | gfredericks: oh, right, chunking :( |
| 15:57 | callen | ##(let [v (vec (range 1e6))] (time (apply + v))) |
| 15:58 | lazybot | ⇒ "Elapsed time: 2175.583604 msecs" 499999500000 |
| 16:02 | coventry | Seems like the JIT compiler optimizes all of this away, anyway. https://www.refheap.com/18375 |
| 16:09 | gdev | sdegutis, my 2 pennies is that when it comes to design I try to make design decisions reversible so once there are no more unknowns I can refactor bad decisions |
| 16:10 | sdegutis | gdev: good plan |
| 16:11 | Rubix | (bean instance-of-user-defined-class) gives me {:class instance-of-user-defined-class} ... I wish it would show the data members therein ... any suggestions? |
| 16:11 | gdev | if you want to manage risk and be able to quickly refactor, you have definitely chosen the right language |
| 16:16 | gdev | Rubix, bean only shows things exposed through its getter methods |
| 16:17 | Rubix | gdev: I have to define getter methods for it? shucks |
| 16:18 | llasram | Rubix: Do you control the user-defined-class? |
| 16:18 | Rubix | llasram: yes |
| 16:18 | gdev | ##(:members (clojure.reflect "foo")) |
| 16:18 | lazybot | java.lang.ClassNotFoundException: clojure.reflect |
| 16:19 | llasram | Rubix: does it exist to ship to a Java interface or such? |
| 16:19 | Rubix | llasram: no, its pojo, |
| 16:19 | gdev | Rubix, if your class really is a JavaBean all of its members should only be accessible through getters and setters so sayeth the sun lord, so it shall be done |
| 16:20 | llasram | Rubix: I mean, are you using a Java class because you need to pass it to some Java API? |
| 16:20 | Rubix | llasram: i've got a pile of legacy java code under my control, trying to extract pojos to maps |
| 16:21 | llasram | There we go -- that's what I should have asked :-) |
| 16:21 | llasram | And the POJOs directly expose data via public members, not getter/setter methods? |
| 16:22 | Rubix | llasram: yes |
| 16:22 | Rubix | all public, all the time |
| 16:22 | llasram | Rubix: Yeah, I don't think anything off-the-shelf exists, but as gdev suggested you should be able to use clojure.reflect/reflect |
| 16:23 | callen | hrm. yes. core.async is fast #_# |
| 16:23 | gdev | ##(:members (clojure.reflect/reflect "foo")) |
| 16:23 | lazybot | java.lang.ClassNotFoundException: clojure.reflect |
| 16:24 | Rubix | llasram, gdev : what's that argument to (clojure.reflect) ? |
| 16:25 | Rubix | string-represented declared class name? |
| 16:26 | gdev | Rubix, I'm just passing in a string so it will give me a map of all the members of java.lang.string |
| 16:26 | Rubix | ah |
| 16:27 | gdev | Rubix, you could also do (:members (clojure.reflect/reflect (MyClass.)) |
| 16:28 | mklappstuhl | how do I reload the namespace I'm currently in in the REPL? |
| 16:28 | llasram | gdev, Rubix: Well, and you can use reflect-type to reflect on a Class |
| 16:28 | llasram | Er, type-reflect even |
| 16:29 | coventry | mklappstuhl: Are you using emacs? I generally just do C-c C-k in the corresponding source file. |
| 16:29 | llasram | &(require 'clojure.reflect) |
| 16:29 | lazybot | ⇒ nil |
| 16:29 | llasram | &(->> clojure.lang.Keyword clojure.reflect/type-reflect :members (filter #(and (instance? clojure.reflect.Field %) (-> % :flags :static not) (-> % :flags :public))) (map :name)) |
| 16:29 | lazybot | ⇒ (sym) |
| 16:29 | mklappstuhl | coventry: no. vim + lein repl |
| 16:29 | llasram | &(.-sym :hello) |
| 16:29 | lazybot | ⇒ hello |
| 16:30 | TimMc | mklappstuhl: (require (.name *ns*) :reload) |
| 16:31 | TimMc | mklappstuhl: (require 'my.ns :reload) if you want to reload it by name |
| 16:31 | callen | you probably don't want to use reload. |
| 16:31 | llasram | TimMc: also (ns-name *ns*) |
| 16:31 | mklappstuhl | callen: whats wrong with reload? |
| 16:32 | callen | no seriously |
| 16:32 | callen | (require '[clojure.tools.namespace.repl :refer [refresh]]) (refresh) |
| 16:32 | callen | do that. Don't use reload/reload-all |
| 16:32 | callen | mklappstuhl: cf. Stuart Sierra's workflow post and the documentation on clojure.tools.namespace. |
| 16:32 | mklappstuhl | callen: link? |
| 16:35 | TimMc | If you don't use protocols or multimethods (and you defonce your state) it is fine. |
| 16:37 | callen | refresh is moar betta. |
| 16:37 | callen | and doesn't require that you cherry-pick. |
| 16:39 | seangrov` | Does lighttable work with clojure 1.5 projects? |
| 16:39 | rasmusto | seangrov`: I think the newest release requires 1.5.x in project.clj |
| 16:43 | aaelony | I am building a map where I start from an initial map and use assoc to make a new key and new value, x1, that is the result of some computation. Now, I want to compute x2 and use the result value x1 in the computation of x2 and then assoc x2 into my growing map. Can I do this? Or need I create a monster let statement with all my dependent calcs x1, …, xn and merge them into my final map? |
| 16:43 | mklappstuhl | callen: if I run (require '[clojure.tools.namespace.repl :refer [refresh]]) and then (refresh) it can't resolve the symbol... |
| 16:46 | justin_smith | aaelony: maybe an iterate that updates the key to use on each time through? |
| 16:46 | justin_smith | aaelony: that would require a function that takes the previous key, and generates the next one from that |
| 16:46 | justin_smith | or an infinite list of keys |
| 16:46 | justin_smith | one of those |
| 16:48 | aaelony | justin_smith: I guess I am hoping there was something like (-> initial-map (assoc :x1 (some-calc)) (assoc :x2 (something that uses value of :x1)) (assoc (:x3 (something that uses :x2 )) etc… ) |
| 16:51 | aaelony | justin_smith: thanks for your thoughts… will think about it some more… I think that hard part is that it needs to be as flexible as a let statement would be, but the results would go in to the final map... |
| 16:51 | aaelony | justin_smith: maybe the answer is indeed "that's what let is for" and then merge it in the last step…. |
| 16:52 | justin_smith | (zipmap (create-key-seq) (iterate process input)) |
| 16:53 | justin_smith | maybe? |
| 16:54 | aaelony | justin_smith: maybe… but there may not be reliable structure in the function sequence.. For example, x2 may need to access 3 values from keys in the map that is being built, but x3 may need some other combination... |
| 16:55 | aaelony | justin_smith: or maybe that is what you specify in the key-seq… interesting... |
| 17:05 | coventry | aaelony: Have not used it, but synthread may help you do this kind of thing. https://github.com/LonoCloud/synthread |
| 17:05 | coventry | Especially ->/as |
| 17:06 | aaelony | conventry: appreciate it, will take a look.. thanks |
| 17:08 | aaelony | coventry: looks like a good fit! Need to figure out the syntax. thanks! :) |
| 17:09 | SegFaultAX | Synthread is awesome. |
| 17:11 | aaelony | kudos to chouser! |
| 17:16 | callen | SegFaultAX: yes it is. |
| 17:17 | Raynes | SegFaultAX: In that it'd take a rocket scientist to have any clue what code is doing after it has been infected with that shit? |
| 17:21 | callen | I think Raynes and callen switched brains today. |
| 17:21 | Raynes | lol |
| 17:22 | Raynes | callen: Was that *that* mean? |
| 17:23 | callen | well. It wasn't as bad as waterboarding bloom with his CV, but it was surprisingly negative. |
| 17:23 | hyPiRion | It could be amalloy too, for that matter. |
| 17:23 | Raynes | callen: :P |
| 17:26 | amalloy | c'mon, that doesn't sound like me at all. i would have found a subtly sarcastic way to object to it, if i didn't like it |
| 17:26 | amalloy | the fecal comparisons are a callen thing for sure |
| 17:28 | callen | so am I dumb for being surprised that (def f (memoize (fn [] (atom {})))) (swap! (f) assoc :a 1) @(f) did the right thing? |
| 17:34 | dobry-den | callen: would that create a new atom when you swap! it with different arguments, but return the same atom when you swap it with the same arguments? |
| 17:34 | seangrov` | Are watches enabled for lighttable? |
| 17:35 | dobry-den | seangrov`: i think so. i saw the keybindings for toggling them when i was editing the behavior/keymapping files |
| 17:38 | TimMc | callen: What were you expecting? |
| 17:39 | coventry | Is there a way to get rid of the red underlining which appears on a form when you compile it under nrepl's C-c C-k? (Other than correcting the error and re-evaluating. :-) |
| 17:40 | SegFaultAX | Raynes: I don't think the synthread macros are that bad personally. |
| 17:40 | callen | dobry-den: just try it |
| 17:40 | callen | SegFaultAX: I think it's more significant that an ex-Haskell user dislikes it. |
| 17:40 | mabes | coventry: I've been wondering that myself.. sometimes I comment out the form with #_, and reload, just to get rid of them... |
| 17:40 | callen | TimMc: for Clojure to be as ghetto as every language I'd previously used. |
| 17:41 | callen | TimMc: Python set my expectations kinda low. |
| 17:41 | callen | even after ${X} years I still haven't learned to just trust it. |
| 17:41 | seangrov` | dobry-den: Ah, yes, found it, thank you |
| 17:41 | seangrov` | Hrm, lighttable is pretty nice |
| 17:42 | SegFaultAX | I don't think Python is particularly more ghetto than any other language. |
| 17:43 | SegFaultAX | Every language has dark corners. Python doesn't have as many as some. |
| 17:44 | unlink | I'm getting the following error when I run nrepl-jack-in: "error in process sentinel: Could not start nREPL server: " |
| 17:44 | unlink | `lein repl' works fine from M-x shell |
| 17:45 | callen | seangrov`: is it? lot of trouble with it lately. |
| 17:45 | technomancy | unlink: does M-! which lein work? |
| 17:46 | rasmusto | callen: my ctrl-space hotkey didn't work with my keyboard, so I couldn't un-fullscreen lighttable without uninstalling |
| 17:46 | unlink | technomancy: yes |
| 17:46 | rasmusto | callen: it's still usable enough for proj euler and 4clojure stuff |
| 17:47 | Pupnik | so is windows notepad |
| 17:47 | technomancy | unlink: huh; dunno. you could do `lein repl :headless` and M-x repl to connect to it |
| 17:48 | technomancy | M-x nrepl |
| 17:50 | rasmusto | Pupnik: so is pencil and paper |
| 17:50 | sdegutis | I vaguely remember a short-hand for (and (> x min) (< x max)), does it exist or was I dreaming? |
| 17:50 | unlink | technomancy: open-network-stream: make client process failed: Can't assign requested address, :name, nrepl, :buffer, *nrepl-connection*, :host, 127.0.0.1, :service, 0, :nowait, nil |
| 17:52 | technomancy | unlink: did you give it a port? |
| 17:53 | seangrov` | callen: I've only used it for ~5 minutes, it's better than I expected. Not expecting to leave emacs for it of course. |
| 17:53 | sdegutis | Ah, (< min x max) |
| 17:53 | sdegutis | ,(< 3 4 5) |
| 17:53 | clojurebot | true |
| 17:53 | sdegutis | Neat. |
| 17:53 | seangrov` | But we have a contractor here learning clojure and he was using x-code, no syntax highlighting, no paren matching... it was painful to watch |
| 17:54 | seangrov` | I recommended he try out lighttable, figured that's likely easier to pickup than emacs |
| 17:54 | sdegutis | seangrov`: sounds like it |
| 17:54 | unlink | technomancy: ah. I had mispelled :repl-options as :nrepl-options. |
| 17:55 | unlink | technomancy: I am able to connect via M-x nrepl. |
| 17:55 | seangrov` | sdegutis: Learning a new language, toolchain, programming style, and editor at the same time seems a bit overwhelming. Trying not to scare him away too quickly. |
| 17:55 | unlink | technomancy: it would be nice if unrecognized forms in defproject weren't silently ignored. |
| 17:55 | technomancy | unlink: nice, but infeasible |
| 17:56 | sdegutis | seangrov`: I'm just really confused about the lack of syntax highlighting part.. doesn't Xcode have a built-in syntax highlighter? |
| 17:56 | technomancy | given that any plugin can arbitrarily choose to recognize any form |
| 17:56 | sdegutis | seangrov`: oh yeah, probably not for Lisp langs.. |
| 17:56 | unlink | sounds like an architectural limitation worth addressing. |
| 17:56 | seangrov` | sdegutis: Exactly. |
| 17:56 | technomancy | unlink: you would have to load every plugin for every execution |
| 17:57 | seangrov` | It's a worrisome sign for me when a developer hasn't spent a lot of time on their tools though |
| 17:57 | unlink | not if you, for example, enforced a convention for plugin-specific options. |
| 17:57 | callen | seangrov`: to me too. |
| 17:57 | seangrov` | You use them for so many years, it makes sense to invest in making them nice and efficient |
| 17:57 | callen | seangrov`: I'm introducing Clojure guerilla style at my company. Going to conquer one mind at a time. |
| 17:57 | seangrov` | Haha |
| 17:57 | rasmusto | callen: what are your tactics? |
| 17:57 | callen | seangrov`: a lot of people aren't that invested in their careers. |
| 17:57 | seangrov` | callen: We'll have to grab drinks some time |
| 17:57 | callen | rasmusto: use Datomic as an excuse to use Clojure |
| 17:57 | seangrov` | Ah, fair enough |
| 17:57 | rasmusto | callen: oh damn |
| 17:58 | callen | rasmusto: steal labor for my project, brainwa^H^H^H^H^H^H convert them |
| 17:58 | technomancy | unlink: that just moves the problem around |
| 17:58 | seangrov` | I suppose I'm expecting a common level of desire to improve |
| 17:58 | callen | rasmusto: make project awesome, impress air support, conquer another thing. |
| 17:58 | rasmusto | callen: yeah, awesome projects can go a long way |
| 17:58 | callen | seangrov`: not what I've encountered. and yes, we should grab drinks. Are you coming to the meetup today? |
| 17:58 | unlink | technomancy: no, it solves that part of the problem. then you require projects to declare the configuration they understand. |
| 17:59 | technomancy | it's technically feasible, but it goes against the design principles of clojure |
| 18:00 | unlink | ...fail slowly and silently? |
| 18:00 | technomancy | if you want to be able to catch unknown patterns properly you need a static type system |
| 18:00 | seangrov` | callen: Heading to a different meetup a friend asked me to join, sadly |
| 18:01 | sdegutis | Ahh!! |
| 18:01 | unlink | this has nothing to do with types, and everything to do with (developer-)friendly user interfaces |
| 18:01 | technomancy | ,(contains? [1] 1) ; <- unlink |
| 18:01 | clojurebot | false |
| 18:01 | callen | seangrov`: You're in the city right? you free tomorrow? |
| 18:02 | seangrov` | callen: Yeah, but heading out to JSConfEU soon, so prepping a lot |
| 18:02 | seangrov` | Our office is in the Mission, I'm in Twin Peaks |
| 18:02 | coventry | mabes: Just thought of the right google query: (defun drop-overlays () (interactive) (remove-overlays)) |
| 18:02 | callen | seangrov`: SOMA / Ingleside for me, also I drive. |
| 18:02 | technomancy | ignoring the significant backwards-compatibility challenges, it's just not in line with the zen of clojure to protect against that kind of mistake |
| 18:03 | seangrov` | callen: Early drinks at CBS? |
| 18:03 | unlink | technomancy: I'm not sure what user-interface compromise in the name of efficiency has to do with making leiningen hard to debug |
| 18:04 | callen | seangrov`: the only word I understood in there is "drinks". I don't know what early is for you, and I don't know what CBS either, sorry. haha. |
| 18:04 | unlink | I think a better example would be: (contains? :x 1) |
| 18:04 | unlink | you pass it something invalid, so it throws an exception loudly and makes the error obvious |
| 18:05 | unlink | instead of silently doing the wrong thing and looking like it works, even when its input is never valid |
| 18:06 | mabes | coventry: nice, thanks for sharing.. adding that along with a keybinding for it :) |
| 18:21 | sdegutis | What's a good way to test if two ranges intersect? Convert them to sets and use the set lib? |
| 18:21 | ztellman | are the ranges already turned into sequences? |
| 18:22 | ztellman | or are they just intervals of [start end]? |
| 18:25 | unlink | another example: how is a user supposed to discover that :dev-dependencies has been deprecated, particularly when current documentation (such as the documentation for ring.util.serve) continues to refer to it? |
| 18:25 | sdegutis | ztellman: I actually just have two pairs of pos/len |
| 18:25 | technomancy | unlink: for backwards-compatible changes there is the lein-precate plugin |
| 18:26 | ztellman | sdegutis: http://www.rgrjr.com/emacs/overlap.html |
| 18:26 | ztellman | that should be a bit more efficient than calculating the intersection |
| 18:26 | unlink | I happen to have studied the differences between the example project.clj files for 1.6 and 2.0, so I know what changed; but here is the error message a newbie would be confronted with: FileNotFoundException Could not locate ring/util/serve__init.class or ring/util/serve.clj on classpath: clojure.lang.RT.load (RT.java:443) |
| 18:26 | technomancy | unlink: including :dev-dependencies in a project.clj is not always a bad idea if your users might be using 1.x or 2.x though |
| 18:26 | sdegutis | ztellman: sweet, thanks! |
| 18:27 | technomancy | further proof that the validity of a given key is undecidable |
| 18:27 | gfredericks | technomancy: is there a leiningen undecidability theorem? |
| 18:27 | seangrov` | ztellman is a wizard |
| 18:27 | gfredericks | (presumably referred to as LUT by the kids these days) |
| 18:28 | ztellman | interval arithmetic is wizardry? |
| 18:28 | technomancy | gfredericks: maybe you're confusing it with the hagelberg uncertainty principle. |
| 18:28 | unlink | of course it's undecidable. that's the problem. you have a declarative document without any checks for validity. |
| 18:29 | sdegutis | ztellman: no, just that you do tons of crazy efficiency things |
| 18:29 | sdegutis | ztellman: I'm never surprised to see ANNs about super-efficient this or that from you on the mailing list :) |
| 18:30 | unlink | Java's maven, Haskell's cabal, and even Python's setuptools will complain (or crash) if they are given improper build descriptors. leiningen stands alone in chugging along with an (often provably) incorrect project descriptor. |
| 18:31 | muhoo | the general attitude of clojure is to encourage you to do the right thing, but not go out of the way to put up barriers to prevent you from doing the wrong thing, AFAICT |
| 18:31 | muhoo | i think rchickey calls it "consenting adults programming" or somethign similarly pithy |
| 18:31 | technomancy | the first two are completely different: XML has schemas, Haskell has a static type system |
| 18:31 | technomancy | I have no idea how python works |
| 18:31 | unlink | no, that's the general attitude of PHP and JavaScript. |
| 18:32 | hyPiRion | so, uh, is it the battle of the types again? |
| 18:32 | unlink | Haskell has a static type system, but its setup descriptor is not code. it's a declarative document similar to project.clj. |
| 18:32 | technomancy | and actually in the case of maven it's a PITA that you can't attach arbitrary metadata to a pom |
| 18:32 | mgaare | cabal is also a terrifying nightmare :D |
| 18:33 | gfredericks | I think you can isolate certain cases in clojure core of returning nil when passed totally irrelevant types, e.g. ##(contains? :foo :bar) |
| 18:33 | lazybot | ⇒ false |
| 18:33 | hyPiRion | `cabal install cabal-install` always gets me |
| 18:33 | unlink | project.clj is *excellent* in principle. it is exactly what you should want: a non-code datastructure specifying your project. |
| 18:33 | gfredericks | it's pretty easy to argue that that should throw an exception without violating the zen of clojure |
| 18:33 | technomancy | gfredericks: this is more like (:foo {:bar 1}) though |
| 18:33 | callen | muhoo: I tend to agree with the "consenting adults" thing btw |
| 18:34 | seangrov` | callen: Have you successfully got datomic into production? |
| 18:34 | callen | oh cool, we're getting a 64TB SSD Z-raid array installed in one of the servers at work. |
| 18:35 | callen | seangrov`: it's not finished, but it's going to be very soon. |
| 18:35 | technomancy | I would actually be interested in a language that had (:foo {:bar 1}) throw if you didn't provide a not-found value |
| 18:35 | callen | have the license key for the pro edition ready to go, just hacking the code together. |
| 18:35 | seangrov` | callen: How's your experience been? |
| 18:36 | technomancy | but that's not what this is about, because having no :repl-options in your project.clj file is completely reasonable |
| 18:36 | callen | technomancy: core.typed? |
| 18:36 | mgaare | callen: have you played around with any larger data sets in datomic yet? |
| 18:36 | callen | seangrov`: there are idiosyncrasies, but it's good so far. The design seems solid so far. |
| 18:36 | hyPiRion | callen: that has nothing to do with core.typed though? It's more about a lack of value. |
| 18:36 | callen | mgaare: nothing substantial yet, but I will when I stress test the pro instance...which will happen whenever IT gives me my server. |
| 18:36 | hyPiRion | a map entry, rather. |
| 18:36 | callen | hyPiRion: core.typed can enforce that, no? |
| 18:36 | technomancy | callen: I'd rather it worked that way without a substantial up-front investment |
| 18:36 | seangrov` | technomancy: Haven't been following along too closely, but how about a lein plugin that checks the project.clj for known mispellings? |
| 18:37 | technomancy | seangrov`: that's reasonable |
| 18:37 | seangrov` | Would be an easy one to submit pr's for on github and help people out |
| 18:37 | mgaare | callen: one thing we noticed was that if you have a lot of entities, partitioning becomes very important |
| 18:37 | technomancy | seangrov`: or even "here's what you're using that's not in sample.project.clj" |
| 18:37 | callen | levenshtein the keys? |
| 18:37 | callen | oh, that's better still. |
| 18:38 | callen | mgaare: interesting. Our needs are relatively minimal so far WRT performance/volume |
| 18:38 | callen | mgaare: the thing I'm building is multiple orders of magnitude overkill for our actual data needs (a conscious decision) |
| 18:39 | callen | mgaare: can you say what tier of entity pop-counts started necessitating paying attention to partitioning? |
| 18:40 | mgaare | callen: our test data was about 8 figures of entities. Need to do it well before that point |
| 18:40 | dissipate__ | what's up with datomic being closed source? |
| 18:41 | callen | dissipate__: wanna make money. don't blame 'em. Their license terms are hyper-mega-reasonable. |
| 18:41 | callen | $3k perpetual license. ridiculously good deal. |
| 18:41 | callen | you re-up a fraction of that for maintenance. |
| 18:41 | callen | pay more for more peers |
| 18:41 | mgaare | not sure exactly where, because we ended up deciding against using it |
| 18:41 | callen | mgaare: we'd be hard pressed to get into anything like that, I think. |
| 18:41 | dissipate__ | callen: Hickey should have closed sourced clojure as well, right? |
| 18:42 | callen | mgaare: we're more likely to run into trouble from churning history. |
| 18:42 | callen | dissipate__: no. |
| 18:42 | dissipate__ | callen: what's the difference? |
| 18:42 | callen | you can't really get people to buy into a language like that, like you can a tool like a database. |
| 18:42 | seangrov` | callen: Even a database is tough |
| 18:42 | callen | it is, but Datomic is sufficiently compelling. |
| 18:42 | mgaare | The issue is that if you're doing a query, the peer needs to pull in the entire index for the partition (or at least that's what we concluded was happening) |
| 18:42 | dissipate__ | callen: there's a lot of open source free database engines out there |
| 18:42 | callen | Datomic was so compelling that many-many-many of my coworkers were really into it despite being deeply skeptical of Clojure |
| 18:42 | callen | I...don't really understand why yet. |
| 18:43 | callen | mgaare: so it's index size as a function of pop then probably, okay. |
| 18:43 | dissipate__ | callen: did you pay $3K for diatomic? |
| 18:43 | dissipate__ | er, datomic |
| 18:43 | dissipate__ | callen: you are in a java shop, right? |
| 18:43 | callen | lol no |
| 18:43 | callen | Python. |
| 18:44 | callen | we have a pro license of datomic lying around, yeah. |
| 18:44 | callen | I've been using free and mem while I get the rest of the data firehose hooked up, I'll flip over whenever I get my server. |
| 18:44 | dissipate__ | callen: ah, that's better than java! |
| 18:44 | mgaare | callen: yea. We did some profiling, and what we were seeing with our huge partition was that on a query it would pull in like 600 MB worth of longs (e-ids presumably) and then whatever other data we were querying against, and then immediately GC all of it :D |
| 18:45 | callen | mgaare: fucking lol |
| 18:47 | callen | http://www.informationweek.com/software/information-management/the-man-who-tortures-databases/240160850 |
| 18:48 | callen | mgaare: next step is to just start breaking out partitions roughly by entity type right? |
| 18:49 | callen | hrm. |
| 18:50 | mgaare | callen: that's what we were doing, but the majority of the entities were the same type. What I've concluded is that if you're trying to store a lot of data in datomic, you have to think about the low level stuff about partitioning just as much as you would in any other db |
| 18:51 | callen | mgaare: that's more or less what I expected. |
| 18:51 | callen | Datomic is just nicely designed, it's not magical. |
| 18:51 | mgaare | there was a discussion group post between I think Ian Eslick and Rich that touched on this situation. Ian was trying to store a lot of data about users, and the solution was to create a partition for every 100 or so users |
| 18:52 | callen | ...wat |
| 18:53 | mgaare | I think it was medical data or something, so each user could have a huge number of entities associated with it |
| 18:53 | holo | hi |
| 18:53 | callen | mgaare: oh I see. yeah I saw that his profile mentioned healthcare data. |
| 18:54 | callen | mgaare: I work at a genetics company, but our data "load" per human or logical 'thing' is much smaller |
| 18:54 | callen | tons of raw data from the sequencers themselves, but that gets sifted quickly. |
| 18:55 | callen | Rich handles some loony conversations on the mailing list. |
| 18:56 | mgaare | lisp seems to attract more than its share of strange minds |
| 18:57 | holo | I have a dilemma. I have some pred? that always return some logical truth that is not really true value, but "foo". the problem is, i want to expose those pred? as part of api, and want to give examples of usage, but returning "foo" in examples instead of true looks ugly. should i clutter the pred? implementation with a boolean or similar? or do i have too much free time? |
| 18:57 | sdegutis | I still don't think of Clojure when I see the word "lisp" |
| 18:57 | sdegutis | holo: I'd probably wrap it with boolean too |
| 18:58 | sdegutis | holo: or just document that the function returns "logical true" |
| 18:58 | sdegutis | In that case, people know not to expect literal true |
| 18:59 | callen | mgaare: have you seen Haskell's menagerie of madness? |
| 19:01 | holo | sdegutis, even if I document at the fn, the users still see the usage first in the readme.md, an ugly and probably meaningless "foo". maybe they will be even tempted to reuse that return value as a non boolean value. i'm more and more convinced about the wrap it as boolean option, as you suggested |
| 19:01 | mgaare | callen: a little bit. It has a bit of a different feel though, not sure exactly how to describe it. Filtered through a love of structure, perhaps |
| 19:01 | sdegutis | holo: ah didn't know it would be shown in the readme |
| 19:02 | sdegutis | holo: another option is to just replace the output in the readme with "<truthy value>" |
| 19:03 | holo | sdegutis, insightful. would you represent it verbatim "<truthy value>"? |
| 19:03 | sdegutis | holo: maybe. |
| 19:07 | holo | (inc sdegutis) |
| 19:07 | lazybot | ⇒ 2 |
| 19:07 | sdegutis | yay |
| 19:23 | seangrov` | Any compojure experts? |
| 19:23 | sdegutis | Many. |
| 19:23 | callen | seangrov`: expert no, journeyman...maybe. soup? |
| 19:23 | callen | aka, "just ask" :P |
| 19:24 | seangrov` | Sorry, looked away for a momenth |
| 19:24 | seangrov` | Looking to match on a route either for "/:callback" or "?callback=" - seems like I have to define two separate routes for that though |
| 19:25 | seangrov` | Any way to make the "/:callback" an optional route variable? |
| 19:27 | Brand0 | callback hell |
| 19:30 | callen | seangrov`: is it namespaced or is this top-level? |
| 19:31 | callen | the routes. |
| 19:31 | callen | as in, is there a prefix? |
| 19:31 | seangrov` | No, just the root url |
| 19:32 | seangrov` | Just wondering if there's a way to get compojure to do something like ["/user/:id" :optional :id] |
| 19:32 | callen | not directly, I'm thinking about a couple of indirect ways atm though. |
| 19:33 | callen | let me test something. |
| 19:34 | seangrov` | No a huge deal, just something I've wanted |
| 19:34 | rigger | why are you providing two different apis? |
| 19:35 | SegFaultAX | rigger: Why aren't you?! |
| 19:35 | rigger | because i have no imagination |
| 19:35 | seangrov` | rigger: BAckwards compatibility |
| 19:35 | rigger | gotcha |
| 19:36 | sdegutis | seangrov`: yeah those will need two separate routes |
| 19:36 | SegFaultAX | rigger: http://imgur.com/r/4chan/3YdJs |
| 19:38 | callen | seangrov`: nope. |
| 19:38 | callen | seangrov`: you can do it if you don't mind snagging the param yourself. |
| 19:38 | seangrov` | Ah well, no worries |
| 19:38 | callen | seangrov`: I have a workable solution. |
| 19:39 | SegFaultAX | You wouldn't want to have 1 route anyway. |
| 19:39 | callen | (GET "*" [] route-handler), (str (:params blah)) in the handler => {:* "/blah"} |
| 19:39 | seangrov` | callen: This is what I ended up doing https://www.refheap.com/ad18f6f873ca84e34753cade5 |
| 19:39 | callen | evil/messy, requires invoking the params parser with a wrapper |
| 19:39 | rigger | SegFaultAX: that's awesome |
| 19:39 | callen | seangrov`: hrm, I tried that and it didn't work for me. |
| 19:39 | callen | let me try it again. |
| 19:40 | rigger | seangrov`: are you running this behind a webserver? |
| 19:40 | clojurebot | Titim gan éirí ort. |
| 19:40 | callen | oh yeah that does work. |
| 19:40 | callen | seangrov`: yeah that's way better. I forgot the keyword before the regex in my attempt. |
| 19:40 | SegFaultAX | seangrov`: You want 2 routes. /foos and /foos/:foo_id should logically name different resources. |
| 19:41 | rigger | because i'd just stuff that compatability layer in a rewrite rule |
| 19:47 | sdegutis | All my time being spent in clojure.lang.Reflector.getMethods and .getField means I should probably drop down to Java, doesn't it. |
| 19:47 | sdegutis | :( |
| 19:50 | technomancy | no, just add type hints |
| 19:52 | sdegutis | thanks |
| 19:58 | callen | sdegutis: your life would be easier if you just went through a Clojure book |
| 19:58 | sdegutis | callen: roger |
| 19:58 | callen | sdegutis: and would involve less time-wastey questions |
| 19:58 | sdegutis | :| |
| 20:03 | rasmusto | sdegutis: don't take that the wrong way |
| 20:03 | rasmusto | sdegutis: Clojure Programming followed by Joy of Clojure really are that good |
| 20:04 | callen | ^^ yes. |
| 20:05 | sdegutis | rasmusto: Very good suggestion, thanks. I'm not taking it the wrong way. |
| 20:05 | sdegutis | Although I may have to trip callen if I ever see him walking by in real life. |
| 20:06 | rasmusto | sdegutis: oh? A trip to where? |
| 20:06 | sdegutis | :) |
| 20:06 | sdegutis | callen: you know I'm teasing :) |
| 20:06 | sdegutis | :| |
| 20:09 | sdegutis | :) |
| 20:18 | callen | he's lucky he left. |
| 20:18 | rasmusto | :o |
| 20:19 | callen | rasmusto: I was about to correct him on my not teasing :P |
| 20:19 | callen | I was quite serious when I said he wastes time. |
| 20:19 | rasmusto | callen: I like being told that I'm writing terrible code/wasting time |
| 20:19 | rasmusto | Other people should be too |
| 20:19 | callen | his problem is he refuses to read or really do anything other than poke at projects he'll abandon in a week. |
| 20:20 | callen | and in the process waste peoples' time with his flavor of the week |
| 20:20 | callen | I've seen 1,000 other people on IRC like him |
| 20:21 | callen | productive people often don't have to ask questions that frequently unless encountering something new, so they're sorta invisible. github is sometimes a better measure. |
| 20:21 | mtp | this is why my client has a fools list |
| 20:21 | callen | when was the last time you saw amalloy ask a question that wasn't hypothetical, rhetorical, or sarcastic? |
| 20:22 | amalloy | or irrelevant |
| 20:22 | rasmusto | are we tring to quantify peoples' software productivity? :p |
| 20:22 | callen | I'm not saying asking questions is bad, but you can definitely up your game in terms of the quality of the questions. |
| 20:22 | TEttinger | callen, was that rhetorical? |
| 20:22 | callen | TEttinger: astute. |
| 20:23 | TEttinger | callen, yeah I do think if there was a required reading for IRC, How to Ask Good Questions should be most of it |
| 20:23 | rasmusto | does anybody else know how to ask good questions? |
| 20:24 | callen | http://www.catb.org/esr/faqs/smart-questions.html |
| 20:24 | TEttinger | rasmusto, how do i lern to spel |
| 20:24 | callen | he's a blow-hard, but he's not wrong here. |
| 20:24 | callen | from there, simply not doing things or asking questions for things that can be resolved by reading a basic introduction to the language/library is good etiquette. |
| 20:24 | coventry | rasmusto, If you rephrase that a little more specifically we might be able to help more. For instance, how are the results from your questions inadequate? :-) |
| 20:25 | callen | it's selfish to expect people to piecemeal teach you what there's already excellent material for. |
| 20:25 | rasmusto | coventry: this is getting a bit meta |
| 20:25 | TEttinger | if it's something like lib coverage, yeah, no tutorials have that. that's a good question to ask experienced clojure devs. that's how several people found out about that code threading lib yesterday |
| 20:26 | callen | yep, very good example. |
| 20:26 | callen | or the deeper darker bits of libraries you are using that aren't well documented and for which you're not finding the code very elucidating. |
| 20:33 | callen | oh my dear god I hate mercurial. |
| 20:39 | seangrov` | If I run-jetty in a background thread (:join? false), how can I get access to the error? |
| 20:39 | seangrov` | Err, the output of the server |
| 20:41 | callen | seangrov`: by output do you mean stdout? |
| 20:41 | callen | seangrov`: or something else? |
| 20:42 | callen | stdout should just work. |
| 20:42 | seangrov` | When running `lein ring server` I get the stack trace on errors in the browser |
| 20:42 | callen | do you want them...in the terminal? in a data structure? what do you want? |
| 20:42 | seangrov` | Let me look at how lein-ring does it |
| 20:42 | seangrov` | callen: Yeah, sorry for being vague, will look into it |
| 20:42 | callen | seangrov`: I've solved this very problem, if you just tell me what you want I can... |
| 20:43 | seangrov` | Ah, I'd like the stack trace printed in stdout |
| 20:43 | technomancy | seangrov`: check *nrepl* if using nrepl.el |
| 20:43 | seangrov` | The contractor is using lighttable |
| 20:43 | technomancy | err--*nrepl-server* |
| 20:43 | callen | seangrov`: add a failsafe middleware that catches the error, snags the stacktrace, and prints it to stdout. |
| 20:43 | callen | you can let the error re-bubble or squash it, up to you. |
| 20:43 | seangrov` | Ah, ok |
| 20:43 | technomancy | or better yet put it in the HTTP response |
| 20:44 | callen | lein ring only does its thing for unhandled exceptions. |
| 20:44 | callen | technomancy: that's what lein ring does, puts it in the HTTP response. |
| 20:44 | technomancy | https://github.com/technomancy/syme/blob/master/src/syme/web.clj#L153 |
| 20:44 | technomancy | oh gotcha |
| 20:44 | callen | it's just hoomans. |
| 20:44 | callen | seangrov` wanted stdout...presumably so LT knows what's up. |
| 20:45 | technomancy | it's probably going to stdout, just not to *out* |
| 20:45 | technomancy | System/out that is |
| 20:45 | bja | this might be OT and unwelcome discussion here, but any hints on places to find people who might want to work on a project in clojure/clojurescript in chicago? |
| 20:46 | technomancy | gfredericks is in chicago iirc |
| 20:46 | callen | bja: you might ping the mailing list as well. |
| 20:46 | bja | thanks, I'll give that a shot |
| 20:47 | bja | was at the chicago clojure meetup last month, but had to leave pretty quick after the presentation |
| 20:51 | bja | err, gfredericks seems to work for Groupon. I seem to remember a couple of their recruiters asking me if I'd be interested in clojure for them in chicago... |
| 20:51 | callen | I've been using core.async to force callbacks to self-destruct. I feel like I could be doing this in a better way. |
| 20:51 | bja | callen: self-destruct how? |
| 20:52 | callen | bja: do no evil, return nil. |
| 20:52 | callen | langohr's consumer cancellation stuff is a little awkward when you forget to set a consumer tag. |
| 20:54 | callen | I'm not even really using core.async holistically but I'm still really enjoying using it to clean up code here and there. |
| 20:54 | callen | I'm getting close to turning all of my callbacks into dumb channel funnels. |
| 21:08 | dnolen | callen: fun stuff |
| 21:12 | bbloom | speaking of callbacks, just saw https://idea.popcount.org/2013-09-05-it-aint-about-the-callbacks/ on HN |
| 21:15 | aaelony | this is interesting… a clojure library for financial planning! https://github.com/sebhoss/finj/ has anybody used it? |
| 21:16 | dnolen | bbloom: I've having a back and forth with somebody about that one on Twitter, how a lot of those issues seem solvable with CSP, but he doesn't seem to think so - could be wrong about that - but it doesn't seem so to me. |
| 21:17 | bbloom | dnolen: so i'm beginning to think that it's just generally a good idea to minimize "upward funargs" to use some legacy vernacular |
| 21:17 | bbloom | dnolen: when you register for a callback, you're effectively throwing a closure up to the infinity point of the stack: the event loop |
| 21:17 | dnolen | bbloom: yes |
| 21:17 | bbloom | dnolen: the lower down the stack your event loops & the less closed over context, the easier they are to reason about |
| 21:18 | bbloom | dnolen: another example: higher order functions are easier to reason about than function factories |
| 21:18 | bbloom | dnolen: people seem to have no problem learning map & reduce, but juxt and fnil and friends occur less often b/c people don't think to reach for them as much |
| 21:19 | bbloom | dnolen: but once you close over *state* then you've got a compounded problem |
| 21:25 | dnolen | bbloom: I think the problem with that Twitter discussion is thinking that with CSP you even need a Stream abstraction |
| 21:25 | dnolen | bbloom: agreed on your other points |
| 21:27 | bbloom | dnolen: Add to the infinite queue of projects: IStream that wraps core.async w/ good interop w/ seqs & channels |
| 21:27 | bbloom | dnolen: not that i think it's a good idea |
| 21:27 | dnolen | bbloom: but what would IStream consist of? |
| 21:27 | bbloom | dnolen: basically Rx :-P |
| 21:27 | dnolen | bbloom: I think the the fact that Node.js has the notion of pause/resume troublesome. |
| 21:27 | bbloom | dnolen: it seems to me that it would be useful if you had to write a lot of async code, but much better idea: write a lot less async code |
| 21:29 | dnolen | bbloom: agreed, though of course many cases where you have no choice - those are the cases you want to account for. |
| 21:31 | bbloom | dnolen: yeah, i guess my view is now as follows: |
| 21:32 | bbloom | dnolen: i can get by with like 1 or a very small number of atoms/refs/etc |
| 21:32 | bbloom | dnolen: so i can probably get by with a very small number of async constructs |
| 21:32 | bbloom | dnolen: well, "devices" is probably a better word, to use the zmq terminology |
| 21:32 | bbloom | some bits of code literally need ONE atom |
| 21:33 | bbloom | but other times i've got like one place that makes atoms & i have a variable number of atoms, but only one logical state "device" |
| 21:33 | bbloom | similarly, i suspect the same would be true of async code |
| 21:33 | sdegutis | TEttinger: http://mikeash.com/getting_answers.html is the best one I've found |
| 21:33 | bbloom | dnolen: for example, i might have a server loop & a client loop |
| 21:33 | bbloom | dnolen: or maybe the server also has worker loops |
| 21:33 | bbloom | dnolen: while the running app may have 50+ goroutines, there really are only 3 devices: server, worker, client |
| 21:34 | bbloom | dnolen: for such a small amount of async code, it makes sense to me to use a more general construct, even if it's slightly harder to use, since it will give me the flexibility and clarity i need |
| 21:36 | seancorfield | ooh! *claps hands* core.async talk! |
| 21:37 | seancorfield | i just posted to clojure-dev asking about stability and the proximity of an 0.1.0 release on maven central |
| 21:37 | seancorfield | heck, even an 0.1.0-alpha1 on maven central would make me happy :) |
| 21:38 | bja | +1 to that |
| 21:38 | bja | also, is there a public CI for this? |
| 21:38 | bja | I set one up local to my company as we began experimenting with core.async and wanted to stay abreast of changes |
| 21:39 | seancorfield | build.clojure.org |
| 21:39 | seancorfield | http://build.clojure.org/job/core.async-test-matrix/ specifically |
| 21:39 | seancorfield | all contrib libs are listed here http://dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go with links to their CI status, maven releases, and JIRA bug trackers |
| 21:54 | sdegutis_ | I admit that today and yesterday I've been disrespecting the channel by asking questions that I really should have researched myself first. There's no excuse for that, and I'm going to make a more conscious effort to do my homework thoroughly before wasting anyone's time in here. I apologize. |
| 21:54 | sdegutis_ | But it's not always caused by habitual help vampirism. I work remotely and rarely communicate with other programmers, so socializing on IRC is a big help. And I'm sure I'm not the only person in this boat. And when you're already in here and have a question on the mind, the habit of typing it in the channel as a way of rubber-ducking can gradually form, much like thinking out loud. |
| 21:54 | sdegutis_ | And I recommend http://mikeash.com/getting_answers.html for future reference, it's written in a very welcoming style, much more likely to actually be read than some of the alternatives. |
| 21:54 | sdegutis_ | \cc callen |
| 21:55 | muhoo | sdegutis_: don't sweat it. i was a total black-hole of dumbass when i first started with clojure, way more than anyone i've seen on here since. |
| 21:56 | brehaut | "a total black-hole of dumbass" love it |
| 21:56 | muhoo | now i've got enough of my brain around this stuff that i can figure out most of what i need to just by reading docs and books and experimenting. you'll get there. |
| 21:57 | muhoo | sometimes it just takes doing a few large-ish projects to find the horizon. |
| 21:59 | seancorfield | I'm actually impressed that #clojure has gotten so big without needing some sort of #clojure-n00b channel to help filter lots of basic questions away |
| 22:01 | ddellacosta | sdegutis_: I talked to you a lot yesterday and generally felt like you were being a pretty good IRC citizen. |
| 22:01 | sdegutis_ | ddellacosta: Nah, I asked a few too many questions yesterday, and way too many today. |
| 22:02 | ddellacosta | sdegutis_: I feel like IRC is for asking questions, and if people want to say, RTFM they can, and if they want to say, "here's one way to do it" they can do that too. So I don't know what you did that was particularly bad, but I can understand personally feeling the need to dial it back. |
| 22:02 | ddellacosta | sdegutis_: okay. Well, I'm not going to question your own feelings on the thing, but just giving you my subjective impression. |
| 22:02 | sdegutis_ | :) |
| 22:02 | seancorfield | Some channels are a lot more tolerant of "noise" than others, as well. |
| 22:02 | sdegutis_ | Part of the charm of #clojure is that the maturity level is (generally) extremely high, which means a really high signal/noise ratio. |
| 22:03 | seancorfield | indeed. |
| 22:03 | ddellacosta | SeanCorfield: I think there are times when it is noisy on here (and I am guilty of contributing to that) and times with a super high sound-to-noise ratio, but generally it's a good place to be. |
| 22:03 | TimMc | sdegutis_: And to the extent that you were exhibiting *any* bad behavior (very little!), callen was being a dick about it. |
| 22:03 | ddellacosta | s/sound/signal/ |
| 22:04 | sdegutis_ | TimMc: meh, we all have our bad days, all I can say is that I'm sorry that I was disrespectful to everyone in here and I'm gonna try to avoid it better from now on. |
| 22:04 | ddellacosta | callen can be a tough customer and prickly but generally he means well, in my experience. |
| 22:04 | TimMc | There's a 40% chance I would have banned callen by now if I were the channel founder. |
| 22:05 | TimMc | Smart guy, has good experience... but pretty rude. |
| 22:05 | ddellacosta | TimMc: mean, he's helped me a TON on here, I just have to say. I know he rubs some people the wrong way but I get on with him pretty well, and I know a bunch of folks who do as well. |
| 22:06 | ddellacosta | TimMc: yeah. I mean, again just expressing my subjective experience. I know everyone interacts with him differently. |
| 22:06 | TimMc | Oh, and I'm not talking about a permaban, just a 5 minute kickban. |
| 22:06 | sdegutis_ | Anyone know of some good references on optimizing Clojure code, especially in tight loops where Java interop is happening? I've been reading Programming Clojure about type hints and when to use defrecord vs [etc], as well as the chosen answer here: http://stackoverflow.com/questions/5549319/real-world-clojure-performance-tuning-tips |
| 22:08 | ddellacosta | sdegutis_: depending on the problem at hand, I've had swapping out clojure data structures for java native data structures to produce a lot of speed gains, but of course it comes at a price |
| 22:08 | ddellacosta | sdegutis_: sorry, you asked for references |
| 22:08 | technomancy | usually if there is reflection in a tight loop, it will overshadow any other potential causes of slowdowns |
| 22:08 | sdegutis_ | technomancy: good to know |
| 22:09 | ddellacosta | great link btw |
| 22:09 | ddellacosta | mikera knows his shit... |
| 22:09 | technomancy | especially dispatch; you can optimize dispatch all day and you won't notice if there's a reflective call |
| 22:10 | sdegutis_ | technomancy: hmm.. |
| 22:10 | technomancy | sdegutis_: `lein check` will show all reflective points |
| 22:11 | sdegutis_ | technomancy: what do you mean by dispatch? |
| 22:11 | sdegutis_ | technomancy: *whoa*, cool |
| 22:11 | technomancy | sdegutis_: like replacing multimethods with protocols |
| 22:11 | sdegutis_ | ahh |
| 22:11 | technomancy | but `lein check` will include ones that aren't in tight loops, so pay attention |
| 22:11 | sdegutis_ | right :) |
| 22:12 | sdegutis_ | Yeah I read recently that multimethods were deprecated in favor of protocols.. Not sure if that's legit though, gotta research more. |
| 22:12 | ambrosebs_ | sdegutis_: on HN? |
| 22:12 | technomancy | totally BS |
| 22:13 | technomancy | multimethods are much more powerful |
| 22:13 | sdegutis_ | ambrosebs_: don't think so.. |
| 22:13 | brehaut | structs were deprecated in favour of records, but thats the only related deprecation |
| 22:14 | ambrosebs_ | sdegutis_: I remember a comment on a very popular Clojure post. That guy was full of it. |
| 22:14 | ambrosebs_ | nvm |
| 22:14 | sdegutis_ | Oh, "Use deftype/defrecord/defprotocol where appropriate. These are heavily optimised, and in particular should be preferred to defstruct/multimethods as of Clojure 1.2 onwards." in that SO link. |
| 22:14 | sdegutis_ | I misinterpreted what he said. |
| 22:16 | technomancy | still pretty suspect |
| 22:17 | cjfrisz_ | Oh man..I missed the conversation about being able to ask newb questions |
| 22:18 | cjfrisz_ | I was really cranky about the "don't ask questions when there's so much great documentation," but took the coward's way out of grumbling into my code instead of saying anything |
| 22:19 | seancorfield | great documentation? where? |
| 22:19 | ambrosebs_ | haha |
| 22:20 | seancorfield | mmm, core.async would be such an elegant solution to a problem i have to solve (for real production code!)... just did a p.o.c. and it's so much cleaner than anything else i've yet come up with for this problem... |
| 22:21 | mlb- | What's the commonly refered name of the "->" macro? |
| 22:21 | seancorfield | thread |
| 22:21 | seancorfield | thread-first for -> and thread-last for ->> |
| 22:21 | cjfrisz_ | mlb-: also known as one of my least favorite parts of Clojure |
| 22:21 | seancorfield | (i believe) |
| 22:21 | seancorfield | cjfrisz_: you no like? nor as-> / some-> / cond-> i guess? :( |
| 22:22 | S11001001 | seancorfield: we always called it arrow |
| 22:22 | mlb- | cjfrisz_: easily abused? |
| 22:22 | S11001001 | hence rplevy's "swiss-arrows" name for his lib |
| 22:22 | cjfrisz_ | seancorfield: I actually really like as-> |
| 22:22 | cjfrisz_ | Haven't messed with the others yet |
| 22:23 | cjfrisz_ | mlb-: I find that they make code unreadable for non-trivial uses |
| 22:23 | sdegutis_ | cjfrisz_: but as-> only makes sense inside -> or ->> |
| 22:23 | ddellacosta | SeanCorfield: what's stopping you from using core.async--the pre-alpha-status of the lib? (Admittedly enough I suppose, even if it works quite well) |
| 22:23 | cjfrisz_ | sdegutis_: I disagree |
| 22:23 | sdegutis_ | cjfrisz_: and I have to disagree, -> and ->> make code way more readable in my experience |
| 22:23 | seancorfield | ddellacosta: leiningen scowls on having release builds depending on snapshots :) |
| 22:23 | cjfrisz_ | sdegutis_: I find that depends on prior experience reading inside-out Lisp code? |
| 22:23 | cjfrisz_ | Er…not ? |
| 22:24 | seancorfield | ddellacosta: and this is production code, after all so i'm wondering how stable core.async really is... |
| 22:24 | cjfrisz_ | sdegutis_: Also, I find as-> as a _replacement_ for -> in many places |
| 22:24 | ddellacosta | SeanCorfield: ah. I always rename things and install via uberjar, maybe it's bad form. ;-) |
| 22:24 | ddellacosta | SeanCorfield: yeah, that's a fair point. I ask because I'm in a similar boat, and wanted to know if you'd experienced anything in particular... |
| 22:25 | sdegutis_ | cjfrisz_: here's one use of -> I like https://www.refheap.com/16959 |
| 22:25 | cjfrisz_ | For stuff like (-> my-map :int-key inc), I think -> is fine, but when you have functions in there that take multiple arguments, it quickly turns into a mess |
| 22:25 | sdegutis_ | cjfrisz_: that sounds highly suspect to me |
| 22:25 | seancorfield | ddellacosta: i asked on clojure-dev for guidance but may go ahead and integrate my p.o.c. and just hammer it under test... |
| 22:25 | TimMc | mlb-: I prefer "stitch-first" and "stitch-last" to avoid confusion with concurrency topics. :-) |
| 22:25 | bja | ddellacosta: I took the implement and measure approach. we've already shipped some alpha releases of a dashboard/search system based on core.async to our internal group |
| 22:26 | ddellacosta | SeanCorfield: yes, would definitely be interested to hear more what your experiences are like. |
| 22:26 | sdegutis_ | "The friend of my friend is my enemy" |
| 22:26 | ddellacosta | bja: glad to hear it. No big issues so far? |
| 22:26 | bja | ddellacosta: plans on releasing to paying customers in a private beta in about a month |
| 22:26 | bja | nope |
| 22:26 | bja | we have nothing to compare it to though |
| 22:26 | ddellacosta | bja: that's part of the problem, haha |
| 22:26 | bja | but we were doing stress testing to make sure it's capable of handling the load we want to throw at it |
| 22:26 | cjfrisz_ | sdegutis_: I really find it comes down to personal taste |
| 22:27 | ddellacosta | bja: but yeah, I've written a half dozen little one-offs with it by now, and will start writing some code integrating it on the CLJS side at first |
| 22:27 | seancorfield | it's not like we haven't gone to production with prerelease builds before... we went live with clojure 1.3 alpha 7 two years ago... and we've been using alpha builds of java.jdbc 0.3.0 in production for... months... |
| 22:27 | sdegutis_ | cjfrisz_: let's agree to disagree about that |
| 22:27 | ddellacosta | SeanCorfield: yah, good point |
| 22:27 | cjfrisz_ | sdegutis_: There was a newbie in here at one point who got understandably confused about lexical scope because a piece of code he was looking at used -> in a weird way |
| 22:27 | cjfrisz_ | And I was already predisposed against it, so that completely soured me on it |
| 22:28 | seancorfield | bja: your experience sounds encouraging ... thank you! |
| 22:28 | ddellacosta | ditto |
| 22:28 | bja | ddellacosta: we were in a boat of nobody really being a frontend person so we had to pick something to learn to ship an app. cljs+core.async seemed less threatening than needing to learn angular |
| 22:28 | sdegutis_ | cjfrisz_: ->> is almost mandatory for clean code when doing a bunch of map/filter/etc in a row |
| 22:28 | bja | then again, none of us have every really done anything besides integrating jquery plugins before either. so our app probably looks nothing like a typical web app |
| 22:29 | bja | although it does remind me a Qt app I wrote once |
| 22:30 | cjfrisz_ | sdegutis_: I see your point, though I'd likely break up that computation rather than use ->> (again, personal taste |
| 22:30 | ddellacosta | bja: interesting. I'm now struggling through the right paradigm to use for frontend development. Having Clojure on the backend and CLJS on the front-end brings some gains in terms of avoiding context switching and maintaining similar data structures, but I'm really looking forward to being able to do stuff (along with browser channel) where we are pushing messages back and forth on channels using only core.async. But that's not |
| 22:30 | ddellacosta | really addressing the stuff regarding DOM updates, so still trying to figure that part out. |
| 22:30 | cjfrisz_ | Even though bbloom and I just had a conversation about how I don't like to let-bind computations that get used exactly once :-) |
| 22:30 | sdegutis_ | cjfrisz_: can you show me an example of it broken up like you say? Maybe I just haven't seen it done right. |
| 22:30 | ddellacosta | bja: this was an interesting, useful article I thought: http://keminglabs.com/blog/cljs-app-designs/ |
| 22:30 | callen | seanaway: are you at the meetup? |
| 22:30 | callen | TimMc: <3 you too. |
| 22:31 | seanaway | callen: no, couldn't make it this month, nor next, so Amit is running the SF group for a while |
| 22:31 | ddellacosta | bja: but anyways, always interested to hear more about what people's experiences have been with CLJS, especially with core.async |
| 22:31 | bja | in our app, we have a "widget controller" which coordinates with other widgets and our query service. It's responsible for maintaining it's local data structure and rending it into a template when it changes |
| 22:31 | callen | seanaway: cool, well hopefully I'll catch you sometime in the near future, would love to talk about c.j.j for a bit. |
| 22:31 | seanaway | ddellacosta: we're consider cljs + angularjs based on some of the stuff kevin lynagh posted about the kerning labs app etc |
| 22:32 | ddellacosta | damn, maybe I should move to a city/country with a Clojure meetup…or I guess start one here |
| 22:32 | callen | seanaway: keming labs ain't it? or is that the joke? |
| 22:32 | ddellacosta | seanaway: definitely want to talk more. I'm reluctant to integrate angular but I haven't given it a fair shake yet, to be honest |
| 22:32 | TimMc | callen: I wouldn't *like* to do it. :-( |
| 22:33 | seanaway | callen: i won't be at any meetups for a while - ping me on IM if you want (skype, aim, y!m... or gtalk... should be obvious what my handle is on all of those :) |
| 22:33 | callen | ddellacosta: I'm fond of Angular, but you have to be okay with the design philosophically speaking. |
| 22:33 | callen | seanaway: fair enough, thanks :) |
| 22:33 | callen | TimMc: awww. thank you. :) |
| 22:33 | ddellacosta | callen: yeah, I should write a few simple apps with it to get a feel before I judge it |
| 22:33 | seanaway | oh year, keminglabs.com ... always read that as k-e-r-n-ing... silly me! |
| 22:34 | TimMc | seanaway: Every. Single. Time. |
| 22:34 | ddellacosta | ddellacosta: mostly I'm not excited about integrating an outside JS lib, but that's probably irrational |
| 22:34 | seanaway | http://keminglabs.com/blog/ |
| 22:34 | ddellacosta | whoops, addressed me |
| 22:34 | ddellacosta | was to callen |
| 22:34 | cjfrisz_ | sdegutis_: https://gist.github.com/cjfrisz/7f3e118098bb7a472e62 |
| 22:34 | callen | ddellacosta: very good idea. part of the reason I like angular is that it lends itself well to being isolated widgets, pages, and growing from there to whole apps. |
| 22:35 | ddellacosta | callen: interesting. I'll give it a shot and see what I learn. |
| 22:35 | callen | ddellacosta: well you just have to decide if Angular does things in a way you're happy with. I think it's a productive way to do most SPAs. |
| 22:35 | sdegutis_ | cjfrisz_: why do you prefer the last one? because it has all 3 args in it at once? |
| 22:35 | ddellacosta | callen: yeah, we have a…semi-SPA, so it may be appropriate, we'll see. |
| 22:35 | cjfrisz_ | sdegutis_: I didn't repl-check that code, so it might have typos in it |
| 22:35 | sdegutis_ | cjfrisz_: I mean, because each fn (map/reduce) have all args and no magic? |
| 22:35 | cjfrisz_ | sdegutis_: precisely |
| 22:36 | sdegutis_ | cjfrisz_: hmm, that is kind of neat |
| 22:36 | ddellacosta | callen: but anything is better than what we have now, which is a mix of old CoffeeScript with a ton of hard-coded selectors, which I'm slow porting over, and some "stopgap" CLJS |
| 22:36 | ddellacosta | makes me cry |
| 22:36 | callen | ddellacosta: yikes. |
| 22:36 | sdegutis_ | It certainly eliminates the need for as-> within it for when the arg isn't in the position you wnat |
| 22:36 | ddellacosta | callen: yeah, I do a lot of sticking fingers in leaking holes |
| 22:37 | ddellacosta | callen: meh, it did what it needed to do for a while though, and it'll get better. |
| 22:37 | sdegutis_ | cjfrisz_: btw I made a slight adjustment to how I'd do the ->> version: https://gist.github.com/cjfrisz/7f3e118098bb7a472e62#comment-901309 |
| 22:38 | cjfrisz_ | sdegutis_: Ah, that does make it a little better |
| 22:39 | cjfrisz_ | sdegutis_: There's still something that bothers me about implicitly keeping track of where the invisible value gets inserted |
| 22:39 | sdegutis_ | cjfrisz_: I can see that. I'm not sure where I stand on the issue now that you gave this example. |
| 22:39 | sdegutis_ | cjfrisz_: thanks |
| 22:39 | cjfrisz_ | sdegutis_: no problem :-) |
| 22:40 | bbloom | cjfrisz_: gotta embrace the threading macros :-) |
| 22:40 | cjfrisz_ | bbloom: nooooooooo :-O |
| 22:40 | bbloom | cjfrisz_: they make pipelines incredibly clear |
| 22:40 | sdegutis_ | I'll defer my opinion on it: (def my-opinion (future (defer-opinion gfredericks))) |
| 22:40 | bbloom | cjfrisz_: also make it super nice to skip or insert steps when debugging |
| 22:41 | cjfrisz_ | If those pipelines are all (rator rand) then I'm totally cool with it |
| 22:41 | bbloom | cjfrisz_: for example try throwing (doto prn) into a -> pipeline |
| 22:41 | bbloom | glorious. |
| 22:41 | sdegutis_ | bbloom: have you seen his example? |
| 22:41 | sdegutis_ | bbloom: https://gist.github.com/cjfrisz/7f3e118098bb7a472e62#file-gistfile1-clj |
| 22:41 | bbloom | sdegutis_: what about it? |
| 22:41 | sdegutis_ | bbloom: as-> looks compelling in it |
| 22:42 | bbloom | sdegutis_: *shrug* not if they are all thread-last |
| 22:42 | sdegutis_ | no implicitness about arg positions, it's all on screen |
| 22:42 | bbloom | sdegutis_: there is no implicitness with -> and ->>, it's right there lexically explicit :-) |
| 22:43 | bbloom | but i'm the guy who wrote a concatenative DSL, so my opinion might not count here :-P |
| 22:43 | bbloom | swap, dip, keep, drop, bi, cleave, etc -- now *that's* implicit :-) |
| 22:43 | sdegutis_ | bbloom: also I've had times where I wanted to do another form in the middle of the threading (maybe a let-block) and the magic stepped on my toes, but with this as-> version that's a non-issue |
| 22:44 | sdegutis_ | granted, I can't think right now of *legitimate* reasons for wanting to stick something in the middle of such a threading chain, but it could have been legit |
| 22:44 | bbloom | basically the style rule is that -> for threading through "this" and you can think of -> the same way you think of dotted.memberAccess.likeThis.inOOP |
| 22:45 | bbloom | and ->> threading through last for when you've got a bunch of operations where it would make a lot of sense to curry the first args, like sequence ops. in cjfrisz_'s example, you could conceivably (def sum (comp reduce +)) and (def product (comp apply *)) |
| 22:45 | bbloom | nevermind that you could also apply + and reduce * 1 ;-) |
| 22:46 | cjfrisz_ | bbloom: thanks for simplifying my highly contrived example ;-) |
| 22:47 | sinistersnare | i always have trouble understanding -> |
| 22:47 | sinistersnare | i get its threading, but being a clojure (/lisp) newbie, its still hard to fathom |
| 22:47 | callen | sinistersnare: ,,, |
| 22:47 | bbloom | sinistersnare: that's why i draw the parallel between -> and dotted access chains |
| 22:47 | nightfly | sinistersnare: Look at how the macro is expanded a few times. |
| 22:47 | callen | sinistersnare: http://blog.fogus.me/2013/09/04/a-ha-ha-ha-aah/ |
| 22:47 | TimMc | Yeah, ,,, is a good crutch. |
| 22:48 | bja | sinistersnare: clojure.walk/macroexpand-all is your friend |
| 22:48 | callen | bja: just let the ,,, magic happen. |
| 22:48 | bbloom | bja: except when it lies to you :-P |
| 22:48 | bja | bbloom: macroexpand lies to you? I feel like I'm getting lied to and I don't know it |
| 22:48 | gfredericks | what is this ,,, nonsense? |
| 22:49 | coventry | bja, bbloom: riddley.walk/macroexpand-all tries to do a more accurate job. |
| 22:49 | gfredericks | is this what fogus was tooting about? |
| 22:49 | coventry | If you're going to use ,,, why not use as->? |
| 22:49 | sinistersnare | oh cool |
| 22:49 | gfredericks | oh it's sticking a comma in the threading position for reference? or three commas? |
| 22:49 | callen | gfredericks: yeah |
| 22:49 | bbloom | the best thing about -> and ->> is that they are obvious to indent. i still can't figure out how to indent multi-line chains in java, scala, javascript, coffeescript, etc |
| 22:50 | callen | gfredericks: yeah to both questions. |
| 22:50 | callen | another way to learn how -> and ->> work is to reinvent them. |
| 22:50 | gfredericks | oh look he has a blag |
| 22:50 | callen | I don't think they merit much pondering though. |
| 22:52 | dobry-den | haha, i just read about ,,, on http://rubylearning.com/blog/2010/07/26/clojure-tips-from-the-experts/ |
| 22:53 | cjfrisz_ | bbloom: my only problem with -> and ->> is that there's just a touch more parsing you have to do in your head when reading them to remember where the implicit expression is going to go |
| 22:54 | bbloom | cjfrisz_: but less paren counting :-) |
| 22:54 | dobry-den | or when ->> works for all argument order except for one function |
| 22:54 | bbloom | cjfrisz_: they can dramatically reduce stacked up close parens |
| 22:55 | cjfrisz_ | bbloom: Look, I've written a *lot* of Scheme in my time; I'm so friggin fast at counting those parens :-p |
| 22:55 | Foxboron | cjfrisz_: i think having a imperative background helps you a lot reading ->> and -> |
| 22:55 | cjfrisz_ | I think it also relates to why I don't like let* in general in Scheme |
| 22:55 | bbloom | cjfrisz_: it's interesting. i love the prefix notation & much prefer the explicitness of parens, but if i see like ))))) i suddenly cringe & refactor |
| 22:55 | Foxboron | my only problem is trying to recall which one does what |
| 22:56 | bbloom | cjfrisz_: a few extra names here or there can dramatically reduce stacked up parens & make code much easier to read |
| 22:56 | sdegutis_ | technomancy: wow thanks for the tip for lein check, this is super helpful |
| 22:56 | cjfrisz_ | That's why I'm currently a fan of as-> |
| 22:56 | cjfrisz_ | It takes care of most of that bit of mental parsing by naming the bit that's getting threaded through |
| 22:57 | bbloom | cjfrisz_: but when i see as-> i say "oh no, i have to be on the look out for non-standard argument positions" |
| 22:57 | bbloom | cjfrisz_: it's like when people stick fucking ! on everything |
| 22:57 | sinistersnare | ,(doc as->) |
| 22:57 | clojurebot | "([expr name & forms]); Binds name to expr, evaluates the first form in the lexical context of that binding, then binds name to that result, repeating for each successive form, returning the result of the last form." |
| 22:58 | cjfrisz_ | bbloom: It's not really any worse than a let-bound variable |
| 22:58 | bbloom | cjfrisz_: right, but it's also no better ;-) |
| 22:58 | bbloom | cjfrisz_: as-> is strictly less clear than let, unless you're mixing it in to an existing -> and ->> |
| 22:58 | bbloom | so far, i've needed as-> like twice ever |
| 22:59 | cjfrisz_ | bbloom: That's probably because you're more willing to use -> or ->> than me |
| 22:59 | cjfrisz_ | I totally use as-> in places where other people would use -> or ->> |
| 23:00 | bbloom | cjfrisz_: but in your "best, in my opinion" example. why not just use let? |
| 23:00 | bbloom | https://gist.github.com/cjfrisz/7f3e118098bb7a472e62 <- i added a comment |
| 23:01 | bbloom | oh dur, i'm an idiot |
| 23:01 | cjfrisz_ | bbloom There's something uneven looking about those kinds of lets |
| 23:01 | bbloom | wait, i don't even know how as-> works |
| 23:01 | cjfrisz_ | bbloom: Again, why I'm always cranky that Clojure only has let* semantics for let |
| 23:01 | bbloom | (doc as->) |
| 23:01 | clojurebot | "([expr name & forms]); Binds name to expr, evaluates the first form in the lexical context of that binding, then binds name to that result, repeating for each successive form, returning the result of the last form." |
| 23:01 | bbloom | so does num-vec change it's binding every time? |
| 23:01 | bbloom | i've never used an as-> bound name more than once |
| 23:01 | bbloom | are those 3 different values for num-vec ? |
| 23:02 | bbloom | i *never* override names unless it's a loop or something really obvious |
| 23:02 | bbloom | i'd rather have num-vec and num-vec* and num-vec** or some more descriptive names |
| 23:02 | bbloom | cjfrisz_: as for parallel let, that's b/c clojure discourages you from having cyclic structures, which is actually a really good thing |
| 23:02 | bbloom | cjfrisz_: if you're gonna have immutable data, then a cycle KILLS your potential for structural sharing |
| 23:03 | bbloom | cjfrisz_: you can't copy *part* of a cyclic structure |
| 23:03 | bbloom | cjfrisz_: you need an indiction, which is what "identities" give you (ie IDeref) |
| 23:03 | bbloom | cjfrisz_: s/indiction/indirection/ |
| 23:04 | bbloom | cjfrisz_: the ease with which you can tie the knot in haskell is a very bad thing. it's absurdly difficult to reason about pointer cycles |
| 23:04 | cjfrisz_ | bbloom: In all the times that I've complained about let, nobody has ever made that argument |
| 23:04 | cjfrisz_ | I'ma need to let that one soak in for a minute |
| 23:04 | bbloom | pointers are like having only one concrete implementation of IDeref |
| 23:04 | bbloom | where you can't ever change the value it points to |
| 23:05 | bbloom | a pointer is the least useful type of identity there is |
| 23:05 | bbloom | there can be no sensible succession of values |
| 23:05 | bbloom | that's why there is letfn: you can't edit a function anyway, so there is no sense having structural sharing |
| 23:05 | bbloom | but if there was, you'd just inline one mutually recursive function in to the other |
| 23:06 | cjfrisz_ | bbloom: I'm really not sure if I'm misunderstanding you or you me |
| 23:06 | bbloom | cjfrisz_: you're talking about sequential vs parallel let, right? |
| 23:06 | bbloom | cjfrisz_: scheme & common lisp have let and let* |
| 23:06 | bbloom | let is parallel, let* is sequential |
| 23:06 | cjfrisz_ | I understand your point, but for the life of me can't wrap my brain around how it relates to Scheme's let semantics |
| 23:06 | bbloom | clojure has let and letfn |
| 23:06 | bbloom | let is sequential, letfn is parallel |
| 23:07 | cjfrisz_ | bbloom: right |
| 23:07 | bbloom | parallel bindings enable cyclic structures |
| 23:08 | bbloom | cyclic structures are an anti-feature for most use cases, in my opinion |
| 23:08 | sdegutis_ | amalloy_: does being so prolific on stackoverflow get many contracting gigs knocking on your door? |
| 23:08 | cjfrisz_ | bbloom: You seem sure enough that I don't want to discount what you're saying, but I don't think that Scheme/CL let enables cyclic structures the way you're claiming |
| 23:08 | cjfrisz_ | letrec, yes |
| 23:09 | bbloom | cjfrisz_: i haven't written much scheme/CL, so let me go look at docs & refresh my memory. but i can't see what the point of parallel bindings would be w/o recursive definitions |
| 23:11 | gfredericks | I just tried scheme |
| 23:11 | gfredericks | let is parallel in the sense of none of them are visible to the others |
| 23:11 | cjfrisz_ | bbloom: Scheme/CL -- (let* ([a 1] [b a] [c b]) c) === (let ([a 1]) (let ([b a]) (let ([c b]) c))) |
| 23:12 | bbloom | ok so i had forgotten about letrec |
| 23:12 | cjfrisz_ | let* in Scheme is always a really simpl |
| 23:12 | bbloom | what's the use of parallel let without letrec ? |
| 23:12 | cjfrisz_ | Er…didn't mean to send that |
| 23:12 | bbloom | cjfrisz_: i get the usefulness of let* and letrec, but what's the use of let? |
| 23:13 | cjfrisz_ | bbloom: Makes lexical scope clearer and discourages imperative programming |
| 23:13 | bbloom | cjfrisz_: in what way does it do either of those things? |
| 23:13 | gfredericks | (letrec ((x (cons 3 '())) (y (cons 4 x))) y) ;; => (4 . #!unbound) |
| 23:14 | cjfrisz_ | bbloom: let* in Scheme when used properly is a signal of "these bindings are very much related and the value of one is dependent on the other" |
| 23:14 | sdegutis_ | you guys are such nerds |
| 23:14 | sdegutis_ | so awesome :) |
| 23:14 | cjfrisz_ | sdegutis_: :-D |
| 23:15 | callen | cjfrisz_: I have sequential bindings so often that I like sequential let being the default. |
| 23:15 | gfredericks | maybe that's the imperative programming he was referring to? |
| 23:15 | cjfrisz_ | ^^^ |
| 23:16 | cjfrisz_ | There's certainly nothing wrong with it |
| 23:16 | bbloom | cjfrisz_: *shrug* i don't like to shadow names if i can help it, so when i cursor over a name and it lights up in other places, i can see the dataflow. if it shows up on the very next line, then yeah, it's sequential :-P |
| 23:16 | cjfrisz_ | The downside the parallel let is that it tends to make your code indent further |
| 23:16 | amalloy | sdegutis_: i don't do contracting; being prolific on SO and IRC is what got me my current job |
| 23:17 | sdegutis_ | amalloy: ok |
| 23:17 | cjfrisz_ | But preferring parallel let does make it obvious that any variable is bound in a strictly enclosing scope |
| 23:17 | bbloom | cjfrisz_: hold on. gotta kill a giant fucking bug |
| 23:17 | gfredericks | man bbloom gets passionate about debugging |
| 23:18 | bbloom | cjfrisz_: no like one with legs.... |
| 23:18 | cjfrisz_ | gfredericks: I think bbloom is just into really, *really* traditional debugging |
| 23:18 | bbloom | er i mean cjfrisz_ |
| 23:18 | gfredericks | man bbloom really does not want to say my name |
| 23:19 | gfredericks | cjfrisz_: that's interesting about the scoping |
| 23:21 | bbloom | LOL |
| 23:21 | bbloom | gfredericks: sorry man |
| 23:21 | cjfrisz_ | gfredericks: it's nice |
| 23:21 | bbloom | gfredericks: total brain fart b/c i had to kill that ugly mother fucker |
| 23:21 | bbloom | gfredericks: no idea what that thing was, it had like a ton of legs & didn't look friendly |
| 23:22 | bbloom | cjfrisz_: but w/ parallel let, that scope is *further down* under the other bindings |
| 23:22 | bbloom | cjfrisz_: w/ sequential let, it's the very next line. close locality |
| 23:22 | cjfrisz_ | bbloom: but then you don't have indentation as a visual cue |
| 23:22 | bbloom | cjfrisz_: yeah, it's a larger extent than w/ parallel let, but i don't think it's a big deal |
| 23:23 | cjfrisz_ | bbloom: Agreed. I'm just an old PL curmudgeon and don't like things that are different than what I'm used to |
| 23:24 | bbloom | cjfrisz_: *shrug* i think i'd get annoyed that i'd have to nest more deeply if i wanted to use a binding in an intermediate expression. i like forms that flatten my code |
| 23:26 | bbloom | cjfrisz_: as for the "imperative style" thing, i think you need to ask yourself "why is it a good thing that i don't program in an imperative style?" |
| 23:26 | bbloom | cjfrisz_: if your answer is "functional is good" then you lose :-) |
| 23:27 | bbloom | cjfrisz_: clojure is all about… because rich is all about…. separating out the components of things to understand the essence of why we do things the way we do them & how we can do them better |
| 23:27 | bbloom | cjfrisz_: turns out that immutablity is 100X more important than not sequentially refining values |
| 23:27 | cjfrisz_ | bbloom: I don't dispute that |
| 23:28 | cjfrisz_ | bbloom: but it's still nice to have separate let and let* to make the visual distinction of when rebinding is likely to happen |
| 23:28 | cjfrisz_ | If it bugged me that much I would probably have a far lower volume of Clojure code |
| 23:28 | cjfrisz_ | It's just one of those things that Schemers notice and think is weird and people who started with Clojure don't notice and think is fine |
| 23:28 | bbloom | fair enough :-) |
| 23:29 | bbloom | but the letrec thing is a big deal ;-) |
| 23:29 | bbloom | cyclic structures without explicit identities == nightmare |
| 23:29 | bbloom | brb |
| 23:30 | cjfrisz_ | bbloom: Agreed |
| 23:30 | cjfrisz_ | bbloom: Hence why there had to be a series of papers called "Fixing Letrec" |
| 23:30 | cjfrisz_ | It turns out that pretty much all of them do it wrong |
| 23:31 | cjfrisz_ | I do have to say that it's really, really smart that Rich decided not to add letrec to Clojure |
| 23:35 | sdegutis_ | I find myself day after day saying "wow, Rich (and the team?) made a great decision [including/excluding] [that/that] feature". |
| 23:35 | cjfrisz_ | sdegutis_: agreed |
| 23:36 | shaungilchrist | it is definitely what keeps me happy with clojure |
| 23:36 | unlink | When I run `lein ring server', it thinks for a second, and then exits with error code 0, printing nothing. |
| 23:36 | cjfrisz_ | Overall, Clojure is a really well-designed language |
| 23:36 | sdegutis_ | unlink: does your project.clj point to a legit handler? |
| 23:36 | unlink | sdegutis_: yes. |
| 23:36 | cjfrisz_ | Most of my qualms are nit-picky, and the things that bother me the most are because of the JVM |
| 23:37 | unlink | lein ring war works. |
| 23:37 | cjfrisz_ | But the benefits of the JVM are also really nice |
| 23:37 | sdegutis_ | Yeah, I do enjoy that my code is much faster than Ruby. |
| 23:38 | cjfrisz_ | sdegutis_: I lolled |
| 23:39 | bbloom | cjfrisz_: i'm not familiar with the fixing letrec series. what's the gist? |
| 23:39 | shaungilchrist | It definitely helps to be able to show the viability of jvm interop when a potential client winces when you say "lisp" |
| 23:39 | sdegutis_ | shaungilchrist: oh man, you get clients? |
| 23:40 | shaungilchrist | just build things people want and it happens |
| 23:40 | unlink | hah |
| 23:40 | gws | you can even build things people don't want, and hire "sales people" (i dunno, that's what they said to call them) to convince "clients" that they want the thing |
| 23:40 | sdegutis_ | shaungilchrist: but I have.. https://github.com/sdegutis/zephyros |
| 23:41 | sdegutis_ | gws: that seems downright immoral |
| 23:41 | cjfrisz_ | bbloom: That dealing with undefined values is really hard when you allow for arbitrary cyclic expressions |
| 23:41 | cjfrisz_ | bbloom: It gets even worse when you have first-class continuations in the mix |
| 23:41 | gws | sdegutis_: i agree, but somebody said it was "good business sense" and i just believed them |
| 23:41 | sdegutis_ | :) |
| 23:41 | sdegutis_ | oh man, just one more star |
| 23:43 | bbloom | cjfrisz_: yeah, i'm 100% against cyclic pointer structures, as you can tell |
| 23:43 | cjfrisz_ | bbloom: Me too |
| 23:43 | cjfrisz_ | I honestly don't remember the last time I used a letrec |
| 23:44 | bbloom | cjfrisz_: as for first-class continuations, oleg & company have sold me on the delimited continuations thing. shift/reset is a nightmare tho, i really like what the Eff folks are doing. huge fan of that approach |
| 23:45 | cjfrisz_ | bbloom: It's been long enough since I thought about delimited continuations that I forget the differences between the three versions, but I remember that Felleisen's prompt/k was better than shift/reset |
| 23:46 | cjfrisz_ | bbloom: Dybvig has also told me that he would prefer prompt/k over call/cc |
| 23:46 | bbloom | cjfrisz_: turns out that there are 4 versions, but i think one is clearly a dumb idea :-P |
| 23:46 | cjfrisz_ | bbloom: remembering that there were 3 was a guess, too |
| 23:47 | cjfrisz_ | I remember that shift/reset was Danvy and prompt/k was Felleisen, and there was one I don't remember who came up with |
| 23:47 | bbloom | cjfrisz_: anyway, the low-level encoding that seems to be preferred is newPrompt, pushPrompt, withSubCont, pushSubCont |
| 23:47 | cjfrisz_ | And apparently possibly another that's super dumb |
| 23:48 | bbloom | cjfrisz_: basically, gensym, mark stack, capture range of stack, install range of stack |
| 23:48 | cjfrisz_ | bbloom Right, and those four can be used to implement any of the models |
| 23:48 | sinistersnare | random question: has it ever been thought to make asm.js a viable backend for clojurescript compilation? |
| 23:49 | cjfrisz_ | Did you pick that up from Dybvig, Sabry, & Oleg's Monadic Framework for Delimited Continuations? |
| 23:49 | sinistersnare | i get that asm.js is more of a static language, maybe we should enforce typed-clojure on it then :p |
| 23:49 | bbloom | cjfrisz_: yeah, but then you have first class "sub continuations", which are just ranges of the stack. but i don't think you really need those. i think the effect/handlers model covers all the bases & is much easier to work with |
| 23:49 | sinistersnare | i mean core.typed* |
| 23:49 | unlink | I am able to run the war created by `lein ring uberwar' in tomcat, but `lein ring server' exits without an error (or error status code). |
| 23:49 | bbloom | cjfrisz_: that's where i grabbed it from just now, but it is also in the ocaml & haskell demo implementations |
| 23:49 | bbloom | cjfrisz_: similar names, same functions |
| 23:50 | cjfrisz_ | bbloom: I need to reread that; I don't think I was careful enough the first time or actually understood what I read |
| 23:50 | cjfrisz_ | bbloom: and it's been about a year and a half, I think? |
| 23:51 | cjfrisz_ | bbloom: Dybvig grilled me on it at my Cisco interview for kicks |
| 23:51 | bbloom | cjfrisz_: it's probably the most enlightening paper on delimited continuations, even though i find talk of monads to be generally gobblty gook |
| 23:51 | cjfrisz_ | bbloom: agreed on that last bit :-) |
| 23:52 | bbloom | cjfrisz_: but what made it all FINALLY click for me was this paper: http://arxiv.org/abs/1203.1539 |
| 23:52 | cjfrisz_ | bbloom: And earmarked for later |
| 23:55 | bbloom | cjfrisz_: i'm a big believer in "capabilities" as a security model, both for actual security & as a simpler/superior model for private/public/etc |
| 23:55 | bbloom | cjfrisz_: i like the idea that i can control which parts of my app can have which side effects by controlling whether or not i pass a particular object to that path of code |
| 23:56 | cjfrisz_ | bbloom: That is a cool idea |
| 23:57 | bbloom | cjfrisz_: yeah, see this one too for a haskell version: http://www.reddit.com/r/haskell/comments/1j9n5y/extensible_effects_an_alternative_to_monad/ |
| 23:58 | cjfrisz_ | bbloom: I've been meaning to read that; one of my friends is the third author |
| 23:58 | cjfrisz_ | But I didn't know he could do any Haskell |
| 23:59 | bbloom | cjfrisz_: cool. in general, this feels like to me a way to get all the cool tricks monads give you without any category theory nonsense AND sensible composability w/o monad transformer stacks. meanwhile, you get to keep a straightforward, direct style of programming |