#clojure log - Dec 05 2014

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

0:44 timvishet: anyone using cider 0.8.1 and austin 0.1.5, after running (austin-exec) with the default phantomjs exec-env get WARNINGs for basically every public cljs.core entity?

0:45 oh, and you have to try to M-x cider-load-file to trigger the WARNINGs

0:46 seems to well and truly fubar the repl, i have to cider-restart each time

1:30 rritoch: What is the URL of the web history of this chatroom?

1:32 otti: clojure-log.n01se.net

1:33 rritoch: otti: Thanks :)

1:34 otti: hm how can i splitup tests with leiningen? because i wrote some helper functions for a few tests, put them into a file /tests/helpers.clj. and now i have all the other tests in separate files.

1:34 but when i want to load them within core-test.clj there are problems with the namespaces, namely it can't find the namespace because it looks at /src/app/test-files.clj

1:34 justin_smith: otti: if you put the files in the classpath (ie. under the test/ directory) they can be required by the other files

1:35 otti: justin_smith: hm didn't work

1:35 justin_smith: otti: does the path to the file match the namespace in the file?

1:35 because it needs to

1:35 rritoch: otti: The only way I know of that you can split-up test is to use 'lein test :only test-namespace/some-test

1:36 justin_smith: otti for example if the file is in test/helpers.clj the namespace needs tobe called helpers

1:36 otti: justin_smith: it is

1:36 justin_smith: otti: then the other reason it wouldn't load is if there is an error in the file

1:37 otti: i only could solve it by linking the test directory within /src and use the following namespace scheme for the files: test.my-test-namespace.test-file

1:37 justin_smith: otti: that should not be needed at all. I use namespaces under test/ frequently with no issue

1:37 otti: but that sucks because on lein run the test files are considered too

1:37 justin_smith: i try as you suggested again

1:38 justin_smith: lein run won't load or use files that are not required by your core namespace anyway, so that isn't even an issue

1:38 otti: but who do you explain the fact, that i once got an exception, while executing

1:39 justin_smith: and if the namespace is test.my-test-namespace.test-file than the path needs to be test/test/my_test_namespace/test_file.clj

1:39 otti: 'lein run' within the tests

1:39 justin_smith: otti: something must have required or attempted to compile the file, but lein run wouldn't do that on its own

1:39 otti: hm

1:40 justin_smith: otti: perhaps you had :aot :all turned on?

1:40 otti: hm think, i just found the issue

1:40 justin_smith: no

1:40 justin_smith: it could be because i use vim-fireplace and run :Eval (core.test/run-tests)

1:41 which is connected to the repl that probably then goes looking within /src/app/

1:41 for the required files

1:41 instead of /test/app/

1:41 justin_smith: clojure.test/run-tests does not load any files

1:41 it only runs the tests that you have defined / loaded previously

1:42 perhaps fireplace loaded the files? I don't know how fireplace does things. lein should only be looking for test namespaces under test/

1:43 otti: fireplace connects to the repl (lein repl) and, yes i have to load the files

1:43 by calling :Require from within vim

1:50 hm very strange

1:52 justin_smith: otti: you say "probably then goes looking within /src/app for the required files instead of /test/app/"

1:52 otti: the way the classpath works, files under src/ and files under test/ are considered the same location

1:53 so you can't count on src/app/foo.clj vs. test/app/foo.clj - they are both the same relative path

1:53 otti: justin_smith: i don't know probably i made some mistakes the first time that i started to write the tests

1:53 justin_smith: OK

1:53 otti: because i removed the link within /src to /test

1:54 and changed the namespaces

1:54 and no namespace exceptions

1:54 thus it works now

1:54 justin_smith: thanks for the clearance

1:56 justin_smith: np

2:08 rritoch: I found another variation of classloader initiated incompatibility during compilation. I am unsure if this is related to yesterday's issue or not. http://pastebin.com/ydcQ9fVc

2:09 justin_smith: rritoch: Bronsa came up with a fix for that issue today BTW

2:10 rritoch: Cool, I haven't had a chance to check all of the logs

2:10 Does it resolve this issue also?

2:11 justin_smith: I think it should. But I'm not sure of that.

2:12 rritoch: justin_smith: Do you have a link to the solution? Bronsa was very active

2:13 Hmm,maybe I found it

2:14 Is this patch supposed to fix it? http://sprunge.us/YddP?diff

2:14 justin_smith: yeah, that's the one

2:16 rritoch: Interesting that he decided to go with the baseLoader. I suppose that is a good idea because the way it is currently you don't have any control over what classloader gets used

2:16 I was thinking that it would be better to check interned classes first though

2:18 Such as adding a map from the fully qualified classname, to the class for any class that gets interned, and checking against that whenever the fully qualified classname is used to ensure consistancy of classes within namespaces.

2:19 I don't think this patch fixes this new issue though, I'll have to double check something in the compiler to see.

2:23 Ok, yes, this should fix the case I found also. The case in this pastebin shortcuts to RT.classForName which was just resolving to Class/forName before this patch. So it looks like the patch resolves both issues.

2:23 I still think it would be more stable though to check against interned classes first

2:25 This additonal control over which classloader is used will certainly help, but could make some systems less stable if library developers start abusing the feature.

2:29 Either way, this problem was very helpful in learning how clojure classloading works. At least now I don't have to ignore the stacktrace portions that start with compiler, since I know what they're doing now :)

2:32 kenrestivo: rritoch: they were talking about how they'd put the fix in jira and, if you want it, you might want to vote it up.

2:33 i don't remember the ticket number but it's in the logs

2:35 rritoch: Sure, I'll vote-up anything that gives more control to the developer. I tried a lot of different tricks trying to get control over which classloader would be used and there really was no way around that Class.forName code

2:36 I'm still a bit curious though what the real cause of yesterdays issue was though, as far as I can tell the only thing that could have caused it is if the non-fully qualified name is getting resolved to a qualified name at some point, but short of adding debugging notices to the compiler I couldn't tell.

2:37 Looking at the code example, any non-qualified name checks interned classes so I'm not sure how the example was bypassing the interned class

2:38 Changing the interned class would alter which class was used at the top level, but not within the let

2:39 I even started using let* for my tests to ensure there was no "funny-business" going on within the macro that was applying the clojure.core namespace during macro expansion.

2:40 I just couldn't figure out a test, short of adding debugging messages to the Compiler, to see if the symbol was getting resolved to the fully qualified name within the let* statement.

2:42 It would be nice if the compiler had a *debug-compile* setting so we could see the internal processes without needing to hack the compiler

2:46 Would the &env in a macro show if a symbol in a let* has been resolved to a fully qualifed name?

2:47 Or would it just show the final eval'd value

3:14 epichero_: i need to spend a few hours getting cider setup with autocomplete setup with my customized emacs using evil mode and hooks...

3:15 sm0ke: is there something like try-let ?

3:16 where the let binding are available in the finally clause

3:16 * rritoch thinks he is the only one using Counterclockwise

3:16 opqdonut: sm0ke: just have try inside let?

3:17 that's how e.g. with-open is defined IIRC

3:17 yep: https://github.com/clojure/clojure/blob/clojure-1.6.0/src/clj/clojure/core.clj#L3512

3:17 Empperi: rritoch: I used to use ccw

3:17 these days I use IntelliJ + Cursive

3:19 sm0ke: rritoch: what if the binding cause exception/

3:19 sorry ^ opqdonut

3:19 rritoch: Empperi: Heh, I just had to install IntelliJ today. I stick with counterclockwise because I program in a lot of different languages, and eclipse has good support for nearly every language I code in, accept possibly C#

3:19 Empperi: well, IntelliJ has support for as wide variety of languages

3:19 maybe even wider

3:20 I personally do clojure, java, javascript, dart, bit of ruby, bit of python

3:20 and of course html, css, markdown etc

3:20 rritoch: Empperi: ccw is fairly broken, but anything I can't do from eclipse I can do from a shell, or PSPad, so I'm able to deal with it.

3:21 Empperi: yeah, ccw isn't that bad really

3:21 it's the eclipse I had problems with

3:21 used it for maybe 10 years

3:21 mavbozo: long live clojure!!! http://matthiasnehlsen.com/blog/2014/12/04/Farewell-Scala/

3:21 opqdonut: sm0ke: with-open with multiple bindings desugars into a nested try-let-try-let...

3:21 sm0ke: so if e.g. the third binding fails, the first two get freed

3:21 s/freed/closed/

3:23 andyf: rritoch: Sometimes adding debug print?s to the Clojure compiler is the quickest way to find out what you want.

3:27 rritoch: andyf: Well, I'm about to start playing with that code soon, but I don't see any "installation" instructions. Once I get it compiled with ant, how do I install it into the localrepo?

3:28 andyf: rritoch: mvn install

3:28 There may be other ways, but that should do it.

3:28 rritoch: andyf: ty, that sounds easy enough

3:32 andyf: If you want to skip running the tests: mvn -Dmaven.test.skip=true

3:32 I mean: mvn -Dmaven.test.skip=true install

3:33 That particular command is not on this web page, but the -Dmaven.test.skip=true part is: http://dev.clojure.org/display/community/Developing+Patches

3:34 rritoch: andyf: Thanks, I made a note of it. I don't think I'll have time to start tinkering until monday though

3:36 andyf: My primary goal is to create encapsulated namespaces to make it possible to have separate virtual runtimes (sandboxes?) within clojure, so OSGi modules can have a safe environment free of namespace and version conflicts.

3:37 andyf: It won't support multiple versions of clojure itself, but it could support independent versions of anything else.

3:37 andyf: I don't know if I would ever need such a thing, but sounds worth learning about some time. I have briefly wondered about ways to avoid problems with conflicting library dependencies in Clojure programs.

3:38 The most common solution is to modify dependencies until only a single version of each library is in use.

3:38 but that can be difficult, and in some cases impossible.

3:39 rritoch: andyf: Well I've found two methods that people are using. One is creating a custom namespace, and the other is to use a clojure "shim" library.

3:39 err, creating a custom classloader

3:39 Both methods involve toying with java classloaders, which is a guaranteed way to run into troubles

3:40 andyf: I've been developing a Clojure lint tool called Eastwood, which evaluates the Clojure code it is analyzing, and to avoid library conflicts between that program and what Eastwood itself uses, I've copied libraries into Eastwood, and renamed their namespaces to something that other programs don't use.

3:40 crude, but effective

3:43 rritoch: Well, that sounds like it would work in most cases

3:47 In my apps I'm using OSGi which already provides isolation for java classes within a module, but getting that isolation to clojure is inefficient. Modules would either need to include their own runtime, which ads a significant overhead to the load time, or classloading "magic" needs to be done to isolate the runtime. I intend to change namespace handling so the namespace registration ...

3:47 clojure.lang.Namespace/namespaces gets stored in thread-local memory, making it possible to isolate environments

3:57 Thinking more about the issue though, as it relates to OSGi integration, any version with namespace isolation support could be shared, so this would support multiple versions of clojure, but would only need one runtime per version, so multiple modules depending on the same clojure version could share a single runtime.

3:57 At least that's the goal.

3:58 I certainly could end up with an environment that is completely unstable and unusable

3:58 andyf: Out of curiosity, do you have an application that needs this?

3:59 rritoch: Yes, I'm developing a web platform/framework which needs it

4:00 https://github.com/search?q=user%3Arritoch+clj-grid

4:02 The system uses a MVC design pattern, that is now namespace based instead of class based, and provides jsp support for templates that are easy to manage by web designers

4:03 I also have "dreams" of eventually support libGDX as a OSGi module, but I haven't even attempted that yet. I still have a lot of core issues to deal with.

4:04 andyf: So the web framework will not achieve its goals without OSGi support?

4:06 rritoch: andyf: The OSGi support is to provide plugins, and facilitate commercial interest in the platform.

4:07 andyf: Businesses aren't going to be very interested in developing plugins that can only be delivered via maven (open source), by giving the download and install option it opens up commercial interests.

4:10 andyf: Aren't there closed source Java libraries delivered via jar files?

4:13 rritoch: andyf: Yes, but OSGi provides module isolation, so you don't end up with as many plugin conflicts, such as are faced by wordpress

4:13 borkdude: does anyone still use lein cucumber? https://github.com/nilswloka/lein-cucumber

4:15 cfleming: rritoch: I'd be very interested to hear about what you come up with.

4:15 rritoch: I'm no longer using OSGi, but I have a similar problem with IntelliJ plugins.

4:15 rritoch: i.e. I'd like to be able to load Clojure code into plugins without replicating the Clojure runtime across each of them.

4:16 rritoch: andyf: I believe openbravo provides modular support without OSGi, but for the most part OSGi is becoming an industry standard which is why I decided on OSGi as the basis for modularity.

4:18 andyf: To provide JSP support I'm already locked into the apache license anyhow, ...

4:19 When given the choice between anything and jboss, I'll choose anything, after JBoss's greedy patent lawsuits when their patents should have been completely invalid since day one since they patented a common software development practice, of having database fields mapped to object fields.

4:19 Because of those lawsuits I will do whatever it takes to avoid using ANY JBoss product

4:20 I also don't include any ORM support in my apps to ensure that JBoss can't get their greedy hands on any of my work

4:21 shiranaihito: rritoch: i always just figured JBoss was way too "Enterprisey", but i guess they're full of shit too

4:24 lxsameer: hey folks, is ther any solution to build android apps using clojure /

4:24 rritoch: Well, I've watched that situation closely because it is a huge thorn in the side of web development, that most web developers aren't aware of

4:24 shiranaihito: rritoch: plenty of other app servers around, though?

4:24 rritoch: Recent supreme court decisions seem to have invalidated JBoss's patent on ORM design, and most software patents, but there hasn't yet been a case to test that theory.

4:25 shiranaihito: There aren't many that I can find that are stable and well maintained, other than Apache Tomcat

4:25 shiranaihito: i'm not sure that matters.. court decisions will always favour the wealthy and politically connected anyway

4:25 Jetty?

4:27 rritoch: shiranaihito: I've started running into jetty a lot lately, and haven't tried it yet. I didn't find jetty until after I was already locked into tomcat libraries.

4:28 shiranaihito: rritoch: afaik, Jetty is very good.. i don't have experience running it in a Serious environment though, so that this for what it's worth

4:28 i'm basing my own Clojure web app development on top of Jetty though

4:30 rritoch: one considerable advantage that Jetty has is that you can embed it in a stand-alone Java/Clojure application

4:30 "so that this for what it's worth" <-- _take_ this for what it's worth, even..

4:31 rritoch: shiranaihito: Tomcat can also

4:32 shiranaihito: alright, i guess that's new

4:32 rritoch: shiranaihito: Currently I'm depending on [org.apache.tomcat/tomcat-jasper "7.0.52"] which provides me all of tomcat

4:32 shiranaihito: wasn't Jasper the JSP engine.. ?

4:33 cfleming: borkdude: I've received at least one request to support it in Cursive, so someone is: https://github.com/cursiveclojure/cursive/issues/478

4:33 borkdude: cfleming ah ok. It doesn't work anymore on my machine, but I think it's because Firefox updated itself

4:34 cfleming: borkdude: Ok - I've never used it myself.

4:34 rritoch: shiranaihito: Yes, as much as possible I am avoiding accessing anything in the catalina namespaces though. Tomcat uses layers and layers of wrapperrs and containers so to keep things light-weight I've been making my own servlet contexts and servlet config's to avoid the overhead

4:35 shiranaihito: As of now, deployment to tomcat servers is fairly seamless since I'm using the same libraries, but other than running JSP's from the command line I haven't yet made a stand-alone server with it

4:35 shiranaihito: rritoch: hmm.. i don't quite follow

4:36 gavilancomun: There can be slight differences in interpretation of the Servlet 3 spec between Tomcat and Jetty, but they can be worked around

4:36 rritoch: shiranaihito: Catalina code in the tomcat library is what provides the servletconfig's and servletcontext's required by the JSP specification

4:36 shiranaihito: how do you "run JSP from the command line"?

4:36 do you mean the Servlet specification? :P

4:36 rritoch: yeah :)

4:37 shiranaihito: :P

4:37 but still, "running JSP" from the command line (or anywhere for that matter) sounds weird

4:37 rritoch: The code to run jsp from the command line is all in http://www.github.com/rritoch/clj-grid-core , it wasn't easy

4:38 shiranaihito: Well, the intention behind that is to eventually provide CGI capability

4:38 gavilancomun: The two issue I have had are scanning jars for annotations alongside web_fragment.xml files...

4:39 rritoch: shiranaihito: Running via CGI would be slow, and cause the loss of all persistence benefits, but it is good for testing

4:39 shiranaihito: Currently I only use the command line support for testing/debugging

4:39 gavilancomun: and how the notion of current URL changes it calls to redirect() and calls to .forward() with a relative URL.

4:40 *it* -> with

4:40 shiranaihito: rritoch: but "CGI" is what Servlets replace, right? it's just an interface for running code that's "called" by a server over the Internet?

4:40 dflkjdsfdf

4:41 rritoch: "called" by a browser, that is

4:41 sorry.. i'm in a brainfarty mood, apparently

4:41 JSP (Java Server Pages) is just a View layer for Servlet -based web applications, right?

4:43 rritoch: shiranaihito: JSP compiles to a servlet so it can provide the entire application, but typically a lot of back-end java is used

4:45 shiranaihito: Either way, I'm only using it for a view layer to JSP web applications

4:45 shiranaihito: rritoch: yeah i know, but people don't write JSP for that aspect

4:45 rritoch: err, clj web applications

4:45 shiranaihito: :p

4:46 rritoch: but yeah.. CGI.. i'm not even sure what you mean with that.. it used to be something like, a way to hand off a HTTP request to a separate process (one per request?), right?

4:47 but why would you not use just plain Servlets or something on top of that instead?

4:48 rritoch: shiranaihito: Running it via CGI means there's no need for an application server. CGI are just command line applications, delivery of metadata occurs by environment variables, and content (for post/put/etc.) delivered on stdin

4:49 shiranaihito: rritoch: yes, but why do it like that, instead of using Servlets or some other established, non-ancient standard for accomplishing the same (and more)?

4:49 rritoch: shiranaihito: This way I can test features directly from the command line without needing to deploy an application server

4:50 shiranaihito: Testing as CGI requires one command "lein run", no need to launch a server, install updates, or open a web browser

4:50 shiranaihito: rritoch: ok, but you could use a http client too.. which would be a better fit with making a web app, since it's going to be used over http anyway

4:51 wouldn't "lein run" launch a web server too, typically? :p

4:52 rritoch: shiranaihito: Not with this platform, with this system lein run deploys a virtual web request, though I haven't added stdin reading or environment variable reading yet, so it isn't yet CGI compliant.

4:52 shiranaihito: At some point I'll add something like 'lein grid server' to launch a stand-alone web server, and it's on my todolist

4:52 shiranaihito: rritoch: "virtual web request"? .. so you're doing "web-like" stuff to avoid doing actual web stuff? :p

4:53 rritoch: But first I need to deal with this isolation issue

4:53 shiranaihito: Yes, development has been much faster that way

4:55 shiranaihito: rritoch: i'm still confused by what you're doing, and why, but.. i guess that's alright :P

4:55 carry on! :P

5:05 rritoch: shiranaihito: The WHY is a big question I'm having a difficult time with lately, there isn't really any interest in this project outside my own mind, but I hope to be able to build enterprise class web applications in clojure that are easily maintained with a large team of developers

5:06 shiranaihito: Your jetty project is the only other project I've heard of that has JSP support in clojure

5:06 Empperi: wait, what, why?

5:06 jsp in clojure?

5:06 man

5:07 shiranaihito: rritoch: if your goal is to write easily maintained web apps in Clojure, i don't see how "CGI-through-JSP-somehow" is the means towards that

5:07 you could check out ring-jetty for some inspiration?

5:08 it sets up a stand-alone Jetty instance and gives it a custom (Jetty-specific) request handler thingy, that calls ring handlers

5:08 rritoch: shiranaihito: ring is a deadzone for my application because ring rejects tomcat dependencies

5:08 shiranaihito: i think that's pretty straightforward, and i'm using parts of that for my own cute little web framework

5:08 rejects?

5:09 rritoch: Yes, rejects, removes the dependency because it contains a servlet implementation

5:10 shiranaihito: rritoch: you mean there's some kind of dependency conflict with Lein?

5:10 can you use the "exclude" command to work around it?

5:10 rritoch: No, I mean the ring plugin specifically rejects the dependency

5:11 Empperi: I know for a fact that several people are running clojure + ring apps on top of tomcat

5:11 rritoch: shiranaihito: I don't think so, exclude works at the package level, not the class level

5:11 Empperi: Yes, they do that with the uberwar

5:11 Empperi: even if that is not the recommended way to do it

5:11 yes, which is the right way to do it anyway

5:12 the whole concept of using jars from tomcat's lib directory is just dumb

5:12 imho

5:12 makes deployments so much harder and gains nothing

5:13 since one should run only one app per tomcat anyway so that when you need to restart tomcat because of one app you don't have to put other apps down too

5:13 and only "gain" you could gain with tomcat lib directory based jar packages is the situation where you have same dependencies for multiple apps

5:14 ordnungswidrig: Empperi: containers should hide all the libs they use to the deployed apps

5:14 Empperi: and even if you *do* run several apps on top of same tomcat instance (which I don't recommend) then only thing you'll lose if you encapsulate that jar to each war is some disc space

5:15 ordnungswidrig: yes, indeed. App decides what libraries they need, not the container

5:15 ordnungswidrig: Empperi: we know all the fun with log4j and jbos

5:15 Empperi: and that's my point, there is absolutely no reasonable reason to put jar packages into tomcat lib directory for your app

5:15 rritoch: shiranaihito: I don't know if they've changed the issue, but the exclusion code is @ https://github.com/weavejester/lein-ring/blob/0c9dff39929a8be35a04f2afc8580ab6b0e1d2d2/src/leiningen/ring/uberwar.clj#L26-L33

5:15 Empperi: it's an antipattern and the world is better without it

5:17 if it is a problem for your server that you might have even few megabytes more of data on it's disc then you have a completely different problem altogether

5:17 maxpn: how to implement javascript-like setTimeout() in Clojure?

5:17 rritoch: shiranaihito: I attempted to use ring, but it was skipping my tomcat dependency because it contains a servlet so I wasn't able to get jsp support with tomcat+ring

5:17 ordnungswidrig: Empperi: there are still links or file systems that do deduplication for that

5:17 maxmartin: there's a lib called atat

5:17 rritoch: shiranaihito: If I was aware of jetty+ring at the time the project may have gone in a different direction

5:17 godd2: maxpn you sure you dont just want sleep?

5:18 ordnungswidrig: rritoch: I never heard someone wanting jsp support in a ring app :)

5:18 maxpn: godd2: yes, sleep but not in main thred

5:18 godd2: maxpn you can just put it in a future

5:18 ordnungswidrig: maxmartin: (future (Thread/sleep 1000) (prn "foo"))

5:19 shiranaihito: rritoch: i can't tell what happened.. but that's ok.. did you have servlet.jar in your tomcat's global lib folder or something btw? that might cause a conflict

5:19 ordnungswidrig: &(future (Thread/sleep 1000) (prn "foo"))

5:19 lazybot: java.lang.SecurityException: You tripped the alarm! future-call is bad!

5:19 ordnungswidrig: lzybot: I'm sorry

5:19 maxpn: godd2: thank you, that is it!

5:19 thank you all

5:20 rritoch: ordnungswidrig: Typical web designers simply won't be able to use clojure directly. JSP templates can be made which are 99% HTML, and typically web designers will just copy/paste in the JSP codes they need.

5:21 ordnungswidrig: rritoch: To my experience they prefer more something like mustache

5:21 rritoch: ordnungswidrig: JSP support in web apps is purely to facilitate employing web designers onto the projects.

5:23 ordnungswidrig: I'm talking about professional web designers, not programmers experimenting with web design.

5:23 ordnungswidrig: rritoch: I know what you mean, it's just contrary to my experience with professional web designers.

5:24 rritoch: I guess the preferences of web designers in this regard vary a lot over different communitites

5:25 rritoch: ordnungswidrig: Well, most web designers I've dealt with require templates to be as close to pure html as possible

5:28 ordnungswidrig: rritoch: sure. To my experience they prefer mustache, freemarker, velocity or like that. All those, like JSP, use html with some extra syntax sprinkled over the tags. As a developer I try to avoid JSP because that binds you to a servlet container and those scary compilcated JSP engines.

5:30 rritoch: ordnungswidrig: Well, the advantage of the platform I'm building is that it really can support any templating engine that's java based, including jsp

5:31 ordnungswidrig: I'm dealing with all of the complexity within the platform itself

5:31 ordnungswidrig: rritoch: ok, that's a point.

5:31 rritoch: good luck to you :-P

5:31 bja: /.er in me says JSP isn't an advantage

5:31 rritoch: ordnungswidrig: If clojure outputs directly to stdout (println) I have that bound to the servlets output stream, that opens a lot of possiblities

5:32 ordnungswidrig: But in all of my example apps I'm jut forwarding to jsp's

5:32 ordnungswidrig: I also recently made a .clj specific servlet, so you can even forward to a .clj script

5:40 kras: which is better in terms of performance #(nth % (- (count %) 1)) or #(first (reverse %)) ?

5:40 for taking the last item

5:43 algernon: I'd think (last %) would be, if I may offer a third choice.

5:43 kras: 4clojure problem #19, restriction on last :-)

5:44 rritoch: kras: For a large list the first would be faster because reverse isn't lazy, I believe rseq would be the fastest ##(time (first (rseq (range 10000))))

5:44 lazybot: java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.Reversible

5:44 shiranaihito: rritoch: as someone pointed out, you can just use a templating engine like Velocity or FreeMarker

5:44 dgellow: hi #clojure

5:44 shiranaihito: there's no need for JSP.. if you're writing a web app, you'll just be spewing out HTML anyway, regardless of how you generate it

5:45 daniel```: hi dgellow

5:45 rritoch: Eek, didn't know lazy sequences aren't reversable :(

5:46 shiranaihito: Most of my web designers know JSP, and there is a large market of JSP template designers

5:47 shiranaihito: rritoch: JSP is alright as a templating engine - i think its best feature is custom tags that can be nested, that enables a lot of modularity

5:47 dgellow: Is cemerick/Friend the de facto library for everything about authentication ? Or do you know other lib with a similar purpose ?

5:48 shiranaihito: but similar things can be achieved with Velocity or FreeMarker.. i'm not sure it warrants the complexity of the JSP setup etc

5:48 algernon: kras: ah :)

5:49 rritoch: shiranaihito: Ex. on odesk there are 920 velocity developers, but over 16,000 JSP developers

5:50 shiranaihito: rritoch: sure, but you're just producing HTML.. learning Velocity or FreeMarker is not difficult either - they're all templates for producing HTML anyway

5:50 but i guess the biggest mystery to me is that CGI stuff

5:53 it sounded like in a way, you'd be testing whether your actual app code can be called (from the command line)

5:54 but that wouldn't really be a problem, right? .. it would be more useful to test the app's code itself, and you don't need to involve HTTP/CGI for most of that

5:54 rritoch: Anyhow, I need to get back to work, but adding jetty support seems reasonable. Eventually I want to swap out all of the tomcat dependent code into it's own library, but that's just one of MANY core issues that I need to deal with. The urgent one is namespace isolation for modules.

5:55 shiranaihito: (for example, most of your functions probably don't have to take a HttpServletRequest as a parameter)

5:56 rritoch: don't strive for excessive generality either :) .. whatever that might happen to mean in practice

5:56 rritoch: shiranaihito: None do, I dynamically bind a *servlet-request* variable from the servlet, so every function has access to the request automatically

5:57 shiranaihito: rritoch: alright, but again, what would you need some kind of CGI contraption for? :)

5:57 daniel```: dgellow: it is, yes

5:57 dgellow: i have looked for others, its by far the most used

5:57 kras: any suggestions on whom to follow on 4clojure, for learning from their solutions

5:57 shiranaihito: rritoch: besides, that doesn't sound very functional

5:57 rritoch: shiranaihito: As I said, it reduces development time for these core systems because it doesn't require the overhead of a server

5:58 shiranaihito: The goal is to provide functions for access to the request

5:58 shiranaihito: rritoch: well what's the problem with running a server?

5:58 functions that would access the global request variable?

5:59 rritoch: shiranaihito: Time, it takes 1 second to type lein run and get the results, up to a minute to restart a tomcat server

5:59 shiranaihito: Previously I also had to install updates to tomcat, similar to the ring uberwar process

6:00 shiranaihito: rritoch: it takes.. let's say 1 second (to mirror your estimate :p) to start up a stand-alone embedded Jetty server :p

6:00 rritoch: shiranaihito: But I've bound the classloader to the development source paths now so I can develop the web apps now in real time, I only use the CGI mode for debugging core features

6:01 shiranaihito: Ok, well the other advantage of CGI mode is that it will work on nearly every web server

6:01 Anyhow, here is an example of how this *servlet-request* design gets converted into functional syntax. https://github.com/rritoch/clj-grid-mvc/blob/master/src/com/vnetpublishing/clj/grid/mvc/base/controller.clj#L49-L54

6:01 shiranaihito: rritoch: well, your app server will just take in http connections anyway right?

6:02 so it doesn't really matter if it's tomcat or jetty or jboss etc

6:02 "nearly any web server" will be able to proxy connections to your app server

6:02 christiaanb: Hi, I'm helping in organising the annual dutch functional programming day (http://wwwhome.cs.utwente.nl/~jankuper/fp-dag/), and I was wondering what the best way is to notify the members of your community of this event?

6:04 rritoch: hmm, just noticed I need to repair that function. Anyhow, I need to get back to work, but those "action"'s need to be changed with name, I was testing actions in controllers and must have been half-asleep when I coded it.

6:09 TEttinger: christiaanb, there is the clojure mailing list, which seems appropriate

6:09 rritoch: shiranaihito: As of now this doesn't have a stand alone application server, it is running via CGI mode or tomcat. I intend to use http-kit to provide a stand alone server, but I first need to deal with namespace isolation.

6:10 christiaanb: TEttinger: thanks

6:11 TEttinger: christiaanb, might be worth reaching out to any companies in the netherlands doing clojure dev, I don't know how you would get a list...

6:12 christiaanb: TEttinger: I think I'll try the user groups for that

6:12 dgellow: daniel```: thanks

7:17 triss: I'm always saying (vec (repeat n some-value))

7:18 is that the easiest way of filling a vector with a default value?

7:18 Bronsa: that's the best way

7:19 triss: cheers Bronsa.

7:21 bja: boo: (read-string (pr-str (keyword "")))

7:22 actually boo my logic that allows me to try to keyword ""

7:49 TimMc: bja: boo to code that keywords arbitrary strings as opposed to statically known values.

7:50 bja: well, they're not *supposed* to be arbitrary

7:51 there was a bug that resulted in something along the lines of (keyword (string/join [" " "foo"])) to occur

8:06 mavbozo: will clojure eXchange 2014 London videos made available in youtube?

8:16 scottj: mavbozo: weren't previous ones available on skillsmatter.com only using vimeo but not accessible on vimeo's site?

8:17 mavbozo: scottj: oh, those videos are in skillsmatter.com. thanks scottj.

8:17 (inc scottj)

8:17 lazybot: ⇒ 2

9:08 triss: hey all. so I'm writing my first proper app in clojure.

9:08 I want to do the frontend in clojurescript

9:08 what's the simplest way of adding clojurescript as a dependancy?

9:09 is iyt possible to use lein to add it to an existing project or do i have to manually edit the project.clj?

9:57 sveri: triss: what I usually do is take a template and work on from there

9:58 triss: adding things later is a bit different, for this I generate a template (for instance with lein new chestnut tempname) and copy & paste the relevant pieces to my existing app

10:01 triss: thanks sveri....

10:01 so create a new cljs project and copy the missing deps from there.

10:02 sveri: triss: this is a tedious thing to do, but usually only a one time setup, so I just do it

10:14 mnngfltg: Hey. Does anyone mock out dependencies like writing to the database? I've tried `conjure` with clojure.test and found it cumbersome.

10:28 bja: mnngfltg: mostly no. I write functions that return data and test the functions

10:29 I mostly assume that the libraries I use to connect to external sources work

10:29 those libraries have their own tests

10:29 mnngfltg: bja, right

10:29 bja, but what about glue code, e.g. code with side-effecets that, say, writes to the database

10:29 * EvanR runs the tests that make sure google apis dont return 400 500 or 503 randomly

10:30 bja: mnngfltg: code doesn't do that typically. It does something, and then finally writes to the db

10:30 I can test the transforms I do

10:30 * EvanR at least wishes

10:30 mnngfltg: bja, in my experience that's not always easy to do

10:31 bja: maybe not easy, but I try very hard to make that part of my design

10:31 helps me live a much happier life

10:31 mnngfltg: I would be happier too :)

10:31 bja: the places I talk to the external world now are mostly over core.async channels

10:31 and those are trivial to mock out when I need to

10:32 i.e. in some logic that handles various failure modes

10:32 mnngfltg: interesting

10:32 so having a queue helps you decouple the code from the actual side effects

10:33 bja: I mean, writing to or reading from a channel is a side effect, but I can usually isolate the actual writing to a db from the control logic that operates on channels

10:33 csd_: What do I need to do to a key-value object to treat it as if it were a JSON object?

10:33 bja: then I can test the control logic by creating various plain old channels and putting input on them or getting a value from them

10:33 and my transforms can be mostly pure

10:34 that's probably some sort of pattern with a name, but I couldn't tell you which one

10:35 mnngfltg: bja, it's an interesting approach, though maybe a bit too heavy if I don't have a use for core.async otherwise

10:36 csd_, what do you mean by "treat as a JSON object"?

10:36 csd_, generate a JSON string? (see cheshire or clojure/data.json

10:38 EvanR: ,(:a {:a 1})

10:38 clojurebot: 1

10:38 EvanR: ,(2 {2 1})

10:38 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn>

10:38 EvanR: ,({2 1} 2)

10:38 clojurebot: 1

10:38 justin_smith: ,(ifn? :a)

10:38 clojurebot: true

10:38 justin_smith: ,(ifn? 2)

10:38 clojurebot: false

10:38 justin_smith: ,(ifn? {})

10:38 clojurebot: true

10:38 csd_: mnngfltg: the chrome.storage api returns data in key/value pairs. dyntable wants JSON. i'm having trouble passing the object returned by the chrome api into dynatable, so I'm guessing it's because it's in some incorrect object format

10:39 EvanR: is it possible implement ifn in clojure

10:39 csd_: oh shoot i thought this was #javascript

10:39 EvanR: for newtypes

10:39 mnngfltg: csd_, JSON.stringify() ? :)

10:39 bja: #(.stringify js/JSON %)

10:39 justin_smith: EvanR: absolutely. Anything made with defrecord does it they way {} does by default.

10:40 EvanR: but you can get creative with it easily with deftype

10:40 EvanR: i keep getting confused about what can/cant implement protocols/interfaces

10:41 justin_smith: ifn? tests for clojure.lang.IFn

10:41 EvanR: which is an interface or protocol

10:42 justin_smith: I think it's an interface. Reagardless, protocol is just a very thin abstraction on interface.

10:42 and every protocol has an underlying interface that gets created

10:43 EvanR: java classes can have protocol impls

10:43 but not interfaces?

10:43 justin_smith: java classes can easily have interfaces. It's a bit more work for them to integrate with protocols. nothing stops them from having both.

10:44 EvanR: alright

10:44 justin_smith: interfaces are part of the jvm. protocols are a clojure thing

10:44 EvanR: but you cant implement a protocol for an interface?

10:45 justin_smith: no, but you can implement an interface for an interface, and every protocol has an underlying implementation as an interface

10:49 pepijndevos: a protocol also generates an interface, right?

10:49 justin_smith: right, that's what I was saying

10:49 pepijndevos: eh, right

10:51 mikerod: Didn't this get discussed yesterday and puredanger ended up saying that Rich had no particular problems with allowing a protocol to extend a protocol or interface?

10:51 puredanger: I'm not sure that's the correct summary :)

10:51 pepijndevos: If anyone has any performance advice, I'd be very happy. This code is a lot slower than equivalent imperative Scala: https://www.refheap.com/c337db72c94175657d1217372

10:51 puredanger: protocols can definitely extend to interfaces now

10:52 llasram: Well, the protocol implementation lookup definitely works pretty hard to do the right thing for interfaces

10:52 mikerod: I've always been torn on why protocols do not allow the extension to other protocol/interfaces like the interfaces do. I tried to think it was idiomatic in Clojure, but that doesn't seem true when looking at the clojure.lang.* impl's

10:52 EvanR: what exactly does protocol extend protocol mean anyway, have an implementation? or is this inheritance

10:52 puredanger: it is not inheritance

10:52 mikerod: EvanR: inheritance is what I'm thinking

10:52 puredanger: at least I don't think of it as inheritance

10:52 mikerod: Type hierarchy inheritance is mostly my focus

10:53 puredanger: it means an implementation of the protocol exists for a type

10:53 mikerod: I see a lot of interface inheritance used in clojure.lang. If Clojure is mostly against that sort of thing, why is it done so pervasively there?

10:53 puredanger: I personally think it would be useful to extend protocols to other protocols. that introduces some problems, but I think it would allow abstraction layering (not concrete implementation layering) that would be useful. I do not know whether Rich would support that or not.

10:54 interface inheritance is fine

10:54 it's concrete extension that is a no-go

10:54 mikerod: puredanger: yes I agree and see that concrete extension is no good and is the main issue on this topic I think

10:54 EvanR: what is concrete extension

10:54 justin_smith: pepijndevos: where does that Node class come from?

10:55 puredanger: class extends class

10:55 EvanR: and in this case extends means inheritance

10:55 mikerod: I guess if I want the "isa" relationships for protocols then Clojure does support ad-hoc hiearaches or I can just drop down and extend protocol generated interfaces

10:55 pepijndevos: justin_smith line 27

10:55 puredanger: EvanR: yes, talking in Java terms atm

10:55 justin_smith: pepijndevos: d'oh, I must not be fully awake yet

10:55 EvanR: and "isa" means, is a subtype? a isa b means a works wherever b works?

10:56 puredanger: pepijndevos: you're using boxed math for one thing

10:56 mikerod: EvanR: I mean if I have a protocol for Animal and I have a protocol for Dog and I have a class that implements Dog, let's call it ActualDog, I'd like to be able to say that ActualDog "isa" Animal

10:57 puredanger: EvanR: this is not precise enough wrt concrete class vs interface

10:57 mikerod: (dumb example of course :) )

10:57 puredanger: mikerod: right, you can extend ActualDog to Animal and ActualDog to Dog

10:57 pepijndevos: puredanger, enlighten me. You mean I should use +' and friends?

10:57 EvanR: mikerod: without implementing Animal?

10:57 puredanger: but you can't extend Dog to Animal

10:58 mikerod: puredanger: yes, it just requires more of a hunt to figure out all the things you must extend to

10:58 EvanR: shudders

10:58 mikerod: puredanger: I just think the maintenance barrier is a bit higher

10:58 puredanger: one trick for this is to extend Object to Animal, then check satisfies? and install an extension for the concrete type you've encoutnered

10:58 EvanR: how do i union two sets?

10:58 ,(union #{1} #{2})

10:58 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: union in this context, compiling:(NO_SOURCE_PATH:0:0)>

10:58 puredanger: EvanR: clojure.set/union

10:59 mikerod: puredanger: that is an interesting way

10:59 EvanR: ,(clojure.set/union #{1} #{2})

10:59 clojurebot: #<ClassNotFoundException java.lang.ClassNotFoundException: clojure.set>

10:59 puredanger: mikerod: I've used it quite a bit and it works fine. note you only have to install it the first time you encounter the new concrete type

10:59 after that there is an extension installed for the concrete type so it routes directly

10:59 justin_smith: pepijndevos: +' is the opposite of what you want. Boxed means each number is actually an object (usually of type java.lang.Long or java.lang.Double) instead of a primitive long or double type (not Objects). You need type hints for this.

11:00 mikerod: This isn't a huge barrier to me anyways. I just have a had a few cases where it has came up. The toughest part about protocols to me is still that you can't rely on a given type that `satisfies?` it to actually implement its functions.

11:00 puredanger: justin_smith: +1

11:00 mikerod: puredanger: that is pretty clever :)

11:00 pepijndevos: ah... can I do *warn-on-boxed* yet? Browsing jira....

11:00 puredanger: it actually came up in a talk at the very first conj and Rich said this from the audience

11:00 pepijndevos: you can in 1.7 alphas

11:01 pepijndevos: I have those... so I'll try that.

11:01 puredanger: mikerod: chouser (I believe) tried to live-code it and it didn't go so well :)

11:01 mikerod: puredanger: the dangers of live coding I guess

11:01 puredanger: live coding suggestions from Rich no less :)

11:01 justin_smith: puredanger: I have an idea to put together a repo that is just a bunch of files with clojure.test, making assertions about whether reflection or boxing occurs, as a "living document" demonstrating where hinting is needed or useful and where it is not.

11:02 I may just work on that today.

11:02 mikerod: that just sounds intense

11:02 justin_smith: (capturing the reflection / boxing warnings via with-out-str)

11:03 puredanger: justin_smith: there are some examples of how to do that in the clojure tests if you want to steal

11:03 justin_smith: puredanger: awesome, thanks

11:03 puredanger: mikerod: you might find this useful - http://david-mcneil.com/post/3495351254/clojure-protocol-adapters

11:03 David and I were working together when he wrote this and it's the same ideas

11:04 EvanR: mikerod: maybe this idea is more about "required prerequisite protocol of a protocol"

11:04 * puredanger adapted into a library though

11:05 puredanger: and then of course, a protocol is nothing more than a map with a well-known structure. you can also just muck with it directly to do all kinds of advanced stuff.

11:05 pepijndevos: so is it *unchecked-math*?

11:06 justin_smith: puredanger: my spidey-sense tells me that could get very ugly if misused...

11:06 puredanger: pepijndevos: (set! *unchecked-math* true)

11:06 EvanR: advanced, powerful ;)

11:06 puredanger: or (set! *unchecked-math* :warn-on-boxed) if you want the warnings

11:06 justin_smith: pepijndevos: I think the warnings turn on with *unchecked-math* - you may or may not need *warn-on-reflection* turned on too (regardless, you want both if you care about perf)

11:07 puredanger: warn-on-reflection is separate, but you probably should use that too

11:07 justin_smith: cool, thanks for the info

11:07 (inc puredanger)

11:07 lazybot: ⇒ 23

11:07 puredanger: I did the boxed warning work after reading way too much bytecode for the Alioth perf stuff :)

11:08 justin_smith: you could certainly abuse it :) great power / great responsibility /etc :)

11:08 justin_smith: haha, nothing motivates better than having your own itch to scratch

11:08 puredanger: I did mention spidey-sense for a reason

11:08 puredanger: Clojure leaves its internals open. if you have the ability to use them for good (and are willing to accept the maintenance costs associated), go for it.

11:09 EvanR: theres the ability to mess with internal junk for idiosyncratic purposes then theres whether you will encourage people to try it

11:09 in ruby, both are true

11:09 across the board

11:09 and its terrible

11:11 mikerod: (inc puredanger)

11:11 lazybot: ⇒ 24

11:11 mikerod: puredanger: thanks that link is good. I haven't seen it before.

11:11 EvanR: yes that is the idea

11:11 EvanR: the link pretty much captures the issue though I think for the most part

11:12 EvanR: mikerod: for a sense of required anything, maybe a first step is to require a whole protocol to be implemented by a single class?

11:13 otherwise we can add new requirements through project documentation at will, if the system doesnt help

11:13 mikerod: EvanR: are you talking about the idea of a given type possibly not implementing a "required" protocol function that you need?

11:13 EvanR: yesterday i heard you dont have to implement all the methods of a protocol, and that confuses me

11:14 justin_smith: yeah, clojure does not force full protocol or interface implementation

11:14 EvanR: thats like, a prerequisite before that other prerequisite

11:15 on the other hand its not like its ensuring you follow an interfaces spec either, even if you do have an impl

11:15 so back to policy docs

11:15 justin_smith: right, that's a turing complete problem I think

11:15 EvanR: depending on the spec language

11:16 specs involving meta physics propositions i dont expect to be computer assisted any time soon

11:16 pepijndevos: I wonder how big a difference unboxed math makes... we'll know in a minute.

11:17 puredanger: if you're doing math, 2-3 orders of magnitude :)

11:18 but if that's not your bottleneck, then won't matter of course

11:22 EvanR: is there something like update-in but just sets the value instead of applying a function

11:22 i know constantly can do it but thats such a long word

11:22 puredanger: assoc-in ?

11:22 EvanR: sweet

11:22 * puredanger works slightly differently, so read the docs

11:23 EvanR: blast

11:23 puredanger: it does what you want, just doesn't follow the update form

11:23 since it's not an update

11:25 (inc crossclj)

11:25 lazybot: ⇒ 8

11:25 puredanger: once again, super helpful as I research things http://crossclj.info

11:32 ajmccluskey: Is there a neat way to flatten a nested map entry? Have {:A {:B :C}}, want [:A :B :C].

11:32 EvanR: ,(flatten {:A {:B :C}}

11:32 ,(flatten {:A {:B :C}})

11:32 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

11:32 ()

11:32 ajmccluskey: {:A {:B :C}} is meant to be a map entry there, not a whole map.

11:32 EvanR: yeah, that surprised me too :p

11:33 mikerod: EvanR: justin_smith what I wish there was available for protocols was a way to at "check" if a given object implements a function

11:33 EvanR: after re-reading the doc i would expect it to crash on maps

11:33 mikerod: instead of just throwing something liek an AbstractMethodError

11:33 could always try-catch for control flow though! :P

11:33 I tend to implement my protocols on Object with some special value like ::undefined

11:33 EvanR: better, assume they implemented it, what is the reason to support partial protocol impls?

11:34 mikerod: then control flow around that in functions that expect some functions to be implemented, but can try to recover if they are not

11:34 EvanR: sounds backwards from the perspective of a library writer

11:36 mikerod: by "recover" I mean do something that makes sense if possible

11:36 EvanR: sends an email to the person responsible for the partially defined thing to get them to complete it?

11:37 ajmccluskey: mikerod: agree with EvanR - sounds like a lot of work. I would go with expecting someone who says they implement a protocol to, you know, implement it

11:37 mikerod: ajmccluskey: I suppose

11:37 EvanR: i mean if they wanted to put a dummy that just crashes, they can

11:37 mikerod: AbstractMethodErrors it is then ;)

11:37 ajmccluskey: mikerod: wait, are you doing anything safety critical? I'm not going to die on the table because of this am I?

11:38 EvanR: or if the protocol is designed to be partially implemented, require an in-band method to describe that officially (or use more than one protocol)

11:38 mikerod: I actually wish even in the Java side that you could mark methods in a way that makes it clear yo do not implement them. Optional interface methods are very strange to me

11:38 If an interface has optional methods, it sounds like a broken abstraction because you dont' know what the contract is of the objects your given

11:38 * EvanR reads about optional interface methods

11:39 mikerod: http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html

11:39 and the UnsupportedOperationException

11:39 for reference http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html#add(E)

11:39 I get it here, I think the interface should have been 2 interfaces

11:40 The whole Immutable vs Editable or w/e

11:40 EvanR: badly design protocol support

11:43 yocapybara: anyone have any opinions on what the most performant way to get a digest (like md5 or sha1) from a clojure map?

11:43 mikerod: From the protocol perspective, the only reason I could see not requiring all functions on a protocol to be implemented is for some dynamic development. However, for "real" stuff I can't really see why there would be partial impl's.

11:43 And protocols should be small to avoid the issue of having too much to implement

11:43 yocapybara: I pulled up pandect but running (sha1 {:a "b"}) gives me an error that there's no implementation of :compute-sha1686 for PersistentArrayMap

11:49 EvanR: ,(values {:a 1 :b 2})

11:49 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: values in this context, compiling:(NO_SOURCE_PATH:0:0)>

11:49 EvanR: ,(keys {:a 1 :b 2})

11:49 clojurebot: (:b :a)

11:51 ajmccluskey: ,(vals {:a 1 :b 2})

11:51 clojurebot: (2 1)

12:03 justin_smith: mikerod: the general approach in Clojure is that if something is needed in dynamic development, it is valid. The differences between work in the repl and what works in files are actively minimized, and I actually think that is a good thing.

12:13 EvanR: if i were going to make a mutable data structure, what do i use. vars?

12:15 nkoza: evanr: you can use deftype, it supports mutable fields

12:15 justin_smith: EvanR: a var is just a mutable container, the thing in it doesn't mutate, it just points at a new thing when reassigned

12:15 EvanR: you can also use java.util.HashMap, or arrays, or whatever

12:16 puredanger: deftype supports marking fields with ^:unsynchronized-mutable or ^:volatile-mutable hints

12:16 clojurebot: Gabh mo leithscéal?

12:16 EvanR: my idea was to put the var in something as a mutable field

12:17 dnolen_: Bronsa: you haven't tried dead code elimination with tools.analyzer have you?

12:17 puredanger: why?

12:17 justin_smith: if you ever use a thread, an atom or ref may be a better pick than a var for that

12:17 clojurebot: because that's not how macros work

12:17 EvanR: but it sounds like i need a deftype

12:17 dnolen_: EvanR: is there some reason an atom does not suffice?

12:17 puredanger: putting a var in a mutable field of a deftype sounds like the wrong answer to most questions :)

12:17 EvanR: yes

12:18 puredanger: two different ideas, not combined

12:18 puredanger: good :)

12:19 Bronsa: dnolen_: no, doing dead code elimination in clojure is nearly impossible without altering the language semantics. but arrdem should have done some tree shaking with oxcart -- which has cljs-like semantics

12:21 EvanR: i have a map of references to mutable objects, each having two mutable fields. so i guess a regular map in an atom for the top level would work, but the important part is that the map entries might point to the same object

12:21 Bronsa: dnolen_: sorry, I blindly assumed you meant tree shaking with "dead code elimination", was I wrong?

12:22 EvanR: in my mind the values are refs to objects, rather than regular values

12:22 OscarZ: was thinking of core.async.. are channels usually used as local variables that die after some function call or does it make sense to create some kind of "global" channel that could be used for multiple requests ?

12:22 dnolen_: Bronsa: not wrong, but what is the problem exactly if it can be summarized?

12:23 puredanger: EvanR: atoms (and refs etc) expect their values to be immutable. updates via swap! to an atom may be retried, which is a bad idea with mutable objects.

12:23 EvanR: for the deftype, its required to put ^:volatile-mutable ? the method name to set a field must be set-foo! ?

12:24 puredanger: that part should be ok, because updating the map is its own operation, nothing is getting mutated there. but the objects would be modified some other way. a map of refs is immutable

12:24 Bronsa: dnolen_: in clojure? w/ a resident compiler there's no way to know for sure if you're never going to need a Var.

12:24 EvanR: i dont know if im using the right terminology for refs

12:24 puredanger: the syntax to set mutable fields inside a deftype is: (set! <field> <expr>)

12:24 hiredman: tree shaking/dead code elimination is a whole program optimization, but in clojure the compilation unit is a single form

12:24 Bronsa: dnolen_: i.e. you could get it dynamically via resolve, eval

12:25 dnolen_: Bronsa: does not compute. For a production artifact with whole program optimization? I don't see how it's any different for JavaScript

12:25 production artifact doesn't need eval

12:25 well

12:25 "might not need"

12:25 EvanR: inside a deftype? eh.. maybe i need a record

12:25 puredanger: EvanR: records only have final fields

12:25 EvanR: whats a final field?

12:25 puredanger: EvanR: you can cheat with arrays though (which are mutable)

12:25 EvanR: cannot be changed

12:26 dnolen_: Bronsa: in anycase this answers my question, no one has tried to do a Closure style tree shaking pass on the AST

12:26 Bronsa: dnolen_: right in cljs since there's no resident compiler, reified namespaces & the compilation unit is the ns/program tree shaking should be trivial

12:26 puredanger: EvanR: here's an example alioth program that uses deftype with mutable fields to do dirty fast things http://benchmarksgame.alioth.debian.org/u64q/program.php?test=knucleotide&lang=clojure&id=5

12:27 dnolen_: Bronsa: as to why I care, if some one had already started on this for Clojure than it would be nice to reuse for ClojureScript such that Google Closure only works on pre-shaken source

12:27 Bronsa: Scala.js is doing this and it can have a dramatic effect of advanced compile times

12:27 Bronsa: dnolen_: I mean, arrdem has -- but he needed to make some assumptions on the clj code

12:27 dnolen_: Bronsa: using tools.analyzer?

12:27 Bronsa: dnolen_: well then you might reuse his impl, one sec

12:27 dnolen_: yes

12:27 dnolen_: https://github.com/oxlang/oxcart/blob/master/src/main/clojure/oxcart/passes/tree_shake.clj

12:27 EvanR: ok so i would make a method set-foo! and implement it as (set! foo ...

12:28 dnolen_: Bronsa: great thanks

12:28 triss: hey all... I'm messing with lein-cljsbuild

12:28 where can i find out/goog/base.js?

12:28 puredanger: EvanR: yes, you could do that. You can't define methods in a deftype though. Rather you define an interface or protocol and implement it in the deftype

12:28 EvanR: puredanger: and when passing the "deftype" value around, this is a ref to an object right

12:28 triss: if it's not there is my build likely to be misconfigured.

12:28 ?

12:28 dnolen_: triss: that's specified by :output-dir

12:29 puredanger: EvanR: yes, will be an object with real (public) fields that you could access via (.- obj field) too

12:29 Bronsa: dnolen_: I'm not much familiar with that code but IIRC all that's doing is trivially merging the var reach set of every def & removing from the program AST the defs not reachable

12:29 dnolen_: Bronsa: cool, I will take a look

12:29 triss: splendid thanks dnolen_

12:29 puredanger: EvanR: just to reiterate, this is all rarely used, way off the beaten path stuff, specifically for the purposes of performance or implementing low-level stuff

12:30 EvanR: my algorithm is more straight forward in terms of mutable objects

12:30 but maybe not rendered as clojure

12:31 puredanger: mutable objects are pretty intentionally hard to create or use in Clojure

12:31 it should feel like you are actively fighting the grain

12:31 as you are

12:31 EvanR: so far so good then

12:33 Bronsa: ,(deftype x [^:volatile-mutable x] Object (toString [_] (set! (.x _) 1) "foo"))

12:33 clojurebot: sandbox.x

12:33 Bronsa: ,(x. 1)

12:33 clojurebot: #<ClassCastException java.lang.ClassCastException: sandbox.x cannot be cast to compile__stub.sandbox.x>

12:34 * Bronsa ba dum *tsh*

12:35 EvanR: hmmm, a vector of two vars ;)

12:36 {blake}: At what point when you're building a web app do you say "OK, that's enough--too much--Javascript. I'm going to incorporate CLJS."?

12:36 bbloom: {blake}: mkdir

12:36 puredanger: (inc bbloom)

12:36 lazybot: ⇒ 50

12:37 EvanR: cp ~/jsutils/* ~/project/js/

12:37 {blake}: Heh. 'k.

12:40 justin_smith: Bronsa: puredanger: I started a repo as a demo of when / how type hints are usefull. PR for demonstrating tricky or interesting corners of the domain are quite welcome. To keep things simple I am just testing for the existing warnings rather than testing for reflection or boxing directly.

12:41 https://github.com/noisesmith/hint-hint oops, almost forgot to link the repo

12:42 EvanR: i got it

12:43 its a map of refs to regular clojure structures

12:48 ,(ref (ref 0))

12:48 clojurebot: #<Ref@4270f8: #<Ref@6c7a9: 0>>

12:48 EvanR: sweet

12:49 justin_smith: ~ref

12:49 clojurebot: It's greek to me.

12:49 justin_smith: ~refs

12:49 clojurebot: I don't understand.

12:49 justin_smith: ~stm

12:49 puredanger: this kind of thing is generally a bad idea :) most people find they are happiest with no more refs than you can hold in one hand.

12:49 clojurebot: I don't understand.

12:49 justin_smith: I forget where the factoid about using refs went...

12:50 EvanR: the common thing to find is an atom holding a map. If alteration is heavily parallel, you will see a small number of refs, each holding a map.

12:52 hiredman: fewer

12:57 gfredericks: is there a general way to flip a bit on a Byte?

12:57 I had to special case the sign bit

12:58 which can't possibly be necessary

12:58 ,(bit-shift-left 1 7)

12:58 clojurebot: 128

12:58 gfredericks: ^ can't really use that on a byte since it's out of range

12:58 puredanger: this sounds like the kind of thing where ztellman must have made a library :)

12:59 gfredericks: I could have 8 constants lying around but that seems sooper weird

12:59 bja_: I feel like there was a binary protocol library that ztellman built which would apply here

12:59 puredanger: gloss

12:59 but I don't think it does

13:00 java bytes are (stupidly) signed but surely there's a lib that does this right

13:01 gfredericks: what happens in java if you do (1 << 7) on a byte?

13:01 justin_smith: ,(byte (bit-shift-left 1 7))

13:01 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Value out of range for byte: 128>

13:02 justin_smith: ,(set! *unchecked-math* true)

13:02 clojurebot: #<IllegalStateException java.lang.IllegalStateException: Can't change/establish root binding of: *unchecked-math* with set>

13:02 gfredericks: oh I hadn't thought of that

13:02 Bronsa: ,(alter-var-root *unchecked-math* (constantly true))

13:02 justin_smith: ,(binding [*unchecked-math* true] (byte (bit-shift-left 1 7)))

13:02 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Boolean cannot be cast to clojure.lang.Var>

13:02 #<IllegalArgumentException java.lang.IllegalArgumentException: Value out of range for byte: 128>

13:03 Bronsa: ,(alter-var-root #'*unchecked-math* (constantly true))

13:03 clojurebot: true

13:03 justin_smith: ,(byte (bit-shift-left 1 7))

13:03 clojurebot: -128

13:03 justin_smith: thanks Bronsa

13:03 Bronsa: justin_smith: binding won't work there, you need *unchecked-math* to be true at compile time

13:03 justin_smith: got it

13:03 Bronsa: and it's quite annoying

13:04 justin_smith: Bronsa: my approach to this in the hint-hint lib https://github.com/noisesmith/hint-hint/blob/master/src/org/noisesmith/hint_hint/capture_warnings.clj

13:04 gfredericks: thanks justin_smith Bronsa

13:06 Bronsa: justin_smith: uhm, does hint-hint cover only "when to use type hints" or can it also be "type hinting wtfs galore"?

13:06 justin_smith: Bronsa: the latter would be great - maybe in a separate namespace to differentiate useful tricks from gotchas

13:07 Bronsa: my motivation is that whenever questions come up here about type hints, we get a lot of "I think..." or "well actually..." so something that demonstrates all the points would be useful I think.

13:07 Bronsa: nice, I'll find some time to contribute

13:07 justin_smith: Bronsa: awesome! thanks.

13:18 EvanR: well thats not going to work very well either. so next is to do it all without mutation by simulating refs with indexes into another map

13:19 and always use indirection

13:20 forgotten objects with no references to them wont be collected by a gc, but since its just for a local algorithm it doesnt matter

13:21 justin_smith: EvanR: by local, do you mean it all happens in one thread, and in one let block?

13:22 EvanR: its a pure function, referentially transparent, and its not multithreaded

13:22 justin_smith: if so, you could get away with a java.util.HashMap / java.util.Arraylist

13:22 EvanR: well that would make sense

13:23 is the java syntax attrocious though?

13:23 puredanger: much less attrocious than mutable deftypes and refs of refs :)

13:24 justin_smith: EvanR: ##(doto (java.util.HashMap.) (.put "a" 1))

13:24 lazybot: ⇒ {"a" 1}

13:24 justin_smith: the doto is useful for chaining, because .put does not return the map

13:24 EvanR: well ill try the immutable way, since all my assoc-ins gets and update-ins started shattering when i tried to use mutable objects

13:25 Empperi: I'm curios, haven't ever tried this

13:25 EvanR: ill try the immutable secondary space first

13:25 Empperi: ,(doto (java.util.HashMap.) (.put :a 1))

13:25 clojurebot: {:a 1}

13:25 Empperi: ,(:a (doto (java.util.HashMap.) (.put :a 1)))

13:25 bja_: does java have something like python's __getitem__ that you could use?

13:25 clojurebot: 1

13:25 Empperi: nice

13:25 it should have worked but wanted to check

13:25 bja_: what das __getitem__ do?

13:26 does

13:26 maybe I'll just google

13:26 bja_: I've implemented assoc-in/update-in with python's mutable collections with __getitem__/__setitem__

13:26 it's the dict/array item access syntax

13:26 foo[0], bar['baz']

13:26 it'd probably be some sort of interface in java

13:26 Empperi: ,(doc get)

13:26 clojurebot: "([map key] [map key not-found]); Returns the value mapped to key, not-found or nil if key not present."

13:26 bja_: map's .get maybe

13:27 justin_smith: bja_: get-in / assoc-in I would guess

13:27 Empperi: ,({"a" 1} "a")

13:27 clojurebot: 1

13:27 Empperi: ,(get {"a" 1} "a")

13:27 bja_: err, do get-in/assoc-in work with HashMaps of HashMaps?

13:27 clojurebot: 1

13:27 justin_smith: ,(get-in {:a {:b 0}} [:a :b]) ;; bja_

13:27 clojurebot: 0

13:27 justin_smith: ,(assoc-in {:a {:b 0}} [:a :b :c] 3) ;; bja_

13:28 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.Associative>

13:28 justin_smith: ,(assoc-in {:a {:b 0}} [:a :b] :c 3) ;; bja_

13:28 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (4) passed to: core/assoc-in>

13:28 justin_smith: err...

13:28 Empperi: :)

13:28 bja_: well, I meant java.util.HashMap. I know they obviously work in clojure (I was implmenting get-in/assoc-in/update-in in python because I missed them from clojure)

13:29 nvm, I'm just causing chaos at this point. ignore my line of questions/comments please :)

13:29 Empperi: ,(get-in (doto (java.util.HashMap.) (.put :a (doto (java.util.HashMap.) (.put :b 1)))) [:a :b])

13:29 clojurebot: 1

13:30 justin_smith: bja_: looks like that's your answer though

13:30 bja_: ah, nice

13:32 EvanR: (get-in the choppa)

13:32 bja_: so get-in works, but assoc-in/update-in won't work because HashMap is not clojure.lang.Associative

13:32 justin_smith: makes sense

13:37 ppppaul: hello clojures

13:43 justin_smith: hello

13:50 ppppaul: hello again

13:51 EvanR: is there dissoc-in

13:51 or something

13:54 justin_smith: EvanR: I think flatland/useful may have dissoc-in

13:55 EvanR: https://github.com/flatland/useful/blob/develop/src/flatland/useful/map.clj#L81 it's here

13:56 ppppaul: flatland/useful no documentation :/

13:56 whodidthis: if i have a map (def cool {1 "a" 2 "b" 3 "c"}) whats a nice way to automatically bind the map values into globals cool-1, cool-2, cool-3, instead of using (get cool 1)

13:56 justin_smith: ppppaul: did you look at the link? the doc strings are pretty comprehensive

13:57 ppppaul: i'm looking through the code now

13:57 i like it. but even something like auto generated readme could be helpful

13:57 justin_smith: ppppaul: I think that's what this does https://github.com/flatland/useful/blob/develop/build-docs.sh

13:57 you could clone the repo and run it

13:58 ppppaul: :D

13:59 justin_smith: http://flatland.org/useful/ <- I think this is generated from that script

13:59 ppppaul: nice!

14:01 anyone who has some experiecne with lighttable and cljs i could use some help in #lighttable

14:03 trying to get my console logging to print to the lighttable console instead of the browser console

14:05 is this even possible?

14:07 BobSchack: ppppaul: Are you connected to the lighttable browser or an external one?

14:08 ppppaul: external

14:08 can't do HTTP stuff in the browser LT opens

14:08 CORS problems

14:09 BobSchack: What kind of HTTP stuff are you talking about? DOM manipulation?

14:10 ppppaul: HTTP requests to servers other than localhost

14:11 even GET requests fail

14:14 arrdem: justin_smith: so what's going on with hint_hint?

14:14 * arrdem reads scrollback

14:17 justin_smith: arrdem: the idea is that its a set of unit tests that prove where type hints are needed

14:18 arrdem: and any gotchas (eg. things that aren't actually useful)

14:20 arrdem: https://github.com/noisesmith/hint-hint/blob/master/test/org/noisesmith/hint_hint_test.clj current state of the tests - doing things that either provoke a warning or not, and using test/is to verify whether a warning happens

14:25 oggie: new to clojure and trying to understand how to do if /else logic... Anyone up for helping me out?

14:25 justin_smith: ,(if true :ok :no)

14:26 clojurebot: :ok

14:26 justin_smith: ,(if fase :ok :no)

14:26 BobSchack: ppppaul: Have you tried shoreleave remote (http://shoreleave.github.io/shoreleave-remote/#shoreleave.remotes.jsonp)?

14:26 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: fase in this context, compiling:(NO_SOURCE_PATH:0:0)>

14:26 justin_smith: ,(if false :ok :no)

14:26 clojurebot: :no

14:26 oggie: justin_smith I tried that, but It doesn't work how I'm doing it

14:26 justin_smith: oggie: what are you actaully trying to do?

14:27 oggie: check to see if a username/password is not passed in (nil) and act differently

14:28 here's what I have

14:28 session (-> (if (not-any? nil? [username password]) (alia/cluster {:contact-points cluster :credentials {:user username, :password password}}) (alia/cluster {:contact-points cluster}) ) (alia/connect keyspace))

14:28 so don't add username/pass to the session if it's nil

14:32 justin_smith: oggie: that looks right, as long as the {:contact-points ...} map should be the first arg to alia/connect

14:33 the (alia/cluster {:contact-points ...}) that is

14:33 oggie: justin_smith it is supposed to be 1st

14:34 it works if I hard code the username/password in there and not use the if

14:34 hmm. maybe I do have it right

14:34 :-)

14:35 this is tough coming from Java for years

14:35 justin_smith: oggie: it may be clearer with let bindings instead of ->

14:36 oggie: ok

14:51 arrdem: is there a trick for looking a value up out of a map throwing if it doesn't exist?

14:51 amalloy: arrdem: use python

14:52 * arrdem chuckles

14:52 EvanR: uhm..

14:52 justin_smith: ,(get {:b 0} :b (lazy-seq (throw (Exception. "boom"))))

14:52 EvanR: ,(:abc {})

14:53 clojurebot: 0

14:53 EvanR: ,({} :abc)

14:53 clojurebot: nil

14:53 justin_smith: ,(get {:b 0} :a (lazy-seq (throw (Exception. "boom"))))

14:53 llasram: Oh, slowness

14:53 clojurebot: nil

14:53 justin_smith: kinda hackish

14:53 clojurebot: #<Exception java.lang.Exception: boom>

14:53 justin_smith: actually works in a real repl though

14:53 Bronsa: justin_smith: you can never know when that'll throw though

14:53 llasram: I think clojurebot is just lagging

14:54 Bronsa: or even if that will throw at all

14:54 justin_smith: Bronsa: where would the gotcha be? if the value was not used?

14:54 Bronsa: justin_smith: yep

14:54 justin_smith: suppose (if (symbol? x) x 'foo)

14:55 llasram: &((fn safe-get [m k] (let [v (get m k ::not-found)] (if-not (identical? ::not-found v) v (throw (ex-info "not-found" {:m m, :k k}))))) {} :foo)

14:55 lazybot: clojure.lang.ExceptionInfo: not-found {:m {}, :k :foo}

14:56 llasram: lazybot: not so lazy today, now are you!

14:56 justin_smith: &((fn safe-get [m k] (if-not (contains? m k) (throw (Exception. "boom")) (get m k))) {} :foo)

14:56 lazybot: java.lang.Exception: boom

14:56 arrdem: llasram: that's nicer than the one I came up with. yoink!

14:57 justin_smith and I had the same solution

14:57 Bronsa: ,((fn safe-get [m k] (if-let [[_ v] (find m k)] v (throw (Exception. "boom"))) {} :foo)

14:58 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

14:58 Bronsa: well.

14:58 you get the idea.

14:58 justin_smith: Bronsa: oh yeah, find is a nice way to do that one

14:58 llasram: Oh nice, yeah

14:59 arrdem: won't that be identical to llasram's solution? both only do one lookup, whereas the contains? version will do two.

15:00 llasram: But Bronsa's doesn't depend on a magical sentinel which you can't ever have as a value in the map

15:00 justin_smith: it's more elegant, but only one lookup as with llasram's

15:00 arrdem: ah good point. In this context I don't care, the set of possible keys is strings only, but yeah in theory Bronsa wins.

15:00 (inc Bronsa)

15:00 lazybot: ⇒ 77

15:02 justin_smith: (inc Bronsa)

15:02 lazybot: ⇒ 78

15:03 dnolen_: ClojureScript 0.0-2411 out

15:03 EvanR: why doesnt (fn [x] (prn x) x) work in the middle of a -> macro sequence

15:04 arrdem: EvanR: ((fn ..)) will.

15:04 EvanR: ohk

15:04 justin_smith: ,(macroexpand '(-> 1 (fn [x] (prn x) x)))

15:04 clojurebot: #<CompilerException java.lang.IllegalArgumentException: Parameter declaration 1 should be a vector, compiling:(NO_SOURCE_FILE:0:0)>

15:04 arrdem: EvanR: (-> x (fn [x] x)) -> (fn x [x] x)

15:05 llasram: EvanR: bonus protip: (-> ... (doto prn) ...)

15:05 justin_smith: ,(macroexpand '(-> foo (fn [x] (prn x) x)))

15:05 clojurebot: (fn* foo ([x] (prn x) x))

15:06 justin_smith: (inc llasram)

15:06 lazybot: ⇒ 42

15:06 justin_smith: yeah that's actually the right way to do it

15:07 wirrrbel: I wanted to checkout yesql and ring / rook

15:07 up until now my project was clojurescript only

15:08 now I wonder where to put my sql file

15:09 justin_smith: wirrrbel: relative to the classpath means if you ask for "some/where/foo.sql" it can be in "src/some/where/foo.sql"

15:11 wirrrbel: justin_smith: thank you

15:36 EvanR: note to self core.match patterns do not introduce variables that shadow

15:36 thought i was going insane

15:42 ppppaul: can i pretty print in cljs?

15:43 i'm having issues printing to the console :/

15:52 dnolen_: ppppaul: sadly no pretty printer built in - jonasen had a port of bblooms' fipp - might be useable unsure

15:53 and by "not built in" I mean I haven't received a clojure.pprint patch

16:03 ppppaul: hmm. i'll deal without one for now...

16:09 kenrestivo: is it kosher to use send for serializing synchronous access to i/o, where i *want* it to block?

16:11 i suppose i could use send-off and then deref to block. but i'm wondering why not use send instead?

16:11 llasram: kenrestivo: Why are you using an agent if you want synchronous access?

16:12 kenrestivo: because some operations i want the agent send-off behavior.. others i don't

16:13 llasram: Can you share the broader context some?

16:13 kenrestivo: it's just a device

16:14 so i've got an agent serializing access to it

16:15 amalloy: kenrestivo: deref doesn't block at all

16:16 llasram: Ok. Well, my 2 cents is that it doesn't sound like an agent is the best fit :-)

16:16 amalloy: it's not clear what difference between send and send-off is relevant here

16:16 kenrestivo: ah right, only on futures/promises, not on agents

16:16 justin_smith: kenrestivo: how about a thread reading a queue and writing to device, it also gets passed a promise that it delivers to when the write is done?

16:16 kenrestivo: yeah, i think the agent approach isn't going to work. thanks.

16:16 amalloy: kenrestivo: if you want exclusive, synchronous read/write access to a device, i'd just use a mutex

16:17 llasram: (inc amalloy)

16:17 lazybot: ⇒ 201

16:17 amalloy: you can cobble together stuff with agents and await and blah blah blah, but like...locks aren't strictly bad

16:17 kenrestivo: was hoping to avoid j.u.c. interop, but i guess why not.

16:17 amalloy: kenrestivo: ?????? ##(doc locking)

16:17 lazybot: ⇒ "Macro ([x & body]); Executes exprs in an implicit do, while holding the monitor of x. Will release the monitor of x in all circumstances."

16:18 dbasch: amalloy: there was a mixup, we sent rich hickey a cardboard cutout of you

16:18 kenrestivo: nice

16:18 amalloy: dbasch: that was you crouching in the bushes with a camera? i thought i'd become interesting to the paparazzi somehow

16:18 dbasch: it was hand-drawn

16:18 kenrestivo: amalloy: once again, thanks for showing me a new corner of clojure i had no idea existed

16:18 dbasch: no word from rich hickey yet

16:19 the clojureazzi

16:19 * dbasch goes back to pretending to work

16:20 EvanR: a queue with max size 1 would also work

16:21 and you would have to muck with mutices

16:21 wouldnt*

16:21 justin_smith: EvanR: I thought there was an implication that he only sometimes wanted to block

16:21 also, locking isn't much of a muck at all

16:22 EvanR: well P and V are crap

16:23 justin_smith: P and V?

16:23 llasram: Pevear and Volokhonsky?

16:23 EvanR: issue the lock command on a mutex object, then later... you had better issue the unlock on the same mutex

16:23 amalloy: he's a letter connoisseur

16:23 EvanR: that's what locking guarantees to do

16:23 justin_smith: EvanR: that's now how locking works ##(doc locking)

16:23 lazybot: ⇒ "Macro ([x & body]); Executes exprs in an implicit do, while holding the monitor of x. Will release the monitor of x in all circumstances."

16:24 EvanR: yes ok

16:24 justin_smith: all you do is wrap your code in the locking macro, it's not messy

16:24 EvanR: but im not sure exactly how even this corresponds to sometimes blocking

16:25 justin_smith: EvanR: he wanted to block on the write sometimes, and not others. So you want a queue with a larger size than 1, and a way to indicate the write completed (thus my suggestion of a promise)

16:25 EvanR: was the same implication also implying that you also sometimes forgo even doing your write?

16:25 oh

16:26 this policy is way past my concurrent semantics comfort level, crash when queue is maxed?

16:27 block anyway

16:27 dont write?

16:27 justin_smith: it would block on a full queue, let you go on your merry way otherwise. But a full queue indicates slowing you down is probably the right thing to do anyway.

17:10 _ak__: Is there anyone from north-west England, around Manchester or Liverpool here this evening?

17:23 FliPPeh: http://sprunge.us/LYDZ?clj - how's that for my first not-entirely-useless clojure program? Any obviously bad things?

17:26 kenrestivo: FliPPeh: at first glance, there are a couple things you're doing there that might already have functions in clojure.core to do what you want. but rewriting clojure.core functions can be a good learning exercise.

17:27 ,(doc keyword) ;; for example

17:27 clojurebot: "([name] [ns name]); Returns a Keyword with the given namespace and name. Do not use : in the keyword strings, it will be added automatically."

17:27 amalloy: kenrestivo: huh? he calls keyword himself

17:27 FliPPeh: ,(keyword "something with spaces")

17:27 clojurebot: :something with spaces

17:27 FliPPeh: That looks evil

17:28 amalloy: FliPPeh: i don't see why you're converting to keywords at all

17:28 just use strings as your map keys

17:28 FliPPeh: Well what I'm doing there is taking a string that may contain spaces and other weird things and turns those into simple dashes

17:28 I could, but keywords feels more clojury

17:28 justin_smith: FliPPeh: another vote for just using strings as keys

17:29 amalloy: no. don't build keywords out of user-controlled data

17:29 FliPPeh: Alrighty

17:29 justin_smith: keywords are good if you are designing the data structure as literals, but getting it from somewhere else, just leave it a string

17:30 amalloy: otherwise i'd say this is all fairly reasonable, except that i'd use line-seq instead of slurp+lineify

17:31 get a reader, call line-seq, then chunk those based on blank lines, then put the chunks into maps

17:32 dbasch: FliPPeh: also, you don’t need two separate requires

17:32 FliPPeh: Like partition-by on an empty line=

17:32 ?*

17:32 amalloy: sure, seems fine

17:33 EvanR: ,(atom? (atom 0))

17:33 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: atom? in this context, compiling:(NO_SOURCE_PATH:0:0)>

17:34 dbasch: ,(type (atom 0)) ;; EvanR

17:34 clojurebot: clojure.lang.Atom

17:34 FliPPeh: Ah, doesn't seem like line-seq will work here. Apparently it wants a buffered reader, but those don't work on /proc files

17:34 hiredman: what makes you say that?

17:35 FliPPeh: Well, that's what the repl is telling me

17:35 hiredman: what makes you say the repl is telling you that?

17:35 dbasch: FliPPeh: what error do you get?

17:36 kidpollo: Hola @dbasch

17:36 FliPPeh: Whoops pardon, I indeed misread

17:36 clojer: I've downloaded a JAR lib that I want to include in my Clojure project. Where should I put it and how to included in project.clj and any file which :require s it?

17:36 FliPPeh: "(line-seq (java.io.BufferedReader. (java.io.FileReader. "/proc/cpuinfo")))" does the trick just fine

17:36 dbasch: kidpollo: howdy

17:37 clojer: is it something that wasn’t available in a public repository? Because if so, you don’t need to download it

17:37 kidpollo: I am trying to 1 up my clojure fu to the next level by hanging out with the cool kids :P

17:38 clojer: dbasch: Downloaded from an individual developer's website.

17:39 dbasch: I've already downloaded it. How to add it to the project?

17:39 sg2002: clojer: https://github.com/kumarshantanu/lein-localrepo

17:40 dbasch: that’s one way, or you could stick it in a local maven repo

17:41 clojer: http://nakkaya.com/2010/03/16/adding-custom-libraries-into-local-leiningen-repository/ like this

17:41 clojer: dbasch: Do you mean in my .m2 repo?

17:41 dbasch: clojer: no

17:42 you could hack your .m2 repo, but I wouldn’t recommend it

17:42 clojer: dbasch: Nothing fancy .... please :)

17:42 kenrestivo: kidpollo: or you could do 4clojure.com exercises

17:42 dbasch: clojer: I think the article I linked is the easiest way

17:42 at least it’s what I did the last time I had to do this, a couple of years ago

17:43 whodidthis: https://www.refheap.com/94472 how do i get the symbol bound to n replace the last n in this macro

17:43 arohner: fun friday: Puppet Docs + HP Lovecraft in a markov chain: http://thedoomthatcametopuppet.tumblr.com/

17:44 kidpollo: kenrestivo: that also

17:44 clojer: dbasch: Kreist, what a lot of ceremony.

17:45 dbasch: clojer: well, you are including an artifact for which you don’t have the source and that doesn’t happen to be in a repository anywhere

17:46 meaning, you’re using a dependency management tool (lein)

17:46 kenrestivo: there used to be a lein-local. i think it's deprecated, but it probably would't be to hard to have a lein plugin that wraps the mvn ceremony to install a local jar into ~/.m2

17:46 clojer: dbasch: Been spoiled by Ruby for too long, maybe. `require_relative <module>`. Done.

17:46 arohner: you can 'lein install' arbitrary jars

17:47 it generates a minimal pom for you

17:47 EvanR: heh require_relative

17:47 clojer: arohner: Now yer talkin'

17:47 EvanR: autoloading yall

17:48 kenrestivo: "gem install hairball" :-P

17:48 amalloy: clojer: well. that's nice in some ways, and lein is nice in others. clojure (and java) would much rather automatically download dependencies for you, from a repository, than have jars floating around your whole filesystem

17:48 arohner: clojer: I must be misremembering. you can certainly 'mvn install' :https://maven.apache.org/plugins/maven-install-plugin/usage.html

17:48 amalloy: are you sure this thing you're trying to use isn't in any repo anywhere?

17:49 downloading jars by hand is a desperation move, a last resort

17:49 clojer: amalloy: I don't think so but I'll double-check.

17:50 arohner: clojer: and if you're doing a 'serious' project, it's often worthwhile to have your own private repo

17:50 using e.g. nexus or https://github.com/technomancy/s3-wagon-private

17:51 * kenrestivo has exactly 11 jars in his private mvn repo

17:52 whodidthis: https://www.refheap.com/94473 or is this possible somehow, defin with the created symbol instead of n

17:52 kenrestivo: everything else, googling "libraryname maven" found some repo somewhere with it.

17:57 dbasch: whodidthis: I don’t understand what you’re trying to do

17:58 justin_smith: whodidthis: the way def works, it will always define n

17:58 whodidthis: ok, im a bit of a bad then

17:59 justin_smith: are you trying to pass a string to def-k and end up with that string being a def with the value "nice"?

17:59 whodidthis: yes :(

17:59 justin_smith: (defmacro def-k [k] `(def ~(symbol k) "nice"))

17:59 still very silly

17:59 but that should actually work

18:00 dbasch: whodidthis: look into intern

18:00 justin_smith: yeah, intern is actually a nicer way to do it, as long as the metadata that def adds isn't important to you

18:02 whodidthis: i wanted to find a nice way to get a maps keys and values deffed, like {1 "a" 2 "b"} => (def value-1 "a") (def value-2 "b")

18:02 EvanR: hah

18:02 php extract

18:02 only global

18:02 dbasch: whodidthis: that is a strange requirement

18:03 whodidthis: so i could access them with values/value-1 instead of (get values/values 1)

18:03 EvanR: if you use that a lot on a large map, you wont know heads from tails

18:03 dbasch: if you need to keep global state, you shouldn’t be defining variables willy-nilly

18:03 whodidthis: it was just a nice color scheme :(

18:12 amalloy: yeah, just leave it in the map. value-1 doesn't save a lot of characters compared to (values 1), and it avoids some other headaches

18:12 celwell: Hi, I'm trying to get a single Set of all page numbers. I have this code, which works, but I was wondering if I could get any feedback for a more idiomatic way of writing it.

18:12 (reduce #(apply conj %1 (s/split (:pages %2) #","))

18:12 #{}

18:12 [{:id 1 :pages "1,2,3,4"}

18:12 {:id 2 :pages "2,3,4,6,7"}

18:12 {:id 8 :pages "9,10,12"}])

18:15 EvanR: (concat (map (comp split-on-comma :pages)))

18:17 weavejes_: (mapcat (comp split-on-comma :pages) data)

18:17 (set *1)

18:19 celwell: Thanks, I like weavejes_'s answer the best.

18:20 amalloy: (reduce into #{} (map (comp split-on-comma :pages) xs)) is also possible

19:21 {blake}: OK, so I'm creating a login. I go to the page, get the login (sony/password) and now I want to go back to "/" with the "sony" in the session map. I was looking at "redirect" but it doesn't take a body.

19:31 If something is a library and not in clojars, do you just download it and make it part of your own code?

19:32 zeapo: {blake}: that depend on the licence. Check if you can redistribute it.

19:33 xeqi: {blake}: it might be in http://search.maven.org/

19:35 {blake}: xeqi: 'tis not.

19:40 justin_smith: {blake}: for doing a redirect and also putting something in the session, maybe try (assoc (redirect url) :session updated-session)

19:40 redirect should return a response map I think

19:40 or, if that was a login, it could be (assoc (redirect-after-post url) :session updated-session)

19:40 {blake}: justin_smith: Thanks, lemme try.

19:42 (inc justin_smith)

19:42 lazybot: ⇒ 152

19:42 dbasch: {blake}: it is a clojure library and it’s not on clojars?

19:43 {blake}: I've SO got to run through all my compojure stuff again. I'm not thinking right at all.

19:43 dbasch: Yeah, it's a little weavejester thing called "decorate".

19:44 dbasch: {blake}: ask weavejester to put it on clojars

19:45 or fork it and do it yourself

19:45 amalloy: oh my gosh it's five years old

19:46 it looks like a bad version of robert.hooke, or maybe just convenience wrappers over alter-var-root?

19:47 {blake}: It was more of an idle question. It's just what happens when you chase around the web looking for helpful information. Sometimes the most helpful (looking) stuff relies on ephemera.

19:54 justin_smith: {blake}: crossclj.info is good for seeing which libraries people are using

19:55 http://crossclj.info

19:55 and more usage often means more helpful

19:56 {blake}: justin_smith: Yeah, but in this case, I was looking for explanation and found this: http://blog.experimentalworks.net/2010/02/dealing-with-sessions-in-compojure/

19:56 Which uses that "decorate" thing. Though I did manage to figure out that I didn't need it. So I got that going for me.

19:57 Wow, midje's up there.

20:00 justin_smith: yeah, I was surprised it was so prevalent

20:01 aha, decorate is doing the "decorator pattern", which you can also do with standard ring middleware

20:12 {blake}: justin_smith: Right, I sorta guessed that. I read it and thought "Hey, isn't that what you always do with everything ring-based?"

20:29 thearthur: this core.logic SO question needs some attention: http://stackoverflow.com/questions/27324013/core-logic-unification-matches-value-in-map-but-not-key

20:35 amalloy: thearthur: you're arthur ulfeldt? the question's only been up for five hours, and it has three upvotes; i'm sure it will get some answers when someone qualified comes across it. and if it doesn't, you certainly have the resources to put a bounty on it

20:36 TEttinger: asked by shaft, amalloy

20:36 amalloy: TEttinger: yes, i see that. so?

20:36 thearthur: amalloy: thats me, yep. it's just bugging me and i'm impatient :-)

20:37 TEttinger: oh, i thought bounties were added by the asker

20:37 amalloy: anyone can put a bounty on anything

20:38 TEttinger: stack overflow/exchange is certainly different

20:38 justin_smith: thearthur: oh hi, I'm noisesmith on stackoverflow, we've crossed paths there a few times

20:38 amalloy: i mean, in practice most of the time people put bounties on their own questions because they really want an answer

20:39 but some third party can do it if they want an answer too, or just if they think it was a good question that deserves an answer; when you have as much rep as arthur, spending 50 on someone else's question is no big deal

20:39 TEttinger: rep is precious! I have like 9!

20:40 thearthur: perhaps I should switch nicks to match everywhere else

20:41 I'm unable to find an add bounty button on this question

20:42 amalloy: thearthur: you can't, because it's only five hours old

20:42 you're supposed to let it simmer for a bit :P

20:42 thearthur: (dec thearthur)

20:42 lazybot: You can't adjust your own karma.

20:42 amalloy: or just like...mention dnolen_ and http://stackoverflow.com/questions/27324013/core-logic-unification-matches-value-in-map-but-not-key in the same line

20:43 TEttinger: dnolen_ with the underscore of inactiveness?

20:43 amalloy: he'll get it eventually, i imagine

20:43 TEttinger: there's also $mail

20:44 that's one of the more widely used features on my lazybot

20:50 amalloy: $mail TEttinger i heard you like mail

20:50 lazybot: Message saved.

20:52 TEttinger: $mail amalloy yes I do

20:52 lazybot: Message saved.

20:52 amalloy: $login

20:52 lazybot: You've been logged in.

20:52 amalloy: $unmail TEttinger amalloy

20:52 lazybot: Deleted unread messages from TEttinger to amalloy

20:52 amalloy: hacks

20:52 $logout

20:52 lazybot: You've been logged out.

20:52 TEttinger: heh, I didn't know you had a login

20:52 nice

20:55 tuft: is there a repl client for clojuredocs.org? e.g. (clojuredocs cond) to see examples of cond

20:56 justin_smith: $grim clojure.core/cond is similar

20:56 lazybot: http://grimoire.arrdem.com/1.6.0/clojure.core/cond

21:01 andyf: tuft: github.com/jafingerhut/cd-client

21:02 tuft: But the data you get via the API is currently stuck at about sep 2014 when they upgraded the rest of the site from clojure 1.3 source to 1.6

21:03 There is an issue requesting updating the API data, too, at github.com/zk/ClojureDocs

21:18 timvisher-xubunt: anyone aware of a port of tools.trace to clojurescript?

21:20 justin_smith: timvisher-xubunt: I bet you could do some nice tracing and even step debugging with the browser's inspector

21:22 timvisher-xubunt: justin_smith: that's probably true. but i'm headless at the moment and would prefer to continue to be.

21:22 tools.trace is _so_ nice but it doesn't look like anyone's tried to port it yet

21:22 stuartsierra: i'm assuming you haven't heard anything?

21:23 actually, you stopped maintaining it iirc, sorry :|

21:32 Jesterman81: hey ladies/gents, quick question. I have a clojure web app using hiccup with something like [:a {:href “/img/foo.jppg”}]

21:32 do I have to manually add the context if I am deploying to a tomcat instance?

21:33 justin_smith: Jesterman81: it's easier if your app is at the root, I don't know if there is any nice automated way to add the context to links

21:34 Jesterman81: our approach has been to make a function that generates a route for a resource or endpoint, and call that

21:34 and let that function adjust for the context path etc.

21:34 amalloy: justin_smith: i think the only thing you can do is write a function like make-link, and have that function know what the context is

21:35 justin_smith: that also ends up helping when the client want's different URLs but you don't want to do a major app rewrite

21:35 amalloy: figures, yeah that's what we do

21:35 Jesterman81: thanks, I was hoping I just wasn’t missing something easy

21:36 justin_smith: you may get something about the context info from the container in the request map

21:36 couldn't hurt to dump the request map as you receive it in tomcat and look for something useful

21:38 Jesterman81: ill take a look at the request and see whats in there

21:40 justin_smith: another option would be using a config to export the context as a system property that the clojure app can then pick up

21:41 Jesterman81: thanks for the options. appreciate it

22:17 Frozenlock: In compojure, is it possible to apply different middlewares to different routes? (c/routes (-> r1 m1 m2 m3) (-> r2 m4 m5 m6)) ?

22:29 justin_smith: Frozenlock: yes. I am a little fuzzy on the details as I don't use compojure in anger myself, but I know that middlewares can be used to wrap individual routes

22:29 it should just be a question of function composition

22:30 Frozenlock: justin_smith: thanks

23:18 AH! Found how to do it. Must use compojure.core/wrap-routes to wrap the routes *only once they have been matched*.

23:40 josiah14: I'm reading through a bunch of Clojure code seeing how much I can figure out/comprehend, and I ran across what looks like a very short lambda function which is a bit cryptic to me in syntax. Can anyone tell me at a high level what #(%2) does, and why calling reductions with it on a list of read-line functions requires an initial value of nil for every function in the list to get executed?

23:41 justin_smith: josiah14: ##(macroexpand '#(%2))

23:41 lazybot: ⇒ (fn* [p1__13570# p2__13569#] (p2__13569#))

23:41 josiah14: the actual code is like, (reductions #(%2) nil (repeat n read-line)) where 'n' is some calculated number

23:42 justin_smith: does the above macroexpansion make sense?

23:42 equivalent: (fn [a b] b)

23:42 err

23:42 (fn [a b] (b))

23:43 josiah14: actually, I think so

23:43 justin_smith: it expects two functions, and calls the second one, ignoring the first

23:43 josiah14: yah, that's what I got from that. I'm still getting used to reading macros.

23:43 justin_smith: well, two things, and calls the second as a no arg function actually, to be more precise

23:43 josiah14: is there a better function I could use there so that i can eliminate the nil initial value

23:44 I would have thought #(%1) would be like that one but call every function

23:44 I can't remember what the error message was

23:44 justin_smith: well, the thing is the first version takes N args, and only calls the second one

23:45 so that's a really weird "reduce" in that it always throws away the accumulator

23:45 it would be much clearer as a doseq

23:45 (doseq [f (repeat n read-line)] (f))

23:45 josiah14: except I need the values returned from read-line

23:45 justin_smith: oh, reductions

23:45 sorry

23:45 it's not reduce, but reductions, so you do see each result

23:45 josiah14: yes

23:45 basically

23:46 justin_smith: (doall (for [f (repeat n read-line)] (f)))

23:46 you still get all the results, but what it's doing is much more clear

23:46 josiah14: i thought there had to be somethnig simpler

23:47 yah, it'll probably take me a bit to get the syntax down. I know conceptually what I want to do, but then figuring out how to say it in Clojure is proving tough for impure functions, yet

23:48 but then, Haskell was tough in that way too (and it's looking like this will be easier than learning all that crap about Monads, Monad Transforms, Arrows, etc.)

23:48 justin_smith: the way I see it that there is a strategy of making immutable and pure very easy to do, and impurity a bit trickier

23:49 josiah14: the general rule of thumb that has worked for me is take everything you think may have to mutate, turn it into a function argument, and do chained / recursive function calls

23:49 that is pretty effective for translating imperative algorithms to functional world

23:49 josiah14: yah, same as in haskell

23:49 it's IO that gets tricky, and event handling

23:50 justin_smith: you can also "cheat" by making a map holding a "state of the world" under various keys as one of the parameters

23:50 in clojure integrating io/events is a bit easier I think

23:50 it's handled more pragmatically at least

23:50 josiah14: yah, it's looking that way - just a matter of syntax

23:50 rritoch: josiah14: Cant you just map over #(%1) ? As far as I can tell that would produce the same results

23:50 josiah14: (map #(%1) (repeat n read-line))

23:51 justin_smith: rritoch: that's what the for does, but I think for is more readable in that case

23:51 josiah14: rritoch, yes, that works out perfectly

23:51 just tested in the repl

23:52 justin_smith: josiah14: beware that that is lazy

23:52 that is why I added the doall in my for version, to match the eagerness of reduce

23:52 josiah14: yah, I just need to get the syntax in my head, then I think all that effort I put into Haskell will start to pay off in terms of already knowing how to think functionally

23:52 justin_smith: I'm used to lazy, so no problems, there

23:56 rritoch: justin_smith: Is reductions being depricated? I could be wrong but it seems reductions is replaced with map transducers that have "reduction state"

23:57 justin_smith: it carries no deprecation warning in the latest 1.7 alpha

23:58 but yeah, it may make a lot of sense to use a transducer

Logging service provided by n01se.net