#clojure log - Oct 21 2014

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

0:31 egghead: is there a good lib for wrapping up apis as cli apps in clj?

0:34 justin_smith: you should be able to do most of it with cheshire, clj-http, and tools.cli

0:35 maybe grenchman if the load-up time of an uberjar is still too long

0:40 trx|2: egghead: I use swig for accessing shared libraries (.dll,.so) from clojure. Swig is a command line tool but it wouldn't be difficult to create a custom leiningen plugin to run swig scripts from the command line.

0:41 rritoch: egghead: the problem I run into is with clojure class loaders so you need to register the generated .so or .dll from a static initializer

0:42 eggghead: because of that you typically need to adjust the .java files generated by swig before you compile them

0:43 justin_smith: rritoch: oh, you think he means library apis, I thought he meant http apis

0:44 rritoch: justing_smith: now that you mention it, he didn't specify

0:44 egghead: :)

0:45 as pitiful as the jvm is for cli apps, tools.cli is closest to what I was looking for with my vague question, just was wondering if there was anything ~fancier~

0:47 justin_smith: fancier means - integration with other tools? cursor control? colorful output?

0:49 egghead: i dunno what I was thinking justin_smith, I guess *in* and clojure.tools.cli are all I need

0:50 justin_smith: egghead: you'll likely find *out* and *err* pretty handy too

0:50 egghead: :p

0:51 justin_smith: plus stuff from clojure.string if you are taking input from stdin that comes from other tools, likely

0:56 rritoch: Does anyone have any suggestions for AOT compiled scripts? I'm developing a clojure web application framework and it seems I made a major performance mistake in the dispatcher. To mimic the behavior of other script languages like PHP I made a (script ...) macro which runs during compilation IF a dispatch variable is set as true.

0:56 arrdem: tbaldridge: watching the commit stream for pixie is an inordinate amount of fun :D

0:57 rritoch: example use case?

0:58 rritoch: my gut is that you're doing it wrong, but I'd like to quantify that

0:58 rritoch: Here is a condensed version of the macro (defmacro script [docstr & body] `(if *dispatch* ~(conj body 'do)))

0:59 Usage could be ... (script "HelloWorld" (println "hello world!"))

1:00 In the actual macro there is also some logging which dumps something like "running script: " docstr...

1:00 justin_smith: and the "script" would be something that optionally occurs as a stateful action during application template rendering while creating a project?

1:01 rritoch: The script is launched with either load-file or load-reader depending on if it is a local resource or a remote (URL)

1:01 justin_smith: in what context? when is the script run?

1:02 rritoch: The script is run from the servlet, this particular servlet sends all requests through the doPost method of the servlet.

1:02 justin_smith: OK that's a really bad idea

1:03 rritoch: Yep, I wanted to mimic the behavior of PHP before I realized how slow it would be

1:03 justin_smith: there is a lot of overhead on eval

1:03 yeah, eval is slow

1:03 rritoch: Now I want to undo that decision, preferably by just changing the macro and possibly the deployment method

1:03 justin_smith: what you want is one server process that stays running for months (maybe even years) at a time, that has a function that gets called for each request

1:04 instead of loading a script, call a function in a handler namespace

1:04 so convert the load-script logic to an invoke-function logic

1:05 this will involve defining the namespaces (of course), requiring them from your main servelet definition, and then invoking their functions - instead of having a file that imperatively does a sequence of steps, have a file that defines a function which another namespace can invoke

1:05 rritoch: Here is the complexity. Say there are more than one scripts in a single CLJ, this creates an issue since it would need to have multiple functions

1:05 justin_smith: rritoch: ok, that is the normal way to do clojure

1:06 I have namespaces with hundreds of functions in them

1:06 well, at least two

1:06 rritoch: Well, the point of this is to smooth the transition for developers coming from other script languages, such as PHP, CGI (Perl), etc.

1:07 * arrdem furrows brow

1:07 justin_smith: that's kind of odd

1:07 rritoch: I was thinking that maybe I could define an atom holding an array, and put the randomly generated function names in that array, and have a single initializer

1:07 justin_smith: why would you randomly generate function names?

1:08 and why would putting the functions in an array be in any way useful?

1:08 rritoch: The problem is the macro expansion would happen for each script in the file so I'm not sure if it's possible to have a different expansion for the first (and/or last) expansion in a given file.

1:08 It is useful because it simulates running a Perl or PHP script

1:10 arrdem: Okay so lemme get this straight

1:10 you have this (script) thing, that runs... when... at load time? at -main invocation time? at AOT time?

1:10 rritoch: So the purpose of using randomly generated function names is to avoid collisions between scripts, than there would be a single function like __run_scripts whic would run all of the scripts

1:10 But defining __run_scripts should only happen in one of the macro expansions

1:10 arrdem: that's a terrible reason. we have gensym. function name collisions are literally impossible.

1:11 justin_smith: rritoch: if they are in an array, they don't need any names at all

1:11 rritoch: arrdem: Yeah, I'm aware of gensym, it is what I plan on using

1:11 arrdem: rritoch: so... why do you have worries about name collision?

1:12 justin_smith: ,((juxt #(+ % 8) #(* % 3) #(mod % 2)) 12) ; rritoch - none of these have names, nor do they need them. They are all functions.

1:12 rritoch: But I would need to collect the list of functions which need to be run from the single script execution function (__run_sccripts)

1:12 clojurebot: [20 36 0]

1:13 arrdem: Why? a "script" is really just a function that sequentially calls a bunch of other anonymous functions in a straight line block..

1:13 justin_smith: rritoch: you can have a list of functions without any names

1:14 rritoch: Ok. so say I have some index.clj script setup which has 3 scripts in it, an init script, a form validation script and an output generation script as would be typical for a single page web application

1:15 justin_smith: what differentiates a script from a function?

1:15 rritoch: These need to be run in order, but the dispatcher has no idea about what index.clj is going to contain, or what functions it will contain

1:15 arrdem: this (if *script ... ) macro thing apparently

1:15 rritoch: arrdem: yes, basically

1:15 arrdem: rritoch: so... you have three functions in a file... go on...

1:16 rritoch: But the macro expansion just surrounds the code in an (if *dispatch* (do ...code...)

1:16 So as of now it runs at load time

1:16 But I want to AOT and simulate this same behavior

1:16 Assuming it's possible

1:16 justin_smith: rritoch: is the condition in the macro, or in the output of the macro?

1:17 rritoch: In the output of the macro

1:17 justin_smith: if the condition is in the output of the macro, and it checks *dispatch* at runtime, you are fine

1:17 just make sure *dispatch* is not resolved during compile time

1:17 rritoch: Yeah, that is how it currently works, but it is slow

1:18 justin_smith: it's slow because you are calling load

1:18 rritoch: I'd like to AOT compile this instead

1:18 justin_smith: you don't need to call load

1:18 just require the namespace, and call the function

1:18 wrap the whole "script" in one function you can call

1:18 rritoch: The dispatcher isn't going to know the names of the functions

1:18 The web designer is going to build index.clj

1:19 With whatever scripts they need to run to produce the web page

1:19 justin_smith: OK, then pass those function names in as an argument

1:19 this is all logic you can do at runtime, without needing to use the compiler to load new code

1:20 rritoch: The dispatcher won't know what the function names are, at least not on an initial HTTP GET request, I can see function names being passed in POST requests, or part of URL's but not for a home page

1:20 But you did give me an idea

1:21 Can the macro define the gensym function with metadata? So at runtime a (run-script) function could extract the list of functions which need to run?

1:22 ex. (run-script "index.clj")

1:22 justin_smith: rritoch: in order to know what to run, there needs to be shared information between the one deciding what runs and the one doing the running. In your case it was a file name.

1:22 rritoch: you can literally take every file name, and make it a function name, that the contents of each file you would load, and put it in a function body.

1:23 there is no extra information needed that was not needed in the original unperformant design

1:23 *that has the contents of each file

1:23 you can have a single namespace, with an "index" function, and a "validate" function, etc. etc.

1:23 no gensyms are needed

1:23 no runtime compilation is needed

1:24 rritoch: Hmm, it's going to take me a few minutes to process that one

1:24 justin_smith: rritoch: that's understandable

1:24 rritoch: So your suggesting I wrap the source code in a function that gets called, and compile that instead so I can just call the function?

1:25 * arrdem cheers

1:25 justin_smith: rritoch: clojure is not a scripting language like php or perl, but I promise that the clojure approach is very useful, and helps make good designs that scale well

1:25 arrdem: (inc justin_smith)

1:25 lazybot: ⇒ 100

1:25 justin_smith: rritoch: yes, that sounds about right

1:25 rritoch: Technically I think that is exactly what I want, but I've never considered that possiblity, nor am I sure where to start, but your right, that would be a fast AOT script

1:25 justin_smith: rritoch: and you don't need to explicitly compile the function, that should happen (as much as is needed) during generation of the uberjar and startup of the app

1:26 rritoch: you have a marvelous new world of app design ahead of you if you stick with it :)

1:27 rritoch: Lol, I have 30 years programming experience, and 10 years web development experience, I'm not new to LISP, but fairly new to clojure (less than a year)

1:27 justin_smith: OK

1:27 rritoch: I'm almost literally over-the hill

1:27 To the point where I'm just making code to pass on to the next generation

1:28 justin_smith: sorry, not meaning to be condescending, just saying, based on your level of (un)familiarity of how things are done here, and my own experience with scripting oriented stuff

1:29 rritoch: No, I understand your perspective. It is the clojure way of doing things, and the solution you came up with is almost exactly what I'm looking for

1:30 In addition to helping developers familiar with scripting languages, this also simplifies the task of translating existing web applications into clojure.

1:30 justin_smith: I think you'll find it's the way of doing things you'll find in any language that doesn't run a process that is expected to run for under half a second and then exit

1:30 rritoch: that is a promising thing, yeah

1:31 rritoch: maybe you could also blog about the adaptation process also - I bet there would be a lot to learn from that

1:33 rritoch: justing_smith: It has taken me a very long time to reach the proof of concept phase where clojure web apps could be run from tomcat, and standalone, deploying .jsp templates and using .clj scripts for deployment.

1:33 Sources can either be in the application, maven or OSGI bundles.

1:34 justin_smith: rritoch: ring makes things a lot easier

1:34 rritoch: I developed a leiningen plugin which copies all dependencies to the WEB-INF/lib folder

1:34 justin_smith: it connects regular clojure functions to the servlet api

1:34 ring does that part too

1:34 rritoch: justin_smith: Ring made things worse, I had to remove it

1:34 justin_smith: rritoch: I suspect you were not using it the way it was meant to be used - I have used it for years

1:34 rritoch: Ring doesn't support JSP

1:34 justin_smith: OK

1:35 rritoch: There is a conflict because Ring provides it's own javax/servlet/Servlet.class

1:35 justin_smith: OK

1:35 rritoch: That of course conflicts with what tomcat provides

1:36 justin_smith: were you using ring uberwar?

1:36 rritoch: It was a nightmare so I disabled ring support until I can find a solution to it

1:36 justin_smith: I have a few ring apps running in tomcat instances

1:36 they work great - but I am not explicitly using jsp, just the ring apis

1:37 rritoch: To support CGI this framework depends on tomcat

1:37 justin_smith: like I said, I have ring apps running via uberwars inside tomcat

1:37 rritoch: So it can be run from the command line, and still process .jsp files

1:38 ring uberwars wouldn't be able to support CGI execution of jsp scripts, simply because of the connnflict with the javax/servlet/Servlet.class

1:38 justin_smith: OK

1:39 I don't really know the jsp part, so I can't address that

1:39 rritoch: But I actually still have ring support in the code, I'm just waiting to find a solution to this conflict issue

1:41 In order to load code from OSGi modules I've needed to wrap tomcat's resources (such as ServletRequest, ServletContext, ServletResponse) in wrappers so I could .forward to code which isn't in the classpath but is in OSGi bundles

1:41 Needless to say this development process was a nightmare because around every corner is a new bug or conflict to deal with

1:42 Now that it is working I'm trying to undo some of the horrible design choices that were made just to get the thing functional.

1:42 justin_smith: rritoch: well, I'll just reiterate what I said above - I put functions into namespaces, compiled at uberjar or application startup time, and use function parameters to vary their behavior, and it works very nicely for me

1:42 arrdem: rritoch: so... what class conflict are you getting with ring? Because Ring doesn't actually package that class as far as I can tell.

1:43 rritoch: arrdem: I was getting a security violation

1:43 aardem: If I recall correctly its because the "signers" don't match between what ring utizes and what the tomcat library provides

1:44 arrdem: rritoch: what version of the servlet package are you using?

1:45 in production that is, ring has another version and I suspect that's where your issue is coming from.

1:45 rritoch: arrdem: but yes, that class is provided by ring, at least it was, I can give you it in a sec, but first I wanted to share the leiningen dep which is [org.apache.tomcat/tomcat-jasper "7.0.52"] and conflicts with ring

1:45 The tomcat dep is the only place of conflict

1:47 I don't know if this is new, but as you can see from the sources, ring won't allow tomcat to be used

1:47 https://github.com/weavejester/lein-ring/blob/master/src/leiningen/ring/uberwar.clj#L26-L33

1:48 Simply because tomcat contains javax/servlet/Servlet.class

1:48 Previously I was getting a security conflict, but with the latest version it looks like the tomcat dependency wouldn't even be loaded

1:49 I wasn't actually running ring from tomcat with uberwar though, I didn't make it that far

1:49 It was crashing while running it from the command line (CGI mode)

1:50 The conflict I was getting comes from this code... https://github.com/weavejester/lein-ring/blob/master/src/leiningen/ring/war.clj#L230-L233

1:51 So, until ring is willing to give up control of what servlet it uses, this application framework can't support ring.

1:52 Without tomcat, there is no easy way to execute .jsp templates

1:52 Making your own .jsp compiler is one option, but it would be an insanely huge project

1:53 justin_smith: rritoch: add a config to make that one step optional, it should be a trivial patch

1:53 rritoch: that seems so much easier than the alternatives

1:55 rritoch: Ring doesn't provide any configuration setting to bypass that step

1:56 Yeah, I could create my own "version" of ring which doesn't conflict but that basically eliminates any benefits to using ring in the first place, since I'd have to maintain a custom version

1:57 justin_smith: rritoch: it's open source, clone it, offer a patch

1:58 that process is so much easier than any other alternative I have seen so far

1:58 rritoch: justin_smith: That isn't a bad idea, but it isn't a priority. Optimization is the current priority but before going onto the next phase I really need to revisit the ring issues

1:59 Leaving code in the application that never gets used, while it happens more than anyone likes to admit, I'd prefer not doing it.

1:59 justin_smith: but this is the easy way to get things optimized. eval is very expeinsive, you want a long running process serving requests without runtime compilation

2:00 rritoch: Well, this script issue isn't the worse problem I face

2:00 I believe you helped me the other day with this fallback URL compiler

2:00 But technically the only reason that is required is the classloader isn't looking in the right places to find the pre-compiled classes on the remote server

2:02 justin_smith: rritoch: do the names of the namespaces reflect the location of the files relative to the effective classpath?

2:02 rritoch: This fallback compilation hack to compile the remote sources locally is functional, but I don't want to rely on it as the primary means of utilizing remote code bases.

2:02 justin_smith: compiling before deploying is not a hack

2:02 it is the right way to do it

2:02 compiling at runtime is the hack

2:03 rritoch: I agree, and that is what I have in place right now, a runtime compiler hack

2:03 But there are actually some benefits to that since it could respond to code changes in real time without a need to restart the server or servlet container.

2:04 arrdem: Clojure will do that out of the box with a simple defn, no "compile hacks" required.

2:04 rritoch: Regardless of the possible benefits, it is currently on my list of optimization issues to deal with

2:04 arrdem: The entire def infrastructure is designed to support dynamic code reloading both in development and production without having to defensively eval or load everything all the time.

2:05 rritoch: arrdem: Compile hacks are absolutely required for this case as source code can exist in the local app, in maven loaded jars, in OSGI bundles, or from remote URL's

2:06 This is an issue that was solved yesterday since load-reader doesn't generate __init.class when *compile-files* is enabled.

2:06 justin_smith: rritoch: and we have a classpath, so that the function (require) can abstract over all of those, as long as you set the classpath properly

2:07 rritoch: Since the compile function only accepts a local source, the only way around it was to generate a reader from the URL and call the Compiler/compile function directly, manufacturing an appropriate script path to ensure that the __init.class is properly generated.

2:07 justin_smith: rritoch: every method of loading code compiles it

2:07 rritoch: Justin, these are web applications running from tomcat, adjusting the classpath used by tomcat isn't how I plan on spending the next 3 years of my life

2:08 justin_smith: do you explicitly need to create the .class file?

2:08 rritoch: Tomcat doesn't simply classpath manipulation in any way

2:09 Regardless, what I've done so far is really the only solution until I can get the deployment to properly switch classloaders when controller (MVC) functions get called.

2:10 justin_smith: I'm referring to attaining classes (gen-class) from a source file located on a remote server

2:11 As I said, load-reader doesn't generate the __init.class, which is why the hack is required,

2:11 load-reader does a lot of compilation, but the generated class files are unusable since it doesn't include the __init.class

2:12 justin_smith: rritoch: it's late here, and I need to move on to other things. Good luck. I think there are likely much simpler ways to meet your root requirements than the elaborate things you are describing, but I can't go into it right now, sorry.

2:12 rritoch: This may be a bug or a feature of clojure, I'm not really sure, but the way around it was to call Compiler/compile directly

2:13 justin_smith: That is not a problem, this hack solution works, and I neeed to deal with the class loader issue anyhow.

2:14 I also need/want to implement this function/file solution so the scripts run faster by being AOT compiled

2:15 arrdem: rritoch: ... having spent the past summer working on the Clojure compiler implementation, I assure you that you are bludgeoning the Clojure runtime into supporting a sequentially executed imperative style based on code loading for the language is not designed.

2:15 rritoch: AOT is not your problem. Your problem is that you are misapplying the language as if it were PHP or Perl when it is not designed to be used as such.

2:16 rritoch: arrdem: That id debatable, since it is exactly how most versions of LISP function

2:16 err, is debatable

2:17 arrdem: rritoch: Clojure is hardly a "typical" lisp in a number of ways especially with regards to the total lack of an interpreter let alone the datastructure and software engineering philosophies involved.

2:18 rritoch: arrdem: You can't have your cake and eat it too, your explicitly contridicting the reasoning behind not allowing cyclical dependencies

2:19 Either clojure is meant to support Streaming source code, or it isn't

2:19 arrdem: rritoch: cyclical dependencies on what... namespaces? vars? classes?

2:20 ddellacosta: I guess it's not possible to do destructuring w/Schema in schema.core/defn, huh

2:20 rritoch: It may take me some time to find the article, but as I said, what your stating is directly contridicting the statements from clojure's developers as to why they won't support cyclical dependencies

2:21 It is right here: https://news.ycombinator.com/item?id=2467809

2:22 By Rich Hickey who supposedly has a big role to play with Clojure

2:22 arrdem: how does that have anything to do with the conversation at hand

2:22 by the way we do support circular dependencies on symbols via declare

2:22 with some restrictions

2:23 rritoch: You stated I was misapplying the language, but I'm actually directly applying the language per the reasoning by Rich as to why cyclical dependencies aren't being allowed

2:24 I may not know all of the clojure politics, but I suspect Rich is higher up in the food chain than anyone in this chatroom.

2:24 Raynes: ☜(⌒▽⌒)☞

2:24 rritoch: So, either Clojure is meant to be scriptable/streamable, or it isn't

2:24 arrdem: Raynes: lols

2:24 rritoch: I'm working under the assumption that it is

2:26 Since load-reader doesn't create the required __init.class files when *compile-files* is enabled the only way to compile a class from a stream is to pass it to Compiler/compile directly, as I have done.

2:27 sveri: Hi, I have a list of keywords and a map. For each keyword I want to update the map with a given function, how would I do that? I know that I can reduce over the list, but I don't know how to keep a copy of the new map the same time.

2:27 rritoch: If clojure is planning on moving away from streamability, than remove this cyclical dependency issue because it causes more problems than it solves.

2:30 amalloy: sveri: reduce keeps an accumulator; that's the whole point. here, your accumulator is the new map

2:30 rritoch: Better yet, just repair load-reader (Compiler/load) so that it generates the __init.class files when *compile-files* is enabled.

2:30 amalloy: (reduce (fn [m k] (change m somehow with k)) original-map list-of-keywords)

2:30 dbasch: ,(reduce (fn [x y] (assoc x y (rand-int 10))) {} [:a :b :c :d])

2:30 clojurebot: {:d 6, :c 5, :b 7, :a 0}

2:30 dbasch: ^ sveri

2:31 sveri: amalloy: dbasch thank you, obv. that's the whole point. My head still does not want to think about it that way, but it's clear if someone states the obvious, jeez

2:32 justin_smith: rritoch: to step back in for a moment: clojure supports runtime update, and aims to minimize the difference between entering code sequentially in a repl vs. loading from a required file. This is on order to streamtime development, but has nothing to do with hotswapping code in production. Also, this does not mean that streaming code and using eval on arbitrary sources at runtime is a) efficient b) simple or c) a sane way to get any r

2:32 work done. I'm not suggesting this is wrong because clojure doesn't or isn't meant to support scripting, but saying that the kind of complexity and brittle behavior you are seeing is symptomatic of using clojure in unusual ways.

2:34 if I dealt with the kind of complexity and frustration in my clojure development that you are describing, I would have ditched it long ago.

2:34 rritoch: justing_smith: I've walked away from this project a few dozen times for the exact reasons your stating

2:35 justing_smith: But the goal of this is to reduce the complexity, and learning curve, for developers using this web platform

2:35 If I do the hard work, they don't have to

2:35 For that matter, it also means that I don't ever need to deal with these problems again, once they're solved

2:36 justin_smith: my fear is that the design is importing external complexities that don't need to exist, and introducing an extra layer of complexity by trying to make clojure something it simply is not

2:38 rritoch: Flexibility is exactly why I'm utilizing clojure instead of Pike, clojure has far fewer limitations

2:38 In this particular case a real clojure developer can define their functions and have a (script) macro which calls their functions, escaping the scripting structure

2:39 But for programmers familiar with scripting languages, this hybrid functionality makes the transition easier on them

2:40 arrdem: At the expense of atrocious performance and shielding them from a language designed to support real software architecture rather than load order based imperative programming

2:41 rritoch: arrdem: That is why I'm now dealing with the performance issue, and I believe justins solution of wraping the file as a function will solve that problem

2:42 arrdem: I've never tried it before, and I'm not entirely sure if (ns .... (:import) is going to function properly within a function, but these are issues I'll learn when I try

2:44 Regardless, this platform has a long way to go, after the optimization step, I need to revisit the ring issue, and after that I need to establish a modern GUI. I'm considering using libGDX instead of JavaFX, but integrating that into a framework which is already complex is probably going to take years.

2:46 So far all I've solved is creating a MVC framwork that is script driven, which can utilize maven resources, OSGi bundles, and remote codebases (Such as how many .js files are delivered client-side).

2:46 I'm currently optimizing what I have so far because repairing these things after adding new layers of complexity will be a nightmare

2:47 amalloy: rritoch: importing inside of a function doesn't do anything. import doesn't load any classes, just gives the current file a shorthand to refer to them

2:48 rritoch: amalloy: :( that is truly sad then, because these scripts need a way of defining Imports to the scripts can be clean

2:49 justin_smith: rritoch: but that isn't what :import does

2:50 rritoch: justin_smith: I believe I know what import does, it likely generates bitecode so the class file contains the imports at a binary level, and it also cleans up the code because you don't have to namespace qualify all of your classes

2:50 justin_smith: rritoch: nope

2:51 rritoch: justin_smith: Ok?

2:51 justin_smith: it's a convenience so you don't have to type out the full package name

2:51 arrdem: rritoch: there is no JVM bytecode "import" operation.

2:52 rritoch: loading a class loads all of its transitive dependencies recursively. As justin_smith says, import just makes class names nicer to type.

2:52 rritoch: arrdem: If I recall correctly, the class file format includes a section for imports, but I could be wrong, it has been over 10 years since I dealt with class files at a binary level

2:52 justin_smith: rritoch: http://stackoverflow.com/questions/9680295/import-statement-byte-code-significance

2:53 rritoch: Well, I just rechecked the class file structure, and your right, there is no section for imports

2:53 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html

2:54 It's been well over 10 years since I dealt with class files at a binary level

2:54 arrdem: Right. Classes make fully qualified references to their depended classes, and unresolved dependencies forces classloading.

2:54 rritoch: arrdem: Ok, well using load-reader is allowing me to utilize imports

2:55 arrdem: what does "utilize imports" mean. We just went over the fact that (import) is simply syntactic sugar.

2:57 rritoch: arrdem: Are you trying to be helpful or are you just trolling?

2:57 dysfun_: is there a clojure library for handling renaming files with a known name into the format file.n.ext where n is an increasing number?

2:58 rritoch: dysfun_: http://clojuredocs.org/clojure.core/format ?

2:58 dysfun_: hrm, i suppose that works

2:59 rritoch: dysfun_: If you want it more automatic you may be able to find a way of wrapping format to make it automatic

2:59 dysfun_: that's overkill. it just seems like a common piece of code. i wondered if anyone knew a library that included it

3:00 it's not terribly difficult to write

3:45 rolfb: urh

3:45 oh nice, completely botched the window there

3:45 sorry all

4:43 tincho1: Hi, I'm having an issue with loading the optimus library as it uses core.memoize which relies on core.cache and that has some issue with it in core.cache/through.

4:44 I've found similar issues online but their solutions don't seem to work for me. I've tried tracking through the dependencies and :excluding core.cache when I can. But no luck.

4:45 If anyone has some advice it would be greatly appreciated

4:56 rurumate: Why does tools.analyzer depend on datomic-free?

4:57 It's surprising to find a part of the compiler need some sort of database

4:57 see https://github.com/clojure/tools.analyzer/blob/master/project.clj

4:58 AeroNotix: Bronsa^?

5:07 borkdude: rurumate https://github.com/clojure/tools.analyzer/search?utf8=✓&q=datomic

5:08 rurumate it has scope provided

5:12 rurumate: borkdude: yes but still lein pulls all the datomic deps when doing a lein install in tools analyzer. Also, there is no mention of datomic on README.md

5:13 borkdude: rurumate that is normal with scope provided. it won't be packaged with your uberjar

5:14 rurumate: if it's not packaged with the uberjar, apps may break at runtime. The circumstances for that are not mentioned in the README

5:16 maybe it makes more sense to put the datomic stuff in a separate project that depends on t.a. ?

5:18 cfleming: rurumate: Bronsa is a bit too clever for that I think. I haven't looked in detail, but I believe the datomic stuff is experimental, and it looks like it's conditionally compiled out if not present: https://github.com/clojure/tools.analyzer/blob/5a58c3ffd87da05e50924d2931b833544717ee55/src/test/clojure/clojure/tools/analyzer/query_test.clj#L11

5:18 rurumate: Is this actually causing you some problem?

5:20 rurumate: cfleming: yes, it bothers me

5:22 cfleming: rurumate: That sounds like a fairly mild sort of a problem :-)

5:23 rurumate: also it clogs my hard drive

5:28 dysfun_: gah, i keep getting "Variable binding depth exceeds max-specdl-size just trying to do (ns foo) and evaluating it under cider-ritz (via nrepl). any ideas?

5:29 or at the very least what that error even means to give me an idea where to look?

5:30 oh, seems to be on the emacs side

5:30 is there a channel for clojure-related emacs stuff?

5:34 phillord: so this error is normally caused by an illfounded recursion

5:34 although it can happen as a result of just deep recursion

5:34 One solution is to do (setq max-specpdl-size 4000)

5:35 which will increase the max allowable level, but if it still happens, then there is a bug somewhere. For which you need to turn debugging on, and get a stack trace

5:35 dysfun: oh, i think it might be something to do with the 5 nrepl connections i just closed

5:35 but then i was creating them because i was getting that, and sometimes it would just go away after a while

5:37 phillord: if it occurs randomly and not predicably, then it's quick likely just that you are hitting a deep recursion

5:37 so increasing the max size will work

5:37 dysfun: i've set it to 10 for now, and it's gone away. i suppose i'll have to either find the bug and fix it or just restart emacs periodically

5:37 phillord: if not, again, you need to get a stack trace

5:38 You have max-specpdl-size at 10?

5:38 dysfun: yes

5:38 phillord: well, the default on my OS is 1300

5:38 dysfun: that's bizarre then

5:38 cause it's working fine now

5:38 phillord: what OS?

5:38 dysfun: osx

5:38 plain gnu emacs

5:39 phillord: launch with "emacs -Q"

5:39 and then tell me the value?

5:40 dysfun: will do, once I've reproduced it

5:40 (if i reproduce it)

5:40 phillord: you don't need to reproduce anything -- just see whether max-specpdl-value is the same with -Q --

5:40 dysfun: oh right

5:40 rurumate: Is it possible to require more than one library at once, in the repl? Like the :require clause in the ns macro

5:41 dysfun: 1300

5:41 rurumate: you can use ns if you want

5:41 phillord: this variable controls how many times you can recurse -- because it controls how many times a variable binding can be pushed onto the stack

5:41 Emacs cannot know whether something is going to terminate, so it just sets this value

5:41 rurumate: oh sure, why didn't I do that before

5:42 dysfun: *nod*, most interpreted languages do that

5:42 so why didn't everything break completely when i set it to 10?

5:42 phillord: if you have rest it to 5 from the default 1300, then are you going to crashes in perfectly normal code

5:42 * phillord shrugs

5:42 phillord: I don't know

5:42 dysfun: software :)

5:42 phillord: where did it get set to 10?

5:42 dysfun: m-x set-variable

5:43 phillord: you set it to 10?

5:43 dysfun: yup

5:43 phillord: why?

5:43 clojurebot: why is startup slow is busy compiling the `for` macroexpansion

5:43 phillord: set it back to 13000

5:43 dysfun: first stackoverflow i answered

5:43 phillord: sorry 1300

5:43 dysfun: er saw

5:43 well i killed it now

5:43 so it's back to 1300

5:44 phillord: This value used to be smaller in the past -- it protects emacs from o-o-memory crashes

5:44 dysfun: i have 8 gigs on this machine. i'm not concerned about that :)

5:44 phillord: no

5:44 that's why it's got much bigger than it used to be

5:44 dysfun: i know it was written for a different day...

5:45 then again, the default configs for postgres and mysql are very conservative

5:45 the postgres one in particular is for a Sun IV

5:46 phillord: well, emacs is like Shakespeare -- not of a time, but for all time

5:47 cfleming: It's also like Shakespeare in that no-one really understands it :-)

5:48 dysfun: heh. i'm kind of hoping DEUCE will get somewhere, but i'm not interested enough to actually develop it

5:59 SagiCZ1: how does (swap! foo atom) work with the foo function? when i redefine foo while the application is running, the new behavior isnt reflected.

6:02 i mean the live re-compilation is advertised as a feature of clojure but it seems to me that you have to design carefuly so that you can use it and if you do would that produce idiomatic code?

6:12 dysfun: the code that uses it also has to be recompiled

6:13 it gets bound to a compiled function

8:02 mearnsh: dysfun: #clojure-emacs exists

8:14 dysfun: mearnsh: yeah, i discovered :)

8:16 mearnsh: ah yes

8:58 justin_smith: dysfun: you may want to mention on #clojure-emacs that you are using cider-ritz

8:59 dysfun: the issue has gone away

9:44 SagiCZ1: ~lazy-logs

9:44 clojurebot: lazy-logs is http://logs.lazybot.org/

9:45 justin_smith: SagiCZ1: the syntax is (swap! atom foo)

9:46 SagiCZ1: if you need t see a new definition of foo, you need to recompile the function that calls (swap! atom foo) OR you need to call (swap! atom #'foo)

9:46 that is guaranteed to always look up the definition (can be a bad idea because of the var lookup overhead)

10:02 SagiCZ1: thank you justin_smith

10:03 justin_smith: np

10:03 SagiCZ1: is that true for other calls as well? (foo (foo2 coll))

10:04 justin_smith: yes, if you need to see changes without redefining, then you can change it to (#'foo (#'foo2 @#'coll)) ; assuming all 3 were global defs

10:05 in practice you should only need explicit var lookup like the above in stateful functions that have internal mutation (like a server process, or if they wrap some long running stateful java thing)

10:06 with pure functions, just re-evaluate the definition to capture the new definitions for things it uses

10:06 SagiCZ1: my case is a long running doseq

10:06 which is consuming a lazy-seq stream

10:06 if i want to recompile it, i would have to stop the consuming and start over

10:06 justin_smith: yeah, if you need to see new defs while it runs, it makes sense to use var lookup explicitly then

10:07 mdrogalis: That sounds like some funky code.

10:08 SagiCZ1: and now that i mention it, i am not sure i should use lazy-seq to act as a stream... i am streaming some data from the internet and it seems to work fine, but i wonder if there is some better clojure way to do streams.. non mutable..

10:08 mdrogalis: it probably is kinda funky, i would like to improve it

10:08 justin_smith: SagiCZ1: what about using core.async and putting the data elements on a channel?

10:08 mdrogalis: SagiCZ1: Can you use a real queue and reload your code in a normal way?

10:09 justin_smith: then you can redefine the consumer of the channel

10:09 or yeah, a queue

10:09 mdrogalis: Aye, both are good solutions.

10:09 SagiCZ1: what is a normal queue?

10:09 *real

10:09 rurumate: queue = channel in core.async lingo

10:09 justin_smith: SagiCZ1: there are a few options in java.util.concurrent

10:09 mdrogalis: SagiCZ1: Oh, I mean something like HornetQ or ActiveMQ.

10:10 justin_smith: mdrogalis: oh, an inter-process queue?

10:10 mdrogalis: The reason I say that you might want an inter-process queue is that it will buy you the ability to kill off your old jar and reload a new one from scratch. Avoids redefining vars.

10:11 SagiCZ1: mdrogalis: yeah i would probably end up with that later, because i might need some automatic back up in case of connection drop, but for now i would like to be able to use just clojure stuff.. of course writing abstract enough code to be able to swap in activeMQ alter

10:12 mdrogalis: Maybe an interface between your code and a channel would be best. Sounds like you get the idea.

10:12 SagiCZ1: yeah so i will probably use java's blocking queue or something.. or get familiar with clojure.async

10:13 mdrogalis: :)

10:13 SagiCZ1: thank you both for ideas

10:14 mdrogalis: Yep

10:18 mmeix: trying to solve 4clojure #58, need a hint

10:18 see: https://www.refheap.com/92101

10:20 clgv: mmeix: do not construct lists but call functions in the reduce step

10:21 mmeix: hm, tried that ... but obviously the wrong way

10:21 ok ... more thinking - thanks for the hint

10:21 (but it's not way off, right?)

10:23 SagiCZ1: if i want to apply a function to each element of a coll but i only care about the side effects, is there a better way than (dorun (map foo coll)) ?

10:23 puredanger: maybe the new run! in 1.7?

10:24 I guess that does reduce-y things so maybe not

10:24 dorun seems fine

10:27 SagiCZ1: puredanger: alright, just wondering

10:28 zerokarmaleft: SagiCZ1: I prefer doseq

10:29 SagiCZ1: but map can do pmap

10:32 puredanger: if you're heading in that direction it might be more direct to just make your own ExecutorService

10:33 jonathanj: how does one do networking in Clojure?

10:33 i'm hoping for something more high-level than java.net.Socket

10:34 * clgv checks run!

10:35 clgv: ok, `run!` just uses the benefits of reducible collections if possible

10:35 sam_: Hi, When I do (class (clojure.instant/validated [ 1 1 1 1 1 1 1 1 1 1 1 ])) , I get clojure.instant$validated$fn__6196. Could someone explain what this means?

10:36 ToxicFrog: sam_: does clojure.instant/validated return a function?

10:37 Jaood: jonathanj: haven't use it but there's aleph

10:37 ToxicFrog: Because that's the type of an anonymous function.

10:37 stuartsierra: puredanger: What's the first argument to `run!`

10:38 puredanger: based on the source, I'd say it's a 1-arg function to be invoked with an item from coll

10:38 SagiCZ1: (doc run!)

10:38 clojurebot: "([proc coll]); Runs the supplied procedure (via reduce), for purposes of side effects, on successive items in the collection. Returns nil"

10:38 puredanger: ,(source run!)

10:38 clojurebot: Source not found\n

10:38 jonathanj: Jaood: thanks, i actually just stumbled on to aleph and it looks fairly useful at first glance

10:39 puredanger: ,(run! println (range 5))

10:39 clojurebot: 0\n1\n2\n3\n4\n

10:41 stuartsierra: OK, it's just `(reduce #(proc %2) nil coll))`

10:42 Like `(dorun (map …))` but without the intermediate seq.

10:42 sam_: Oh. I was trying to annotate namespaces.

10:42 So, under what type would this come?

10:42 And the [ 1 1 1 1 1 1 1 1 1 1] is a persistent vector, right?

10:44 stuartsierra: sam_: Every Clojure function compiles to its own class with a generated name.

10:45 `clojure.instant$validated$fn__6196` is probably the class of an anonymous fn created in the body of a function named `validated` in the namespace `clojure.instant`

11:38 numberten: is there a function that lazily concats but with a non-deterministic order?

11:41 Bronsa: numberten: no but it's trivial to make one

11:41 numberten: (defn shufcat [& args] (apply concat (shuffle args)))

11:47 mdrogalis: Bronsa: shufcat. I love it.

11:48 numberten: Bronsa: (shuffle args) would realize the lists in args right?

11:49 Bronsa: numberten: no

11:49 numberten: it realizes args, which is not lazy anyway. but the elements in args are still not realized

11:49 ,(defn shufcat [& args] (apply concat (shuffle args)))

11:49 clojurebot: #'sandbox/shufcat

11:50 Bronsa: ,(first (shufcat (map #(do (println %) %) (range 10)) (range 10 20) (range 20 30)))

11:50 clojurebot: 20

11:51 numberten: very cool

11:52 i guess I thought the inner most arguments were evaluated first, so any strict list processing call would realize everything

12:01 sveri: ,(midje)

12:01 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: midje in this context, compiling:(NO_SOURCE_PATH:0:0)>

12:01 sveri: (midje)

12:01 nullptr: ~midje

12:01 clojurebot: #<RuntimeException java.lang.RuntimeException: Invalid token: :>

12:04 EvanR: so is there a way to use reflection intentionally without a reflection warning

12:04 without disabling the warn option for the whole file

12:04 Bronsa: EvanR: probably only by using clojure.lang.Reflect directly

12:05 EvanR: thats what im doing, clojure.lang.Reflector/invokeInstanceMember

12:05 and i get reflection warning, clojure.lang.Reflector/invokeInstanceMember cant be resolved

12:06 Bronsa: EvanR: you have a reflection warning on your usage of c.l.R/invokeInstanceMember then, not on the method you're trying to invoke

12:06 EvanR: confused

12:06 Bronsa: EvanR: I see the 3-arity takes either an array or an Object

12:06 EvanR: i have an object

12:08 putting ^Object does not help

12:09 sam_: Hi!

12:09 Bronsa: EvanR: hint the first arg as ^String

12:09 EvanR: oh

12:09 sam_: Are functions/namespaces to work with data structures?

12:10 EvanR: the second arg to invokeInstanceMember? it didnt work

12:10 Bronsa: EvanR: I really can't figure out why the compiler thinks there's an ambiguity there, might be a reflector bug

12:10 EvanR: http://sprunge.us/XeeE

12:11 EvanR: the first arg

12:11 why string?

12:12 Bronsa: because that's its signature, the defined arities are (Object,String), (String, Object, Object[]) and (String, Object, Object)

12:12 EvanR: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Reflector.java (String, Object, Object[]) ?

12:13 oh wrong method

12:13 dbasch: it could match this method too perhaps: public static Object invokeInstanceMember(String name, Object target, Object... args)

12:14 EvanR: i had the arguments reversed

12:14 Bronsa: dbasch: no, in my repl (clojure.lang.Reflector/invokeInstanceMember ^String a b c) doesn't cause a reflection warning while (clojure.lang.Reflector/invokeInstanceMember a b c) does

12:14 dbasch: that’s not object[], it’s variadic

12:15 Bronsa: dbasch: what? Object.. x compiles to Object[]

12:16 EvanR: currently i have this

12:16 (clojure.lang.Reflector/invokeInstanceMember (str "get" (name k)) t (int i))

12:16 dbasch: Bronsa: what I mean is that when calling the method you don’t call it with an array

12:17 EvanR: (int i) doesnt look right

12:17 Bronsa: dbasch: from clojure you do

12:19 dbasch: Bronsa: but how would the compiler know whether c is Object or Object[] ?

12:19 noncom: can anyone explain, why is it a "while" cycle here instead of a simple "if" that would suffice in my opinion? https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Namespace.java#L58

12:20 EvanR: (clojure.lang.Reflector/invokeInstanceMember ^String (str "get" (name k)) t (int i)) is still giving me a warning

12:21 but

12:21 Bronsa: EvanR: it's the int the issue there, you need to remove it

12:21 EvanR: (clojure.lang.Reflector/invokeInstanceMember ^String (str "get" (name k)) ^Object t ^Object (int i)) worked

12:21 remove it?

12:21 Bronsa: dbasch: the java or clojure compiler?

12:21 dbasch: Bronsa: clojure

12:21 Bronsa: EvanR: either remove the (int ) call or box it

12:22 EvanR: box it?

12:22 Bronsa: dbasch: it might just default to Object

12:22 EvanR: why do you need that (int) call?

12:22 dbasch: Bronsa: but I can see how both methods could be considered

12:23 Bronsa: dbasch: there are some cases where the compiler just picks one of possible methods, I think this is one of those

12:23 EvanR: Bronsa: it appears to be used as the argument to the dynamically named method?

12:23 Bronsa: dbasch: it probably picks the Object[] arity only if you tag the arg as ^objects

12:23 myguidingstar: hi all, is it possible to run a lein task from existing nrepl?

12:25 joegallo: it's all just clojure code, so it is *possible*

12:25 technomancy: myguidingstar: if you set :eval-in :nrepl, Leiningen will try to connect to an existing nrepl server instead of starting a new jvm

12:25 (it will fall back to starting a new JVM if it can't though)

12:26 Bronsa: EvanR: look, (int x) in that case returns a primimtive int. the invokeInstanceMember method takes an Object. if you pass a primitive to it the compiler will not know how to invoke it, just remove the (int) call

12:26 technomancy: and you can't initiate it from within the repl (unless you bring in leiningen as a dep)

12:28 myguidingstar: (inc technomancy)

12:28 lazybot: ⇒ 150

12:29 Bronsa: noncom: the compareAndSet might fail

12:32 noncom: Bronsa: ah, i see.. :)

12:39 numberten: i'm looking at the implemention of interleave and it appears to make recursive calls without the use of recur

12:39 does that mean it uses O(n) stack space?

12:40 it's lazy so I assume it would still be O(1) as long as you don't hold the head?

12:40 sam_: Are there functions/namespaces to work with data structures?

12:50 clgv: numberten: it uses the macro 'lazy-seq` so it does not use any recursiv calls

12:50 Bronsa: sam_: what do you mean?

12:51 sam_: I mean are there any functions to implement various data structures?

12:51 Like tree, heap etc

12:52 Bronsa: sam_: that's such a vague question, it depends on how you want to implement them

12:52 sam_: Actually.

12:53 Tree etc can be a namespace and there can be various functions

12:53 For inserting, deleting etc

12:54 clgv: sam_: there is no clojure.tree namespacen in the clojure jar - if that answers your question ;)

12:55 sam_: It does answer the question, thank you!

12:55 clgv:

12:56 Wouldn't it be a good idea to add those?

12:57 Bronsa: sam_: clojure already ships with a number of persistent data structures that are used extensively, and a big amount of functions to manipulate them

12:59 hiredman: a reasonable argument could be made that clojure is entirely a dsl for manupilating those data structures

13:00 clgv: sam_: I guess you'll only get such namespaces included if they add important missing features. so what exactly is missing for you?

13:01 sam_: That's true , but I feel having these basic data structures would be helpful, Bronsa.

13:02 benmoss: does anyone know in vim-fireplace if there’s a way to reset the REPL once you’ve accidentally caused an infinite loop?

13:02 noonian: its pretty easy to construct trees out of clojure's core datastructures if that is how you need to model your data

13:02 clgv: sam_: you build trees with vectors and maps in various ways

13:03 benmoss: i can <ctrl>-c the command, but subsequent commands never return either after that happens

13:03 clgv: +can

13:03 jro_: sam_: https://clojure.github.io/clojure/clojure.walk-api.html operates on tree-like clojure forms

13:04 sam_: To be completely honest, I dont really find anything missing, clgv. But as I have used C, C++ extensively. I feel implementing these would make it closer to other programming languages. I'm sorry if what I say seem like non-sense to you. I'm a newbie here.

13:04 EvanR: benmoss: im using fireplace, im interested in how you caused an infinite loop

13:04 mgaare: sam_: can you give an example or two of what kind of tree manipulation functions you would think to add?

13:04 clgv: sam_: oh when you are learning Clojure, you should avoid to make it closer to C/C++ ... just try to learn something entirely new

13:05 benmoss: EvanR: as in evaling `(range)`

13:05 EvanR: :S

13:05 technomancy: seems to me that trees aren't as much a data structure as a way of using data structures, just like stacks are just a way of using lists

13:06 benmoss: not actually doing something *quite* as dumb as that, but a function that recurs infinitely

13:06 EvanR: ah

13:06 clgv: technomancy: yeah, our third semester students usually struggle with trees represented in arrays ;)

13:06 sam_: I meant the basic functions like insertion, deletion and the BST stuff.

13:06 That's it.

13:06 benmoss: vim hangs waiting for a response which will never come, I <ctrl>-c it, but i get the sense I need to reconnect to nrepl or something

13:07 technomancy: sam_: have you used update-in?

13:07 EvanR: benmoss: when you close and reopen vim does it work

13:07 technomancy: deletion is just update-in + dissoc

13:07 benmoss: EvanR: yeah, my two options are restart vim or restart the repl

13:07 EvanR: benmoss: does :Connect work

13:07 mearnsh: sam_: see joy of clojure section 6.2

13:07 EvanR: ah no, you said it hangs

13:08 benmoss: EvanR: oh yeah i forgot that is a third option, but it prompts me to enter a host and port and everything, its kinda annoying

13:08 EvanR: even if you have .nrepl-port ?

13:08 benmoss: EvanR: yeah

13:09 EvanR: another good reason to show that your code will not infinite loop before running it

13:09 jonasen: bbloom: Interesting post on Om! Thanks

13:09 benmoss: EvanR: so just solve the halting problem first?

13:10 EvanR: of course its a case by case argument ;)

13:10 bbloom: jonasen: glad you enjoyed it!

13:10 benmoss: :)

13:10 sam_: I personally feel having a separate namespace along with the functions would make it simpler and hence user friendly.

13:10 Just expressing *MY* opinion!

13:10 EvanR: benmoss: its times like these it would be nice to turn off TCO so that you get an error instead of hanging

13:10 sam_: technomancy, No. I haven't. What does it do?

13:10 jonasen: bbloom: one question: are cursors important in that context, or is all you need the :descriptor support?

13:11 clgv: sam_: how far did you get reading the introducotry clojure material of your choice so far?

13:11 bbloom: jonasen: the technique described in the post is 100% orthogonal to the representation of your app state or references in to that representation

13:11 jonasen: great! that's good to hear

13:11 clgv: sam_: your opinion might change drastically in the learning process...

13:12 jonasen: bbloom: I tend to use om/value a lot and use more of an FLUX architecture instead of cursors/transact!

13:12 bbloom: jonasen: see https://news.ycombinator.com/item?id=8487855

13:13 sam_: I just have a basic idea!

13:13 I was planning to implement these data structures to get a better idea and hence the question came up, clgv.

13:14 EvanR: sam_: have you tried implementing linked lists first

13:14 sam_: No. I haven't.

13:14 EvanR: baby steps

13:15 clgv: sam_: oh, better start trying to implement small tasks for learning. 4clojure.com offers a lot of those

13:15 sam_: Ok.

13:15 :)

13:15 So, you guys are saying that is not neccessary huh?

13:15 There must be some reason!

13:15 jonasen: bbloom: thanks! I'll definitely play with this

13:16 technomancy: sam_: http://clojuredocs.org/clojure.core/update-in

13:17 do we have any bot commands to give clojuredocs links?

13:17 clgv: $docs update-in

13:18 :(

13:18 $clojuredocs update-in

13:18 lazybot: clojure.core/update-in: http://clojuredocs.org/v/5823 clojure.core/update-in: http://clojuredocs.org/v/1692

13:18 mdrogalis: *Claps* :D

13:18 technomancy: huzzah

13:18 clgv: awesome :)

13:18 technomancy: though... why two links?

13:18 mdrogalis: For *twice* the learning

13:18 * technomancy nods sagely

13:18 clgv: lazybot: botsnack

13:18 lazybot: clgv: Thanks! Om nom nom!!

13:21 EvanR: i seem to be able to redirect pprint to a file using *out*

13:21 so i guess (def *out* to something else), but how to do i undo it

13:21 clgv: EvanR: use (binding [*out* ...] (pprint ...))

13:22 EvanR: alternatively i just noticed it takes a writer as a second arg

13:22 clgv: $(source with-out-str)

13:22 $source with-out-str

13:22 lazybot: with-out-str is http://is.gd/tw8lMA

13:23 clgv: EvanR: for an example have a look overthere ^^

13:23 ,(with-out-str (println (vec (range 3))))

13:23 clojurebot: "[0 1 2]\n"

13:24 EvanR: nice...

13:25 does clojure have a macro to put my - key back in place?

13:25 its popping off the keyboard

13:26 noonian: i think theres an emacs command for that: M-x pop-keycap-into-place

13:28 sam_: Sorry. Did you guys say something? WiFi has issues here.

13:29 technomancy: sam_: http://clojuredocs.org/clojure.core/update-in

13:29 travisrodman: noonian: lol

13:29 sam_: I saw that technomancy :)

13:30 For insertion

13:30 oskarkv: Hm, the clojuredocs quickref doesn't have all the functions in it, and it's usually where I go to see if what I need already exists

13:30 Don't you guys think that it should have every function in there?

13:31 technomancy: sam_: for deletion, use update-in with dissoc

13:32 sam_: Yes.

13:32 technomancy: oskarkv: is that the thing designed for being printed out?

13:32 kind of defeats the purpose if it doesn't fit on the page

13:32 oskarkv: technomancy no, this http://clojuredocs.org/quickref

13:32 Is that for printing out? I dunno

13:33 sam_: I guess the usage of BST in cpp created all the problem. The complexity of the problem is reduced to large extent using it in cpp.

13:33 technomancy: oh, I'm thinking of the cheat sheet

13:33 that is pretty extensive

13:33 sam_: I'm sorry if this seems nagging, but could you explain why you feel it is unneccassary?

13:34 oskarkv: The quickref is great when looking for something because the functions are grouped

13:34 technomancy: sam_: what is BST?

13:34 sam_: Binary Search Tree. :)

13:35 technomancy: sam_: and that ... does something that regular clojure maps don't?

13:35 mikerod: Is there not a named var that can be used to find the current line number value from the compiler?

13:35 I see this in the Compiler: `static final public Var LINE = Var.create(0).setDynamic();`

13:35 So there is an unnamed var

13:35 that is public here

13:35 I'd have expected a named var like the *file* var

13:37 llasram: mikerod: what's the context where you're trying to discover this information?

13:38 mikerod: llasram: macroexpansion would be fine

13:38 technomancy: sam_: probably the reason no one has advice for you is that you aren't framing your questions in terms of specific functionality

13:38 mikerod: or a function called by a macro while expanding

13:38 llasram: mikerod: Within a macro, you should be able to check the `:line` metadata of argument forms

13:38 mikerod: if I wanted to ask, "what is the line number that is currently being compiled"

13:38 &form?

13:38 lazybot: java.lang.RuntimeException: Unable to resolve symbol: form? in this context

13:39 mikerod: well, not lazybot, I just meant the special &form binding

13:39 Bronsa: sam_: don't take this the wrong way but from what you've beein saying it looks like you haven't even read about the availbale clojure data structures, it's probably best if you read some introductory material before trying to implement your own data structures

13:40 llasram: mikerod: That'll work, although I believe :line metadata is applied to any list

13:40 sam_: I guess that's the reason Bronsa. Thanks technomancy.

13:41 Bronsa: mikerod: yeah (:line (meta &form)) should work

13:43 sam_: I've heard http://aphyr.com/posts/301-clojure-from-the-ground-up-welcome is good, you might want to check that out and ask here if you have any doubts

13:51 muraiki: sam_: I also recommend http://www.braveclojure.com/ as it has a good explanation as to how the built in structures work and why you're able to use the same functions across them all (section: Core Functions in Depth)

13:52 SagiCZ1: sam_: And I would recommend Programming Clojure if you don't care for lame jokes in brave clojure, also Joy of Clojure which gets recommended very often is too advanced for a beginner.

13:59 mikerod: llasram: Bronsa hmm thanks that probably works then

13:59 I still wish there was just a dynamic var like *file* for *line*

13:59 :D

14:10 muraiki: sagicz1: yeah, sometimes brave clojure gets a bit too wacky. which is a shame because I think it really has excellent pacing and clear descriptions otherwise.

14:11 andyf: oskarkv: The Clojure cheatsheet is also grouped by functionality and may include things the quickref page does not have. See clojure.org/cheatsheet or click the "Download other versions with tool tips" link near top of that page

14:18 roelof: Hello, whar is wrong here : (defn divides? [divisor n] (if (=(mod n divisor)0)))

14:19 swedishfish: roelof: you aren't supplying "if" the right number of args

14:20 roelof: you are only passing in a predicate

14:20 andyf: roelof: If is unnecessary there if you want to return Boolean val

14:20 amalloy: roelof: you just want to remove the if entirely

14:21 roelof: thanks, that did the trick

14:23 another guestion : Can I say to midje that I only wants to test one function instead of the whole namespace ?

14:30 mr-: Hey, what's wrong with (filter #( (= 1 (mod % 2)) ) [1 2 3]) ? It says it can't cast Boolean to IFn.

14:31 amalloy: too many parens

14:31 #((...)) should just be #(...)

14:32 mr-: Oh. Those keep tripping me up :-(

14:32 Thanks

14:33 amalloy: mr-: remember that () is for calling functions, not for grouping

14:34 mr-: amalloy: Yeah, I thought the #( ) was special

14:34 and if they are special, I thought I had to call =

14:35 amalloy: #(x y) is short for (fn [] (x y)). the idea is that you can take an expression that does something (such as (= 1 (mod % 2))), and just putting a # in front of it changes that into a function that, when called, does that thing

14:36 dbasch: one of the first things in any Clojure tutorial for Java/C people should be a section called “parentheses are not curly braces”

14:36 roelof: another guestion : Can I say to midje that I only wants to test one function instead of the whole namespace ?

14:37 mr-: Is the #( ) special syntax the interpreter implements, or is it implemented in clojure?

14:38 amalloy: mr-: there's no such thing as the interpreter. clojure is clojure; it's compiled

14:38 mr-: amalloy: Sorry, I have only been using the repl so far.

14:40 justin_smith: mr-: everything you do in the repl is compiled

14:40 mr-: amalloy: But, for example in Agda, if then else is implemented in Agda's standard library. You could define your own, if you liked.

14:40 justin_smith: mr-: what distinction are you trying to make?

14:40 amalloy: i think he's getting at special forms

14:41 mr-: you could not implement #() yourself: it is a reader macro

14:41 mr-: justin_smith: I am wondering if I could implement my own #( ) in clojure

14:42 amalloy: you could do something very much like it, but you couldn't use quite the same syntax. it'd have to be like (my-lambda (+ 5 %)) instead of #(+ 5 %). it would have to have a name, and look like any other clojure function call

14:45 mr-: Great, thanks

14:46 EvanR: parentheses are not curly braces in C or java either ;)

14:49 dbasch: EvanR: no, but some people who arrive from those languages think { translates to (

14:49 mdrogalis: puredanger: What's the Sonatype repository to grab Clojure 1.7.0-master? Can't seem to find it.

14:49 EvanR: that seems like an odd conclusion

14:50 dbasch: EvanR: it’s pretty common, in particular people who are used to throwing extra curly braces around because why not

14:50 justin_smith: EvanR: dbasch: but you see it all the time, it's not odd at all

14:51 mr-: I don't know why you'd have to jump to curly braces. In most languages even the normal braces are just grouping devices..

14:51 justin_smith: probably the most commonly asked question on clojure SO: clojure said Long cannot be cast to IFn here is my code: (5) what's wrong with it

14:51 EvanR: when would you put {5} ?

14:52 justin_smith: EvanR: I am simplifying slightly

14:52 people do it all the time

14:52 dbasch: EvanR: you’d have something that evaluates to 5

14:52 EvanR: {2 + 3} ?

14:52 mdrogalis: Nevermind puredanger, found it :)

14:52 justin_smith: {return 2+3;}

14:52 mr-: return (2+3); is much more common :-P

14:52 EvanR: o_O

14:52 dbasch: or (nil) when you just wanted to print something out, for example

14:57 justin_smith: EvanR: mr-: a more specific example (if (foo) (5) (6)) where foo is a value not a function

14:57 noonian: ,([1 2 3])

14:57 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentVector>

14:57 noonian: ,(map #([%]) [1 2 3])

14:57 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentVector>

14:58 justin_smith: noonian: yes, slightly more subtle examples

14:59 jro_: ,(map #(-> [%]) [1 2 3])

14:59 clojurebot: ([1] [2] [3])

14:59 amalloy: EvanR: or (defn foo [x] (\n (+ x 1)))

14:59 justin_smith: ,(map #(do [%]) [1 2 3])

14:59 clojurebot: ([1] [2] [3])

14:59 noonian: ,(map #(do [%]) [1 2 3])

14:59 clojurebot: ([1] [2] [3])

14:59 noonian: doh, you beat me to it

15:00 amalloy: where they put the first open paren on its own line to be a comfortable grouping mechanism, then another one to call +

15:00 dysfun: can clojure be written in funky character sets?

15:00 justin_smith: ,(map #(max [%]) [1 2 3]) ; so many ways to do it

15:00 amalloy: dysfun: any character set can be funky if you have enough confidence in your jive

15:00 dysfun: i don't want to, i'm just wondering if assuming utf-8 would be bad

15:00 clojurebot: ([1] [2] [3])

15:00 noonian: justin_smith is good at that iirc

15:01 * justin_smith gets down.

15:01 dysfun: party at justin_smith's!

15:01 amalloy: noonian: is justin_smith the one who pastes 💩 PILE OF POO whenever someone mentions silly characters?

15:01 dbasch: here’s some code by a guy who was having an interesting conversation with arrdem and justin_smith last night https://github.com/rritoch/clj-physics/blob/master/src/Physics/core.clj

15:02 pmonks: dysfun: seems to work ok: (defn 💩 [] (println "💩") )

15:02 noonian: amalloy: yes i think so, and he had one super long crazy character symbol a while back

15:02 justin_smith: amalloy: I have occasionally pasted it, but my goto is ☃

15:02 dysfun: pmonks: and that's invalid utf-8?

15:02 pmonks: No - it’s valid UTF8.

15:02 dysfun: right. my question is whether i can assume clojure is utf-8

15:02 justin_smith: dbasch: omfg

15:02 amalloy: dysfun: i think the clojure reader reads utf-8

15:03 dysfun: good enough for me

15:03 pmonks: Clojure-on-JVM is UTF-16 internally (since that’s what Java is).

15:03 justin_smith: dbasch: I was really trying to help this guy

15:04 amalloy: pmonks: well, but the files it reads are utf-8

15:04 justin_smith: dbasch: it appears he really is just trying to do php or perl in clj

15:04 pmonks: amalloy JVM can read a bunch of encodings, and it’ll convert internally to UTF16

15:04 UTF16 is the canonical JVM representation (for historical reasons).

15:04 amalloy: i know that. it's not relevant to what dysfun is asking

15:05 eg, clojure.lang.Compiler/loadFile reads files as UTF-8

15:05 justin_smith: pmonks: sure, but it reads utf8

15:05 dbasch: perljure

15:05 perljury

15:05 arohner: dbasch: are you familiar with swearjure?

15:05 EvanR: hysterical raisins

15:05 dbasch: arohner: yes :)

15:06 pmonks: amalloy I’d say it’s relevant - doesn’t hurt to know that the JVM itself can read just about anything. The fact the the clojure reader happens to hardcode UTF8 for source is also relevant.

15:06 But whatever...

15:06 We’re splitting hairs. ;-)

15:06 amalloy: pmonks: he's trying to write an alternative clojure reader

15:06 * dysfun was sort of hoping people would forget about that

15:06 pmonks: Right, so if he’s doing that on the JVM, he could pick any of the supported encodings the JVM supports, is my point.

15:07 amalloy: man. i keep trying to get out of the habit of using gendered pronouns on irc, and it's really hard. even with tab-completion for dysfun's actual name, "he" just comes so easily

15:07 pmonks: Thought UTF8 is probably the “best” choice...

15:07 EvanR: please dont encode your files in utf16

15:07 dysfun: well, 'he' would be the least inappropirate pronoun tbh

15:07 * EvanR starts flames

15:08 TEttinger: amalloy: "it"

15:08 dysfun: actually this isn't for the reader anyway, this is because i'm slurping .clj files out of jars to do stuff

15:08 amalloy: dysfun: of course it's accurate most of the time, and technically is the correct pronoun to use in english if you're not sure of gender, but in practice i'd like to avoid being unwelcoming to any women who do arrive here

15:08 dysfun: i get a byte buffer and i have to decode it to a string

15:08 bridgethillyer: amalloy: ^

15:08 justin_smith: use EBDIC

15:09 *EBCDIC sorry

15:09 dysfun: amalloy: *nod* i get it. but in this case, no foul :)

15:09 pmonks: That would be EPcdIC!

15:09 TEttinger: justin_smith: that's a painful acronym

15:09 justin_smith: indeed

15:09 dysfun: justin_smith: you know, in perl, the internal encoding on mainframes is UTF-EBCDIC ?

15:09 pmonks: Having done EBCDIC both pre and post JVM, I can say that the JVM’s encoding support is pretty fantastic. ;)

15:09 justin_smith: oooh! use Baudot code, it's 5 bit!

15:09 pmonks: Though EBCDIC isn’t built in.

15:09 EvanR: use KOI-8

15:10 justin_smith: dysfun: woah

15:10 I bet you could do UTF5 via BGaudot

15:10 *Baudot

15:10 dysfun: and the 'utf8' module magically applies to UTF-EBCDIC on those platforms

15:10 pmonks: I like WTF-8 meself.

15:11 EvanR: libiconv exists

15:11 Bronsa: amalloy: this is something I've always felt uneasy about when speaking in english. In Italian I can just omit the pronoun and it all works just as fine

15:11 arohner: ok, another fun transducers question. I'm trying to write partition-all, which means that at the end, in, the ([result]) step, I need to flush state, and call (f1 result x) one more time. Is f1 assumed to be side-effecting or pure?

15:11 i.e. can I (f1 result x) (f1 result)?

15:12 amalloy: Bronsa: what about words like "him"? in spanish there's "lo" and "la" which i don't think you can usually omit without changing the meaning of the sentence

15:14 aztak: good evening!

15:15 noonian: aztak: good afternoon!

15:15 aztak: no no, that's not right. I'm pretty certain it's dark outside!

15:16 :)

15:16 technomancy: ~ugt

15:16 clojurebot: ugt is Universal Greeting Time: http://www.total-knowledge.com/~ilya/mips/ugt.html

15:17 arohner: technomancy: thank you for being the voice of sanity

15:18 pmonks: Kind of sad that we’ve figured out a non-timezone-specific greeting but not a non-gender-specific one… #justsayin

15:18 noonian: in that case, good morning!

15:18 technomancy: pmonks: dunno what thon is talking about

15:18 aztak: pmonks: +1

15:19 amalloy: (inc technomancy)

15:19 lazybot: ⇒ 151

15:19 * technomancy is partial to "folks" for realsies tho

15:19 EvanR: just use "she" everywhere

15:19 noonian: nice use of thon

15:19 aztak: Good morning everyone! :)

15:19 technomancy: "hello, cats and kittens"

15:19 EvanR: (dec lazybot)

15:19 lazybot: ⇒ 30

15:22 Bronsa: amalloy: yeah there are cases where you can't avoid it, but anyway "gli" in Italian has a much shallower gender implication than "him" in english

15:27 TEttinger: gli's right

15:28 pretty sure "dawg" is gender-neutral

15:28 mgaare: I can just use "y'all" and people will think I'm charming and southern

15:28 EvanR: i just banged on this code for several minutes wondering where this bug was coming from that i thought i fixed, only to realize i didnt do "reload"

15:29 justin_smith: this is a clojure channel, *1 is the only pronoun we need

15:29 TEttinger: heh

15:29 EvanR: *2 is right

15:29 justin_smith: well maybe you'll need *2, *3 etc. sometimes

15:29 TEttinger: *1 is right

15:29 this gets confusing

15:29 justin_smith: but you'll never need *4

15:29 EvanR: *23

15:29 Bronsa: (inc justin_smith)

15:29 lazybot: ⇒ 101

15:30 dsrx: EvanR: sometimes after writing too much cljs code with my editor connected to the browser through a repl I go back to writing JS on a work project and forget I have to reload :)

15:30 EvanR: (or save the file even!)

15:31 EvanR: i closed and reopen the file to make sure i saved

15:31 not the same as reloading

15:31 dbasch: I use cider-restart more than I should

15:33 mr-: How would you make something like that readable? :-) (defn fib [n] (if (= n 1) [1] (if (= n 2) [1 1] (conj (fib (- n 1))(+ (nth (fib (- n 1)) (- n 2)) (nth (fib (- n 1)) (- n 3)))))))

15:34 dbasch: mr-: for one, paste it on refheap with proper formatting :)

15:34 amalloy: mr-: i mean, the simplest change is to not repeat (fib (- n 1)) three different times

15:36 dbasch: nested ifs also don’t help readability

15:37 mr-: Would that count as properly formatted? https://www.refheap.com/92111

15:38 schmir: mr-: no, put closing braces on the same line

15:38 justin_smith: mr-: you should use let

15:38 ,(doc let)

15:38 clojurebot: "([bindings & body]); binding => binding-form init-expr Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein."

15:39 justin_smith: ,(let [a 1 b (inc a)] (+ a a b b b))

15:39 clojurebot: 8

15:39 mr-: justin_smith: cool, thanks.

15:39 schmir: will do

15:39 schmir: mr-: use cond instead of nesting ifs

15:39 technomancy: *5 is right out

15:39 justin_smith: (inc technomancy)

15:39 lazybot: ⇒ 152

15:41 aztak: if I use :keys in a map binding like: (defn xxx [{:keys [foo bar]} :body}] (...)) -- is there a way to rename the binding to something else for 'foo' and 'bar' in the map?

15:42 justin_smith: aztak: just use normal map destructuring

15:42 ,((fn [{the-a :a the-b :b}] (+ a b)) {:a 1 :b 2})

15:42 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(NO_SOURCE_PATH:0:0)>

15:42 justin_smith: err

15:42 aztak: ok - so :keys can only be used to bind to the "real" names?

15:42 justin_smith: ,((fn [{the-a :a the-b :b}] (+ the-a the-b)) {:a 1 :b 2})

15:42 clojurebot: 3

15:43 justin_smith: right, keys is just a sugar for when you want the same name as in the map

15:43 aztak: aight - thanks :)

15:44 dbasch: mr-: this is more readable to me https://www.refheap.com/92112

15:48 mr-: Any more suggestions to https://www.refheap.com/92114 ?

15:48 it's got let and cond now

15:48 dbasch: ah, having all the braces close like that is Ok?

15:49 justin_smith: mr-: it's the only right way™

15:49 mr-: I see

15:50 EvanR: i tried to write a trace function. (defn trace [msg x] (println msg) (pprint x) x) and it seems to work except that its not printing anything out

15:50 justin_smith: mr-: you may find it useful to look at some of the code you use (though clojure.core itself can often be funky), there is clojure.repl/source which will show you the source for most functions

15:51 SagiCZ1: mr-: put the cond on a new line and all ending braces together after (- n 3) )))))

15:51 TEttinger: ,(defn trace [msg x] (println msg) (pprint x) x)

15:51 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: pprint in this context, compiling:(NO_SOURCE_PATH:0:0)>

15:51 TEttinger: ,(defn trace [msg x] (println msg) (clojure.pprint/pprint x) x)

15:51 clojurebot: #<CompilerException java.lang.ClassNotFoundException: clojure.pprint, compiling:(NO_SOURCE_PATH:0:0)>

15:51 mr-: SagiCZ1: Ok

15:51 justin_smith: EvanR: two likely causes: it's happening in a thread where *out* is bound differently, or you are calling it inside a lazy squence construction and the seq is not realized

15:51 mr-: justin_smith: great, that's exactly what I was looking for :-)

15:52 justin_smith: also there is bbatsov's clojure style guide - not 100% uncontroversial, but it's pretty good

15:52 EvanR: justin_smith: its happening inside of with-out-str

15:53 justin_smith: EvanR: so the code that runs it is fully realized, and its output is not in the string?

15:53 EvanR: its not in the string

15:53 checking again again

15:54 justin_smith: EvanR: is it being called inside for, map, filter...

15:55 EvanR: theres a map there

15:55 justin_smith: EvanR: do you consume the contents of map before leaving the with-out-str scope?

15:56 ,(do (map #(println "hello" %) (range 10000)) nil)

15:56 clojurebot: nil

15:57 EvanR: well, the final results are printed out before leaving with-out-str

15:57 that is still working

15:57 going to try to print anything out at all on the inside

15:57 justin_smith: EvanR: the contents of the mapping?

15:57 EvanR: uhm the value of the result of mapping

15:57 im not clear on what contents of the mapping means

15:58 justin_smith: EvanR: can you make a paste of it on maybe refheap.com?

16:00 EvanR: does println and print obey *out* too

16:00 justin_smith: yes

16:00 EvanR: justin_smith: unfortunately for this current code blob its all mixed up with proprietary bullshit

16:00 justin_smith: OK

16:01 technomancy: does cider have a command to remove-ns before reloading?

16:01 I can't find it in the readme; seems like a strange omission

16:02 EvanR: justin_smith: i think the code im trying to trace is just never called, no laziness involved

16:02 justin_smith: oh, that would do it too :)

16:02 EvanR: having a hard time travesing this giant map of maps of maps

16:02 justin_smith: laziness is an often source of that

16:03 EvanR: if you are nesting calls to map inside other calls to map, you should use for

16:03 EvanR: this is map nested inside update-ins

16:03 nested inside update-ins

16:03 justin_smith: sounds like a design problem

16:04 EvanR: i too new to clojure to know the difference ;)

16:04 jakebasile: Hi all. Has anyone ever run into a situation where `lein ring uberwar` just sits there? I had this working earlier today, but I can't figure out what happened to cause this, or how to debug this.

16:04 EvanR: design problem or design pattern, eye of the beholder

16:05 mbriggs: hey guys, i have an agent question. Is there any guarentee to the ordering that the "send" functions are applied to the value? So if i send 3 times, will those three functions execute in chronological order?

16:06 EvanR: we have trace \o/

16:07 justin_smith: jakebasile: jstack can tell you what a jvm is currently doing

16:08 jakebasile: the output may or may not help

16:08 (it comes with every jdk)

16:08 jakebasile: thanks, i'll look at that. I've even tried reverting my changes from today - no dice. It just hangs

16:10 mbriggs: never mind, figured it out in the repl, the answer is yes, they execute in order

16:11 justin_smith: mbriggs: I don't think there is any guarantee (the sends can come from different threads, weirdness can happen), but that is the likely result, sure

16:11 mbriggs: good point, in my test all 3 sends came from the same thread

16:11 jro_: are there attempts going on to speed up clojure initial loading time?

16:12 EvanR: to write a constant function, what is it, #(4) ?

16:12 ,(#(4) 5)

16:12 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox/eval25/fn--26>

16:13 Bronsa: EvanR: (constantly 1)

16:13 justin_smith: '#(4) ; EvanR

16:13 ,'#(4) ; EvanR

16:13 clojurebot: (fn* [] (4))

16:13 EvanR: ,((constantly 3) 5)

16:13 clojurebot: 3

16:13 EvanR: ,('#(4) 5)

16:13 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.IFn>

16:13 justin_smith: EvanR: see the expansion from my code above

16:13 that's why that happens

16:14 EvanR: ,('#(4))

16:14 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.IFn>

16:14 EvanR: fn star

16:14 ok i have no idea

16:14 justin_smith: (fn* [] (4)) - what do you think that would do?

16:14 jro_: ,(source constantly)

16:14 clojurebot: Source not found\n

16:15 justin_smith: $source constantly

16:15 lazybot: constantly is http://is.gd/5gCQ2V

16:15 Bronsa: EvanR: fn* is just a lower-level fn, you can ignore the difference for now

16:15 justin_smith: EvanR: fn* is just fn without some cool features like destructuring

16:15 EvanR: oh # is for partial

16:15 justin_smith: EvanR: no

16:15 # is for reader macros, the #() reader macro is for making anonymous functions

16:16 EvanR: yurg

16:16 justin_smith: #(x) expands to an anonymous function that takes 0 arguments and calls x

16:16 jro_: # does not support making vararg funs=

16:16 justin_smith: ,'#(x)

16:16 clojurebot: (fn* [] (x))

16:16 llasram: jro_: That is not true

16:16 justin_smith: ,(#(do %& 5) 1 2 3) ; jro_ nope

16:16 clojurebot: 5

16:16 jro_: I triet to type question mark after funs?

16:17 EvanR: im looking for constantly

16:17 justin_smith: jro_: sorry, I can't parse that

16:17 llasram: jro_: Ok. You are forgiven. *This* time

16:17 ;-)

16:17 jro_: :-)

16:17 justin_smith: ahh, now I get it

16:17 yeah %& is for varargs inside #()

16:18 #(do %& 5) is shorter than (constantly 5), but not preferable to it

16:18 jro_: I tend to write explicit (fn:s as lambdas in most use cases

16:19 EvanR: ,((fn [x] 4) 5)

16:19 clojurebot: 4

16:20 jro_: very simple funs, e.g. #(= 5 %) are exception

16:20 justin_smith: (fn [& _] 4) ~= (constantly 4)

16:20 that's also shorter, but constantly is still better

16:22 EvanR: hehe what is ~= supposed to be

16:22 no infix in clojure!

16:22 justin_smith: is approximately equal to

16:22 right, it's not valid code

16:22 EvanR: constantly takes any number of args

16:22 justin_smith: no two functions in clojure are ever equal, but those two have the same behavior

16:22 EvanR: i mean, the result

16:22 justin_smith: EvanR: so does my anonymous function

16:22 it takes 0 or more args

16:22 EvanR: i see that

16:23 exactly one is fine with me

16:27 jro_: what http client library you use in clojure?

16:27 mostly I've used clj-http, but like to find good alternative for async processing

16:27 noonian: clj-http or http-kit's client; they have similar interfaces

16:28 EvanR: i used http-kit

16:28 noonian: http://http-kit.org/client.html

16:31 EvanR: so this "a reader macro" is a thing built into clojure and not programmable?

16:31 #"foo" #(%)

16:31 jro_: built-in

16:31 egghead: EvanR: you can register your own readers to interpret tagged literals EvanR

16:32 justin_smith: EvanR: http://clojure.org/reader there is data_readers.clj

16:32 EvanR: what is a literal in this context

16:32 ill read the reader

16:32 justin_smith: "When Clojure starts, it searches for files named data_readers.clj at the root of the classpath. ..."

16:33 jro_: oh

16:40 EvanR: to prepend a character to a string its just (str "C" foo) ?

16:41 justin_smith: well, that's prepending a one character string, but sure

16:41 ,(str \C "foo")

16:41 clojurebot: "Cfoo"

16:41 justin_smith: that's prepending a character

16:41 EvanR: ,(str 'C' "foo")

16:41 clojurebot: "C'foo"

16:41 EvanR: blur

16:41 justin_smith: that's not acharacter

16:42 EvanR: \C is a java char?

16:42 justin_smith: yes

16:42 ' means quote

16:42 it doesn't get balanced

16:42 ,'C

16:42 clojurebot: C

16:42 justin_smith: ,(type 'C)

16:42 clojurebot: clojure.lang.Symbol

16:43 justin_smith: ,(type \C)

16:43 clojurebot: java.lang.Character

16:43 EvanR: whats the difference between symbol C and keyword :C

16:44 justin_smith: symbols are useful in making macros - they are usually resolved to some var

16:44 noonian: keywords always evaluate to themselves; symbols are used for variable names and are looked up in the environment when they are evaluated

16:44 EvanR: interesting

16:45 noonian: ,a-symbol-that-hasnt-been-defined

16:45 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: a-symbol-that-hasnt-been-defined in this context, compiling:(NO_SOURCE_PATH:0:0)>

16:45 noonian: ,(quote a-symbol-that-hasnt-been-defined-but-is-quoted)

16:45 clojurebot: a-symbol-that-hasnt-been-defined-but-is-quoted

16:45 noonian: ,:a-keyword

16:45 clojurebot: :a-keyword

16:45 EvanR: ,((quote undefined-symbol))

16:45 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (0) passed to: Symbol>

16:46 noonian: you just tried to call the quoted symbol

16:46 EvanR: i tried to evaluate it

16:46 justin_smith: ,((quote undefined-symbol) '{undefined-symbol 1})

16:46 clojurebot: 1

16:46 noonian: in a repl anything you type will be evaluated

16:46 EvanR: ,(eval 'C)

16:46 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: C in this context, compiling:(NO_SOURCE_PATH:0:0)>

16:46 noonian: ,(eval (quote foo))

16:46 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:0:0)>

16:46 justin_smith: ,(eval (quote *clojure-version*))

16:46 clojurebot: {:interim true, :major 1, :minor 7, :incremental 0, :qualifier "master"}

16:47 noonian: ,'this-is-shorthand-for-quoting

16:47 clojurebot: this-is-shorthand-for-quoting

16:47 EvanR: ok

16:48 im going to need a style guide pretty soon

16:48 my code is indented more than php

16:49 justin_smith: EvanR: check out bbatsov's clojure style guide

16:49 EvanR: doh, nested #(.. %...) are not allowed

16:50 justin_smith: EvanR: yeah, which % would be which?

16:50 EvanR: you know very well

16:50 well, nevermind

16:54 amalloy_lunch: EvanR: your code *will* end up more indented than php. that's not really a problem. in On Lisp, paul graham has this to say about functional programming:

16:54 The structure in a functional program comes entirely from the composition of arguments within expressions, and since arguments are indented, functional code will show more variation in indentation. Functional code looks fluid on the page; imperative code looks solid and blockish, like Basic.

16:55 jakebasile: I'm not sure why, but switching to Oracle's JDK seems to stop `lein ring uberwar` from hanging. I don't really know why - but there it is if anyone else sees it.

16:55 TEttinger: good to know, jakebasile

16:56 EvanR: amalloy: in other settings i avoid deeply nesting anonymous functions, it helps debug each one

16:56 for me

16:56 justin_smith: EvanR: it can help to use let to bind the anonymous functionas locally

16:57 EvanR: instead of literally putting each inside the other

16:57 EvanR: yes ive been doing that, i still end up with 1/2 of my horizontal space gone

16:57 and you still cant test them in isolation (though it may not make sense depending on the closure)

16:59 my editor is auto indenting stuff all the way under the last word of the previous line, which could be 15 characters out

16:59 TEttinger: you can use declare to make something not-an-error-to-be-called before it's defined, then define it after the call, and as long as the function is called after the definition runs, you're fine

16:59 EvanR: which is equivalent to like 7 tabs

16:59 justin_smith: EvanR: have some code you can paste and share? that may help for offering tips

17:00 TimMc: amalloy: Did that fl come from your machine or the place you copied it from?

17:01 (in "fluid on the page")

17:01 TEttinger: flappy bird

17:01 EvanR: justin_smith: no :(

17:01 amalloy: whoa

17:01 TimMc: http://ep.yimg.com/ty/cdn/paulgraham/onlisp.pdf apparently has the fl ligature in it

17:02 i didn't notice it at all

17:02 TimMc: Makes for fewer c㏊racte₨. :-P

17:03 amalloy: it actually looks like everywhere in that pdf that fl is used, he uses fl instead

17:05 justin_smith: flævør flæv

17:07 llasram: That sort of ligature-insertion is something that TeX tends to do for you

17:21 numberten: is there a core function that given a seq returns both its head and tail?

17:21 like: (foo [1 2 3]) => [1 '(2 3)]

17:21 noonian: ,((juxt first rest) [1 2 3 4])

17:21 clojurebot: [1 (2 3 4)]

17:21 numberten: i always forget about juxt

17:21 EvanR: do sequences necessarily end?

17:21 numberten: that's nifty, thanks

17:22 noonian: np

17:22 amalloy: EvanR: no

17:22 (range) is all the integers from 0 to infinity

17:22 noonian: EvanR: nope, you can have infinite seqs with no problems as long as you dont try to realize the whole thing

17:22 justin_smith: ,(split-at 1 [1 2 3 4]) ; kind of

17:22 clojurebot: [(1) (2 3 4)]

17:23 justin_smith: I see many combined usage of take / drop that should be one call to split-at

17:23 EvanR: uncons

17:24 amalloy: snoc for life

17:24 justin_smith: ,(let [[h & t] [1 2 3 4 5]] {:head h :tail t})

17:24 clojurebot: {:head 1, :tail (2 3 4 5)}

17:27 EvanR: snoc doesnt append something to the end?

17:28 amalloy: snoc doesn't really exist in clojure. i just mentioned it because you were talking about uncons and it seemed relevant

17:29 noonian: yeah, i just checked if it was in core heh

17:29 you guys are convincing

17:29 you folks*

17:29 technomancy: mirror-universe clojure

17:29 justin_smith: quick, someone make a pr https://github.com/gfredericks/clojure-useless/blob/master/src/clojure_useless/core.clj

17:30 technomancy: resulted from a freak nrepl accident

17:30 EvanR: appends to the end of an infinite sequence

17:31 TEttinger: infinite dimensional sequence

17:32 amalloy: EvanR: actually there is a function to add to the end of an infinite sequence

17:32 identity

17:32 justin_smith: ,(repeatedly #(repeatedly (range)))

17:32 gfredericks: pff.

17:32 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn>

17:32 justin_smith: ,(repeatedly #(repeatedly #(range)))

17:32 clojurebot: #<IllegalStateException java.lang.IllegalStateException: Nested #()s are not allowed>

17:32 EvanR: rofl

17:33 justin_smith: ,(repeatedly (fn [] (repeatedly #(range)))) ; oops

17:33 clojurebot: (((0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) ...) ((0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) ...) ((0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) ...) ((0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) ...) ((0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2 3 4 ...) (0 1 2...

17:33 EvanR: its the ordinal numbers

17:33 justin_smith: that's some nice lazy ascii art there

17:33 EvanR: it's an infinite list of infinite lists of numbers

17:34 EvanR: why stop at just 2 levels

17:34 justin_smith: laziness

17:34 amalloy: justin_smith: an infinite list of infinite lists of infinite lists of numbers, actually

17:34 justin_smith: (the programmer kind)

17:34 amalloy: ahh, yeah, right

17:34 EvanR: an infinite list of infinite list of ...

17:34 TimMc: amalloy: (range) isn't infinite on any hardware

17:34 even infinite hardware

17:34 amalloy: ,(last (iterate repeat (range)))

17:35 that's as far as you can go

17:35 clojurebot: #<OutOfMemoryError java.lang.OutOfMemoryError: Java heap space>

17:35 TimMc: For that you need (iterate inc' 0) or something.

17:35 EvanR: thats int?

17:35 noonian: i feel bad for clojurebot

17:35 amalloy: clojurebot quailed in the face of my list's multidimensional glory

17:36 TimMc: ,(range Long/MAX_VALUE Double/POSITIVE_INFINITY)

17:36 clojurebot: #<ArithmeticException java.lang.ArithmeticException: integer overflow>

17:38 EvanR: ,Long/MAX_VALUE

17:38 clojurebot: 9223372036854775807

17:38 EvanR: ,(inc Long/MAX_VALUE)

17:38 clojurebot: #<ArithmeticException java.lang.ArithmeticException: integer overflow>

17:38 EvanR: thats awesome

17:39 justin_smith: ,(inc' Long/MAX_VALUE)

17:39 clojurebot: 9223372036854775808N

17:39 EvanR: whats N whats inc'

17:39 Bronsa: ,(class 1N)

17:39 clojurebot: clojure.lang.BigInt

17:40 Bronsa: EvanR: inc' is like inc except it auto promotes to BigInt rather than overflowing

17:40 TimMc: range used to use inc' (which used to be called inc)

17:40 EvanR: does big decimal act like floats or does it get arbitrarily big

17:41 justin_smith: ,(*' Long/MAX_VALUE Long/MAX_VALUE)

17:41 clojurebot: 85070591730234615847396907784232501249N

17:41 justin_smith: EvanR: it stays precise, and uses more and more memory to store the contents

17:42 puredanger: (/ Long/MIN_VALUE -1)

17:42 ,(/ Long/MIN_VALUE -1)

17:42 clojurebot: -9223372036854775808

17:42 puredanger: shhh :)

17:43 noonian: huh, i didn't know about those fns

17:43 thanks justin_smith

17:43 justin_smith: noonian: np

17:43 noonian: er Bronsa i guess

17:43 i'm late to the party

17:44 justin_smith: noonian: in this context TimMc brought it up first

17:44 regarding range not using inc'

17:44 TimMc: puredanger: :-( :-( :-(

17:44 Bronsa: ,(map (partial / Long/MIN_VALUE) (range -1 -10 -1))

17:44 clojurebot: (-9223372036854775808 4611686018427387904 -9223372036854775808/3 2305843009213693952 -9223372036854775808/5 ...)

17:44 puredanger: hey, it works for every other long value, so percentage-wise, it's pretty good

17:44 Bronsa: the sign flips :(

17:44 TimMc: justin_smith: I will never not bring up range not being infinite.

17:44 puredanger: http://dev.clojure.org/jira/browse/CLJ-1253

17:45 EvanR: ,(= (Long/MIN_VALUE) (/ Long/MIN_VALUE -1))

17:45 clojurebot: true

17:45 justin_smith: err

17:45 EvanR: therefore 1 = -1

17:45 justin_smith: weird how Long/MIN_VALUE works in parens

17:45 never even thought to try it

17:46 Bronsa: justin_smith: yeah, older syntax I guess

17:46 justin_smith: ,(Math/PI)

17:46 clojurebot: 3.141592653589793

17:46 amalloy: justin_smith: i believe that's legacy syntax, before Long/MIN_VALUE worked at all

17:46 TimMc: ew

17:46 puredanger: yeah

17:46 Bronsa: ,(macroexpand '(Math/PI))

17:46 clojurebot: (. Math PI)

17:46 TimMc: What if I want to throw an exceptino about a number not being castable to an IFn?

17:47 ,((Math/PI)) ;; I have to add more parens!

17:47 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Double cannot be cast to clojure.lang.IFn>

17:47 justin_smith: TimMc: you can't get passed Math/PI as the form, you would get it's value instead

17:47 Bronsa: TimMc: almost like C

17:55 numberten: is there a reverse nth function that removes the nth element from a seq

17:59 amalloy: numberten: no, because it can't be made a very efficient function. if your algorithm involves doing that, you're encouraged to reconsider: there's always a better way

17:59 dbasch: numberten: but if you must, (concat (take (dec n) s) (drop n s))

18:00 noonian: you could write it with a lazy loop recur

18:00 numberten: hm

18:00 dbasch: it’s o(n) regardless

18:01 numberten: yeah I was willing to pay the O(n), was just curious if there was a core fn for it

18:03 dbasch: speaking of useful things, there used to be a separate function somewhere that was the same as (juxt filter remove), wonder why that’s not in core

18:07 amalloy: noonian: there's no such thing as a lazy loop recur

18:07 noonian: er, lazy-seq macro and normal recursion

18:08 gfredericks: which util lib has take-while+1?

18:08 SegFaultAX: Finger trees would be nice.

18:10 gfredericks: dbasch: my guess is it's a questionable thing to advertise for general use since it's not very lazy-friendly

18:11 dbasch: gfredericks: it’s lazy-friendly if used properly

18:11 amalloy: gfredericks: https://github.com/flatland/useful/blob/develop/src/flatland/useful/seq.clj#L365 ?

18:11 dbasch: like everything I guess

18:13 gfredericks: dbasch: what's the proper use?

18:13 amalloy: yep that's it

18:14 dbasch: &(map #(take 3 %) ((juxt filter remove) even? (range))) ;; e.g.

18:14 lazybot: ⇒ ((0 2 4) (1 3 5))

18:14 gfredericks: what if you intend to consume all of each sequence? but they're both too big to fit in memory?

18:15 dbasch: gfredericks: how is that different from any other case of laziness / eagerness?

18:16 on my computer (range) doesn’t fit in memory

18:16 but I’m a poor boy

18:17 gfredericks: dbasch: e.g., (let [nums (range 10000000000), [evens odds] ((juxt filter remove) even? nums)] (doseq [n evens] ...))

18:17 you can't process either result as lazily as you can with other lazy ops

18:18 gzmmsk: ,(= (+ 0.1 0.2) 0.3)

18:18 clojurebot: false

18:18 gzmmsk: ,(= (+ 0.2 0.2) 0.4)

18:18 clojurebot: true

18:19 Bronsa: gzmmsk: that's how floating points work

18:19 EvanR: in clojure, when talking about lazy streams, is there an implicit assumption that getting the next thing in the stream will do IO?

18:19 or might

18:19 gzmmsk: Bronsa: hmm... trying to write tests for my CG algorithms. so this is impossible?

18:20 justin_smith: EvanR: the next item may produce any kind of side effect when realized, but putting side effects in lazy sequences outside of a debugging scenario is probably a mistake

18:21 SegFaultAX: gzmmsk: You should test it the way you test any floating point algorithm. Using an appropriately sized epsilon to account for the inability to represent certain numbers correctly.

18:21 EvanR: whoever said that can you please repeat, possibly in a PM :(

18:21 gfredericks: incidentally this isn't floating point's fault, it's binary fractions in general

18:22 Bronsa: gzmmsk: well you can use BigDecimals instead of doubles to get more precision

18:22 gfredericks: ,(= (+ 0.1M 0.2M) 0.3M)

18:22 clojurebot: true

18:22 SegFaultAX: If you want to add M to all your numbers.

18:22 Yea

18:22 gfredericks: how does that work; are BigDecimals base 10?

18:23 ,(reduce + (repeat 10000 0.1M))

18:23 clojurebot: 1000.0M

18:23 gfredericks: ,(reduce + (repeat 10000 0.1))

18:23 clojurebot: 1000.0000000001588

18:23 dbasch: gfredericks: the answer is in the name :P

18:24 amalloy: gfredericks: they are, yeah

18:24 gfredericks: I hate the word decimal

18:24 dbasch: decimate all decimals

18:24 amalloy: i'm decimated whenever i hear it

18:24 justin_smith: gfredericks: clearly we need decibenes

18:24 Bronsa: oh no, not again

18:25 gfredericks: it's supposed to mean "base 10" here but surely 99% of everyday usage refers to the method for representing fractional parts of a number

18:25 which can be done in binary in the same fashion

18:25 amalloy: computers usually use binary decimals

18:25 gfredericks: it's even called a "decimal point" wtf

18:25 bostonaholic: you mean a binary decimal?

18:26 SegFaultAX: gfredericks: You mean it's confusing to overload the same term with multiple orthogonal meanings?

18:26 gfredericks: in any case, if you had a fixed-point binary "decimal" number it would also fail to (= (+ 0.1 0.2) 0.3)

18:27 SegFaultAX: I think what bothers me is I don't have a fallback word for the positional-fraction-representation-system-thing

18:27 on the other side I can fallback to "base 10" if I want to be precise

18:27 dbasch: you can try to make “denary numbers” happen

18:28 SegFaultAX: dbasch: Stop trying to make denary numbers happen. It's not going to happen.

18:28 dbasch: that’s so denary of you

18:28 SegFaultAX: So fetch.

18:28 gfredericks: "pointed numbers"

18:28 justin_smith: gzmmsk: ##(Math/ulp 1.0) - for your testing, ulp may come in handy

18:28 lazybot: ⇒ 2.220446049250313E-16

18:28 gfredericks: I'll define that up front if I ever give a talk on the subject

18:29 justin_smith: gzmmsk: Unit In Last Place

18:29 lodin: Is there a way to not import java.lang classes? So that e.g. (defrecord String []) wouldn't throw an exception. (java.lang.String should still be available in it's fully qualified form.)

18:29 dbasch: when I talk about my age, it’s always 0x something

18:30 SegFaultAX: lodin: Why do you want to do this?

18:30 gfredericks: SegFaultAX: probably the same reason we encourage reusing names in clojure.core?

18:30 justin_smith: dbasch: you may want to stop when you are 57004 years old

18:31 dbasch: (inc justin_smith) ; lol

18:31 lazybot: ⇒ 102

18:31 gfredericks: ,(Long/toString 57004 16)

18:31 clojurebot: "deac"

18:31 lodin: SegFaultAX: I have a name that makes sense, but it was taken by java.lang. The full name for my class would of course be foo.bar.X (where X is String above).

18:32 SegFaultAX: lodin: I fear using a name that is protected in all of Java-land would probably be confusing. Either way, I don't know how to make that name not protected in a namespace.

18:33 justin_smith: ,0xdead ; gfredericks

18:33 clojurebot: 57005

18:33 justin_smith: but you probably got that already

18:34 lodin: SegFaultAX: Ah. Is java.lang names forbidden as class names in other java namespace as well? (I don't know Java.)

18:34 gfredericks: justin_smith: yeah I'm sooper good at incrementing hex numbers in my head

18:35 SegFaultAX: lodin: AFAIK. But I've never really tried. java.lang is the most special namespace in Java.

18:36 TEttinger: ,36rALIVE

18:36 clojurebot: 17800394

18:37 amalloy: i think you can shadow java.lang classes, but it's just as un-fun in java as in clojure

18:37 gzmmsk: great way to use bigdec. thanks for the pointer!

18:37 SegFaultAX: amalloy: `class String` doesn't blow up? TIL.

18:38 lodin: SegFaultAX: Just to be clear, I'm not trying to do anything crazy. It's just that if I want to have a record or protocol called e.g. Compiler, I can't.

18:39 SegFaultAX: lodin: Oh I'm with ya. I'm sure it makes sense, but it may still be a bad idea.

18:39 (Makes sense in the context of your project, that is)

18:40 amalloy: SegFaultAX: yeah, works fine, not even a warning. you just have to refer to java.lang.String longhand anywhere you want to refer to it, within that file

18:41 package whatever; public class String {public static java.lang.String get() {return "test";}}

18:41 SegFaultAX: Neat!

18:44 gfredericks: I am pleasantly surprised that the 2r101... syntax can create bigints if necessary

18:45 lodin: SegFaultAX: I realized I can just (ns-unmap *ns* String).

18:46 'String, that is.

18:46 SegFaultAX: lodin: Be careful, have fun! :)

18:47 gfredericks: you can even do it in your (ns)

18:47 lodin: SegFaultAX: I've changed the name already. :-)

18:48 gfredericks: (ns foo (:ns-unmap foo String)) ;; works

18:48 bearfeeder: Hey all... I'm working on a project where I need to capture generated bytecode so I can transport that bytecode (rather than the raw Clojure source) to another address space

18:48 I've been digging through Compiler.java

18:48 lodin: gfredericks: Ah. Haven't seen that one before.

18:48 gfredericks: lodin: I think it only works by accident

18:48 bearfeeder: But I haven't found a place I can hook into to get the generated bytecode and list of generated classes

18:49 So, is there a nice way to capture the bytecode?

18:49 lodin: Is there a reason all (?) of java.lang is imported by default?

18:49 I get that we want String and other data types, but the rest?

18:49 gfredericks: lodin: you'd rather have to ask for it? there's no import-all functionality anyhow

18:53 lodin: gfredericks: I guess so, yeah. For the same reason :use is discouraged. (Except the core of course.)

18:53 gfredericks: it's certainly more intuitive to java folk

18:55 amalloy: i mean, what is there in java.lang that you *don't* want? most of the stuff there is pretty primitive, stuff you'd just assume you can access

18:55 gfredericks: RuntimePermission

18:55 ,Void

18:55 clojurebot: java.lang.Void

18:55 * gfredericks has never looked at this list before

18:56 amalloy: gfredericks: yeah, yeah, obviously there's stuff you don't need. but is any of it actually in lodin's way?

18:56 like, excluding the stuff you don't need doesn't buy you anything, because it doesn't conflict with anything you'd write anyway

18:56 and if sun decided it was important enough to automatically import, who are you to decide that they were only right about half of it, or whatever

18:57 gfredericks: ClassValue is weird

18:57 amalloy: huh, i didn't know about that one. new to 1.7

18:57 justin_smith: gfredericks: woah, weird, Void is a class that never has instances

18:58 gfredericks: ,(Void.)

18:58 clojurebot: #<CompilerException java.lang.IllegalArgumentException: No matching ctor found for class java.lang.Void, compiling:(NO_SOURCE_PATH:0:0)>

18:58 amalloy: justin_smith: used in reflection

18:58 gfredericks: ,Void/TYPE

18:58 clojurebot: void

18:59 gfredericks: ,(make-array Void/TYPE 3)

18:59 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException>

18:59 technomancy: anyone want to take bets on it having wacky equality semantics?

18:59 amalloy: technomancy: how could it? any semantics at all are correct, if you can't instantiate it

19:00 gfredericks: ,(= Void Double/NaN)

19:00 clojurebot: false

19:00 gfredericks: ,(= Void Void)

19:00 clojurebot: true

19:00 technomancy: amalloy: I figured at least one instance might be created by the JVM internally?

19:00 amalloy: i don't think so

19:00 gfredericks: "an uninstantiable placeholder class"

19:00 lodin: You're right. I forget that many clojure programers are also Java programmers.

19:01 gfredericks: lodin: I suspect java programmers were the original audience

19:01 dbasch: it would be hard to mess this up http://grepcode.com/file_/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Void.java/?v=source

19:02 amalloy: dbasch: so much wordier than the haskell equivalent: data Void

19:02 dbasch: amalloy: in Java you literally can’t do nothing in less than 6 or 7 lines

19:03 at least with proper formatting

19:03 lodin: gfredericks: And indeed the connection to the Java world was what originally got me interested. :-) Not for Java's sake, but for the availability of libraries.

19:03 gfredericks: lodin: the java.lang library is the best!

19:04 it has...some kinds of numbers...

19:04 ,Compiler

19:04 clojurebot: clojure.lang.Compiler

19:04 gfredericks: woah what

19:04 ,java.lang.Compiler

19:04 clojurebot: java.lang.Compiler

19:04 gfredericks: &Compiler

19:04 lazybot: java.lang.SecurityException: You tripped the alarm! class clojure.lang.Compiler is bad!

19:05 gfredericks: ,EnumerationSeq

19:05 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: EnumerationSeq in this context, compiling:(NO_SOURCE_PATH:0:0)>

19:05 gfredericks: ,IPersistentQueue

19:05 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: IPersistentQueue in this context, compiling:(NO_SOURCE_PATH:0:0)>

19:05 hiredman: http://docs.oracle.com/javase/7/docs/api/java/lang/Compiler.html#command%28java.lang.Object%29 best documentation ever?

19:05 Bronsa: hiredman: it's c.l.Compielr, not j.l.Compiler

19:05 compiler*

19:06 technomancy: hiredman: wow

19:06 Bronsa: hiredman: uh missed context, nvm

19:06 hiredman: Bronsa: but there is a java.lang.Compiler, which I had never seen before

19:06 gfredericks: and it has great docs

19:07 justin_smith: "Examines the argument type and its fields and perform some documented operation. No specific operations are required." <- can we put this in -main in lein new?

19:07 gfredericks: but also while Bronsa is here why on earth does 'Compiler of all things go to clojure.lang?

19:07 Bronsa: gfredericks: no technical reason

19:07 gfredericks: just for funsies?

19:07 Bronsa: I guess

19:08 gfredericks: figures it's the only thing refer'd from clojure.lang and it happens to shadow something from java.lang

19:08 * gfredericks tucks that away for clojure trivia parties

19:08 Bronsa: gfredericks: fun thing is, it's always qualified in the clj files

19:09 tuft: i had a crazy idea: what about a clojure shell? i.e. to take the role of zsh, bash, etc.

19:09 obviously would need to communicate with a persistent jvm

19:09 justin_smith: tuft: you could use scsh as a launching off point design wise

19:09 TEttinger: tuft, and it would need to respond correctly to stuff like ctrl-d

19:09 Bronsa: gfredericks: looking at the impl, it's probably a bug actually

19:10 tuft: TEttinger: i think you'd write the interface stuff in native code or borrow some from somewhere maybe

19:10 justin_smith: cool thanks

19:10 Bronsa: gfredericks: it should refer to j.l.Compiler but c.l.Compiler is shadowing it https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L58

19:11 amalloy: that's pretty funny, Bronsa

19:12 hiredman: well, it isn't like java.lang.Compiler is used

19:13 tuft: justin_smith: fails my first test, which is that all the usual bourne pedigree built-ins should be functions that work out-of-the-box

19:13 gfredericks: Bronsa: wow good catch

19:13 what are the chances a patch would be rejected as a breaking change?

19:16 hiredman: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L33-L34 also amusing

19:16 Bronsa: gfredericks: close to the chances a patch has to be accepted in a reasonable amount of time I'd say

19:17 bbloom: hiredman: ha

19:17 hiredman: i particularly like how F was "t"

19:23 Bronsa: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L2060-L2065 wat

19:24 egghead: looks legit Bronsa

19:33 dbasch: Bronsa: values? We don’t need no stinkin’ values!

19:39 SegFaultAX: I, uh. What?

19:40 gfredericks: it's clojure's secret sauce

19:41 SegFaultAX: So that's where it is. I always wondered where they kept it.

19:41 dbasch: it’s the Clojure Mojo, aka CloJo

19:42 oskarkv: Why do I get this error? https://www.refheap.com/ada027007d68400bd52bddc77

19:43 gfredericks: I don't know.

19:44 SegFaultAX: Is this a cider session we're looking at?

19:44 amalloy: oskarth: that is like a million lines of code, which use functions that aren't defined in this file

19:45 SegFaultAX: Is it possible the namespace was reloaded?

19:45 oskarkv: SegFaultAX No, not cider.

19:49 gfredericks: oskarkv: it will probably help a lot to try to minimize the example

19:50 oskarkv: amalloy The error seems to be specifically about calling hudnode-code, which I just defined. The contents of that functions should not matter, I think; the error is about trying to call it, no?. And my second batch of input uses only one other macro, "with-gensyms".

19:52 gfredericks yeah I'll try

20:03 {blake}: Is possible to un-import?

20:04 gfredericks: ,(doc ns-unmap)

20:05 clojurebot: "([ns sym]); Removes the mappings for the symbol from the namespace."

20:05 gfredericks: ,(import 'java.util.UUID)

20:05 clojurebot: java.util.UUID

20:05 gfredericks: ,(ns-unmap *ns* 'java.util.UUID)

20:05 clojurebot: nil

20:05 gfredericks: ,UUID

20:05 clojurebot: java.util.UUID

20:05 * gfredericks shrugs

20:05 technomancy: mutability!

20:05 ~guards

20:05 clojurebot: SEIZE HIM!

20:06 gfredericks: oh wait

20:06 ,(ns-unmap *ns* 'UUID)

20:06 clojurebot: nil

20:06 gfredericks: ,UUID

20:06 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: UUID in this context, compiling:(NO_SOURCE_PATH:0:0)>

20:06 gfredericks: that was it

20:07 {blake}: (inc gfredericks)

20:07 lazybot: ⇒ 99

20:07 {blake}: daaaww....so close

20:07 Thanx!

20:15 TEttinger: ,(rand-int 2)

20:15 clojurebot: 0

20:15 TEttinger: sorry gfredericks, you get +0 karma

20:17 gfredericks: quick I gotta tell a good joke

20:19 amalloy: gfredericks: make it a calculus joke. people love to look smart by laughing at those

20:19 gfredericks: okay so rich hickey, stu halloway, and alex miller walk into a bar

20:20 * gfredericks tries to think of the rest of the joke

20:21 gfredericks: and the bartender says "this must be clojure conj"

20:22 so that's the joke.

20:22 amalloy: gfredericks: i was really looking forward to a punch line

20:23 gfredericks: I considered having the bartender complain about stacktraces

20:23 SegFaultAX: Definitely an immutability joke in there somewhere.

20:24 amalloy: gfredericks: rich asks for a new england martini, and the bartender brings back sixty empty glasses, all stacked inside each other: "sorry, i haven't heard of that one"

20:24 gfredericks: lol

20:24 (inc amalloy)

20:24 lazybot: ⇒ 176

20:25 gfredericks: aw crap that's not how this was supposed to end

20:25 amalloy: *chuckle* situational humor is more fun anyway

20:25 (inc gfredericks)

20:25 lazybot: ⇒ 100

20:26 amalloy: okay, audience participation time: the joke needs punchlines for alex and stu too

20:26 * bbloom blinks

20:33 SegFaultAX: amalloy: I don't get your joke, what did I miss?

20:34 amalloy: SegFaultAX: the cups are a stacktrace from attempting to resolve an unbound drink order. if you care to look further, you can consider that they're empty and useless to rich, just like clojure beginners think stacktraces are

20:35 SegFaultAX: Ah. Nice.

20:37 amalloy: the best jokes require lengthy explanation

20:38 SegFaultAX: ,(doc joke)

20:38 clojurebot: Pardon?

20:52 visof: hi

20:52 how can i convert this to clojure https://www.refheap.com/92128?

20:52 how can i convert this to clojure https://www.refheap.com/92128 ?

20:53 (.flatMap lines <fun here>)

20:54 guys can anybody help ?

20:54 seancorfield: visof: looks like it splits a sequence of lines into a sequence of words, split at whitespace?

20:54 amalloy: visof: some folks might be inclined to help you, but if you paste the same message twice in two seconds and then prod them to hurry up in under two minutes, that's not very polite

20:55 the clojure equivalent of `new Foo() {public whatever bar(int x) {return y;}}` is (reify Foo (bar [this x] y))

20:55 seancorfield: ,(clojure.string/split "A line\nAnother line\n" #"\s")

20:55 clojurebot: ["A" "line" "Another" "line"]

20:55 Jaood: is that java 8 code?

20:56 amalloy: seancorfield: i think the point is to translate the java into java-interop forms, not to find out how to split a string

20:56 visof: amalloy: i sent it twice to correct the link by removing ?

20:56 seancorfield: It depends what visof means by "convert this to clojure"...

20:57 amalloy: that's true, i suppose

20:57 seancorfield: I was going to suggest (mapcat (fn [line] (clojure.string/split line #"\s")) lines)

20:57 I just wondered whether #"\s" matched newlines so I asked the bot

20:57 clojurebot: Excuse me?

20:59 amalloy: seancorfield: a more interesting question is whether #"." matches newlines

21:00 the answer turns out to be that it depends: you can pass in a flag saying which way you want it to act, with the ?s flag

21:01 like in #".(?s)." the first . doesn't match newlines, but the second does

21:04 visof: amalloy: so the piece of java i posted should be converted to (.flatMap lines (FlatMapFunction. (reify FlatMapFunction (call x) x))) ?

21:05 amalloy: i returned x because x don't splitted

21:05 i got error, so i'm just return x for now to try to figure it out

21:13 amalloy: ?

21:20 hi guys not body can help?

21:27 Bronsa: visof: work with this (.flatMap lines (reify FlatMapFunction (call [x] your-impl-here)))

21:28 visof: but please don't keep asking for help, this isn't a helpdesk and pinging people for help isn't really polite

21:28 seancorfield: visof: I answered your question with idiomatic Clojure about half an hour ago

21:29 it's also past the end of the working day in the USA so I expect a lot of folks are just idling / away at this point

21:30 it's 6:30pm here in California and I'm about to go feed the cats and then have dinner / watch TV...

21:46 numberten: been playing around with this function for a bit anyone mind looking it over for me? http://pastebin.com/euKX8SiT getting IndexOutOfBounds errors though not sure how/why

21:58 * kenrestivo chuckles at an atom that is a big huge wad of state, named "bolus"

22:14 ed-g: Straw poll. What's everyone's favorite way to build forms for the editing of data in a relational database? I'm a fan of Enlive for HTML templates, and YESQL for relational database access.

22:17 beppu: ed-g: I'm not using Clojure, yet, but I use React.js on the front-end. (no templates; just React components).

22:19 numberten: solution to that pastebin (for any interested), was removing the first 0-arity case and replacing it with a (cond (empty? colls) nil :else <old case>)

22:19 doesn't really explain why the old version threw an indexoutofbounds, but seems to work nonetheless

22:21 quile: numberten: couldn’t it throw here: (drop (inc i) colls) if i was the index of the last item in colls?

22:21 justin_smith: numberten: ##((fn [cols] (nth cols (rand-int (count cols)))) [])

22:21 lazybot: java.lang.IndexOutOfBoundsException

22:21 justin_smith: that's what it did every time

22:23 numberten: ah

22:23 ed-g: beppu: thanks. react looks really cool, but for maximum compatibility I'm building this as an "old fashioned" server-side web app.

22:23 quile: i take that back… (drop …) doesn’t care

22:23 numberten: yeah (nth [] 0) >.>

22:23 ,(nth [] 0)

22:23 clojurebot: #<IndexOutOfBoundsException java.lang.IndexOutOfBoundsException>

22:24 numberten: weirdly enough I had print debugs in the let and they would only ever fire for the first call to the function

22:24 you'd think they would have fired since the case where colls = [] is at the very end

22:25 justin_smith: ,(nth [:a] (rand-int 1))

22:25 clojurebot: :a

22:25 justin_smith: ,(nth [:a] (rand-int 1))

22:25 clojurebot: :a

22:25 justin_smith: hmm

22:27 numberten: yeah if you add a _ (println "foo") to the let in the original

22:27 oskarkv: Spent a while, more than I care to admit, on debugging an "unable to resolve symbol" error, that came from me trying to use a record function body as a closure.

22:27 numberten: and do (foo [(range 10)]), you get one print and then the exception

22:28 oskarkv: If only the error message was more specific. :P

22:41 gizmo385: If I have a type, Vertex, and I want to call a function defined in the Vertex type from another type, how can I do that?

22:41 Every time I've tried, I get "no matching method" errors

22:43 gfredericks: gizmo385: can you show us what you tried exactly?

22:44 gizmo385: (let [new-u (IVertex/connectTo u v)] ...

22:45 Where IVertex is the interface that defines connectTo

22:46 I've also tried to replace (IVertex/connectTo ...) with (Vertex/connectTo ...) which is the type that implements IVertex

22:48 gfredericks: IVertex is an interface? is `u` an object that implements IVertex?

22:49 gizmo385: u is a Vertex, which implements IVertex

22:51 gfredericks: okay, then I think you want (.connectTo u v)

22:51 they syntax you're using is only for static methods

22:51 the*

22:51 gizmo385: Ah okay

22:52 If I have a function defined in IVertex that has the same name as a function in another interface, how can I specify which one I want to call?

22:53 Or will it just figure it out?

22:53 gfredericks: I don't think java really allows that situation?

22:53 gizmo385: I suppose the way I phrased that was somewhat confusing

22:53 If I'm in a type A

22:54 that contains instances of type B

22:54 and both A and B defined some function f

22:54 If I want to call f, how can I specify which f I want to call?

22:54 wef: a.f or b.f

22:55 gfredericks: gizmo385: what do you mean by being "in a type A"?

22:55 gizmo385: I'm defining a function inside type A

22:55 gfredericks: with deftype or defrecord?

22:55 justin_smith: gizmo385: since we have actual functions (and hell even java has java.util.function.Function) please use the word method to refer to methods

22:56 gfredericks: he is talking about methods on classes

22:57 gfredericks: justin_smith: I realize that much, but it sounds like he's defining a method, so was just interested in what that meant

22:57 gizmo385: deftype

22:58 gfredericks: gizmo385: inside a deftype method is pretty normal clojure code -- the only thing magical about it is that the fields of the deftype are lexically available

22:58 gizmo385: Sorry for calling them function, I'm still trying to get the hang of the lingo in clojure. The class structure is different from what I'm used to

22:58 Ah okay. That makes sense.

22:58 gfredericks: gizmo385: so doing method calls works the same way there as elsewhere, i.e. the meaning of the method call depends on the type of the object you're calling the method on

22:58 gizmo385: Thanks :)

22:59 justin_smith: gizmo385: well, on top of that, clojure functions are classes! (that's how they can be first class) it's a different world

23:00 gizmo385: justin_smith, how does it handle the typing?

23:00 justin_smith: ,(class (fn []))

23:00 clojurebot: sandbox$eval25$fn__26

23:01 justin_smith: ,(class (fn []))

23:01 clojurebot: sandbox$eval51$fn__52

23:01 justin_smith: each is it's own class with only one instance

23:02 gizmo385: Has this changed since the introduction of lambdas in Java 8?

23:02 rritoch: gizmo385: Types only define the interface (arguments and return types) which an implementing class must implement (unless it is abstract). If the two interfaces define different arguments than you can define your method in clojure with separate implementations for each if the number of arguments is different, otherwise you may need to rely on conditional logic (instance?) to determine which

23:02 gizmo385: The introduction of the new bytecode instruction seems like it would provide significant performance increases for a language like Clojure

23:02 justin_smith: gizmo385: we don't use java lambdas (yet?) - we target 1.6 compatibility

23:02 TEttinger: no, that would reduce availability to JDK 8 only

23:02 gizmo385: Ahh

23:03 rritoch: gizmo385: This is a fairly core feature of Java and an annoyance when part of a team where co-workers insist on using the same function name in multiple interfaces.

23:04 justin_smith: method, please, no need to add confusion here

23:04 rritoch: justin_smith: In clojure function is appropriate for methods since the java method actually calls the clojure function

23:11 gizmo385: What you can do, is "wrap" the second interface in it's own class and create an instance of it within one of the classess. Such as (defn -init [] [[] {:b (B.)}]) (defn -WrappedMyMethod [this] (.MyMethod (:b (.state this)))

23:13 gizmo385: You could also use inheritance, having a parent class implement one interface, have the child class implement the other and utilize exposes-methods which would fundamentally produce the same result without needing to maintain a separate object.

23:14 amalloy: justin_smith: functions aren't classes, they're objects. and they're not singletons either, necessarily: in any app you've written i'm quite sure there are multiple instances of the same function class

23:15 justin_smith: OK

23:15 amalloy: consider, eg, ##(letfn [(f [x] (fn [y] (+ x y)))] (map class [(f 1) (f 2)]))

23:15 lazybot: ⇒ (sandbox5671$eval11877$f__11878$fn__11879 sandbox5671$eval11877$f__11878$fn__11879)

23:16 rritoch: gizmo385: I have this problem with my daily work because my boss incists on using "start" as the method to initiate the a modules function, but OSGi uses start to start the bundle. Thanks to this fundamental flaw in design it is impossible to have the activator double as the OSGi service.

23:16 raspasov: does anyone have experience with best practices regarding triggering IO from from inside a (go ) core.async block?

23:16 amalloy: a function's class represents its code, more or less, and instances of it represent the lexical scope of a particular instance of that class

23:16 raspasov: I know IO within a (go ) is discouraged

23:18 so I'm thinking about starting a (future) from inside the Go block, passing a (chan 1) to that future and waiting within the (go ), aka parking via (<! (chan 1)), for a response on that same (chan 1)

23:19 because I don't want to continue the Go block unless that (future) is successful

23:19 justin_smith: so the future would do all the printing

23:19 raspasov: the future tries to write to a log file

23:19 i.e. disk IO operation

23:20 justin_smith: what about a dedicated logging thread, it takes a task and a chan from it's in chan, writes out the task, sends a status back to the chan

23:22 raspasov: let me do a gist

23:27 https://gist.github.com/raspasov/f16ea712780e6c90908b

23:27 github wasn't coloring the syntax but somehow I made it do it lol

23:28 justin_smith: the (start-write-loop) is essentially a dedicated logging thread (lightweight go thread)

23:29 it buffers a bunch of writes for ~1ms, sends them to disk, and confirms all those writes to the caller

23:31 I'm doing a lot of disk because I'm trying to balance between throughput and speed of writing

23:31 I'm doing all of this*

23:31 sorry

23:31 I'm doing all of this because I'm trying to balance between throughput and safety

23:32 the previous sentence didn't make sense :0

23:32 :)

23:32 rritoch: raspasov: Why are you trying to implement synchronous logic in an asynchronous system? The asynchronous way of handing "wait" conditions is to have the IO function call a callback function when it completes. Typically this would be done with a state variable (atom), you can go into a wait mode after calling future, and the callback could then set either a success or fail state.

23:32 justin_smith: raspasov: so is each spit going to a different file?

23:33 raspasov: justin_smith: no it's the same file

23:33 rritoch: raspasov: Sometimes you may need to put intermediate data into a queue which gets processsed from the callback, but that depends on your application

23:33 justin_smith: raspasov: you'll get much better performance by leaving the file open

23:34 rritoch: the point of core.async is to eliminate callbacks and use channel ops as their replacement

23:34 raspasov: justin_smith - but I do want to flush it to disk on a regular basis (~1ms)

23:34 justin_smith: raspasov: (flush)

23:34 or the jvm interop which accomplishes this for your particular stream

23:35 raspasov: I see, so you're saying try to keep the file always open

23:35 I did a benchmark, and open/close once per 1ms didn't seem like it made a difference, but I might be wrong

23:36 justin_smith: raspasov: I think you'll get the most robust design and best throughput if one thread simply has the file open, takes requests for doing output from a channel, each one accompanied by a "status" channel, and once writing and flushing sends a status back on that channel

23:36 raspasov: rritoch: if you look at the code, I believe I'm almost doing what you're describing

23:36 justin_smith: the requesting go block can park on the status channel

23:36 raspasov: rritoch: via the (chan 1)'s that I'm passing

23:37 justin_smith: thanks for the input, that makes sense, I'll try doing that

23:37 justin_smith: I'm almost doing that, with the only difference that I'm closing/opening the file instead of just flushing it

23:41 justin_smith/rritoch: thanks for the feedback guys, much appreciated, I'll give it a try

23:41 justin_smith: raspasov: yeah, I'd use clojure.java.io/writer to create a BufferedWriter, and then periodically call the .flush method on that stream

23:42 raspasov: that also means you can eliminate the buffering logic - the underlying class has that covered

23:42 you can simplify your code immensely

23:43 rritoch: raspasjustin_smith: It looks like I solved the AOT/script issue I was talking to you about yesterday.

23:44 justin_smith: oh yeah?

23:45 rritoch: I created a new macro (fscript) which creates an gensym named function with metadata of :fscript true

23:46 And this is the runner: (defn run-fscripts [script-ns] (doseq [[s v] (doall (filter #(:fscript (meta (second %))) (ns-publics (symbol script-ns))))] (v)))

23:47 There is also a loader in play at another layer of this system, which doesa load-reader loading if the namespace isn't yet defined (find-ns)

23:48 This should solve the performance issues since loading only needs to happen once, I haven't yet fully tested within the application, but these functions are working, so I'm not yet sure if the load is ever needed when the system is aot compiled.

23:49 The only dilema is if a reload occurs the namespace doesn't get cleaned-out first (require :reload-all) so you end up with multiple copies of the script, running and a giant memory leak.

23:50 justin_smith: rritoch: I don't understand why you need functions with gensym names, why not for example a vector of functions (that could be reset to nil so that they can be garbage collected)

23:52 rritoch: justin_smith: resetting a vector to nil, and deleting a namespace before reloading it is fundamentally equivalent operations.

23:53 justin_smith: sure, but one of them doesn't involve creating a bunch of vars with nonsense names

23:53 rritoch: justin_smith: Both methods are possible, this is just the one I went with.

23:53 The names aren't nonsense

23:54 justin_smith: gensyms are nonsense

23:54 rritoch: I'm using (gensym "__fscript_") so they're easily identified as fscript functions with or without the metadata

23:55 The metadata is simply to allow developers to name the functions themselves

23:55 Instead of (fscript ...) they can (defn ^{:fscript true} MyScript [] ....)

23:58 Either way, needing to remove-ns before reloading is a fairly small price to pay for the performance advantage of not needing to compile multiple scripts on every http request.

23:58 compile and/or eval

Logging service provided by n01se.net