#clojure log - Aug 16 2014

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

1:03 eric_normand: anyone going to the conj want to split a room?

1:04 Clarice: Yes, split a room with a total stranger you meet on IRC.

1:05 abaranosky: Clarice: be a bummer why don't ya

1:05 Clarice: :)

1:05 technomancy: we're like a big family in #clojure

1:05 ~group hup

1:05 clojurebot: I don't understand.

1:05 Clarice: (inc clojurebot)

1:05 lazybot: ⇒ 42

1:06 abaranosky: best way to meet people

1:06 Clarice: Is that a fixed number?

1:06 Is that a fixed number?

1:06 (inc clojurebot)

1:06 lazybot: ⇒ 43

1:06 abaranosky: or die

1:06 Clarice: Oh! No, better keep it at 42.

1:06 (dec clojurebot)

1:06 lazybot: ⇒ 42

1:06 abaranosky: how bad could it be

1:06 technomancy: some day we hope to have the technology to help you understand, clojurebot

1:09 TEttinger: eric_normand: try couchsurfing?

1:09 abaranosky: what do you all think of transducers?

1:09 TEttinger: they're just as much people as cisducers

1:09 Clarice: Hahahahah

1:09 abaranosky: I think they're pointless.

1:10 TEttinger: I haven't used reducers yet, but I see their point

1:10 eric_normand: TEttinger: hmm. now that would be a total stranger.

1:10 TEttinger: eric_normand, yes but #clojure doesn't have reviews of strangers

1:11 abaranosky: Clarice: I See they're designed so they can be used with sequences and also channels... I haven't looked into how they could be used with other types of things

1:11 would it be possible to make them work with other things like futures or promises?

1:13 TEttinger: abaranosky: megaducers in 1.8.0

1:13 Clarice: A promise is not a collection.

1:13 TEttinger: we're just going to get ducing all over

1:13 every version a new *ducer

1:14 mthvedt: i demand recursively enumerable ducers

1:14 TEttinger: duceducers

1:14 paraducers, xenoducers

1:15 mthvedt: nonconstructable ducers

1:15 Clarice: epiducers

1:15 abaranosky: yeah sucks... I wish if they'd made a general abstraciton it could've been truly general

1:15 like in other languages you can map over a future, which is what I was thinkin gof

1:15 TEttinger: the first being a transducer that runs in parallel to another transducer, the second like F#'s type downloader thing that can transduce over unknown data

1:16 Clarice: You can't map over a future in clojure?

1:16 abaranosky: I hadn't read the implementation of reducers enough to know if it was collection-specific

1:16 Clarice: no

1:16 Clarice: futures are very thin wrappers around java Futures

1:17 Clarice: Why don't you force the future when you come across it?

1:17 TEttinger: panducers, which generate mexican pastries whenever you run them

1:18 omniducers, which run over your entire program

1:19 Clarice: abaranosky: As in, why doesn't the function you map with just call future? on its argument, and if true... you dereference its value.

1:19 abaranosky: Clarice: I'm not sure I understand your question?

1:19 it doesn't do that because CLojure doesn't work that way.

1:20 map would need to be specified as part of some Functor protocol

1:20 TEttinger: I like it, keep em coming

1:21 TEttinger: swearducers, which turn your program into swearjure and then overwrite the file

1:21 preducers, which run before you start the program to evade JVM startup

1:22 theoducers, which work if you believe they will

1:23 franzducers, which if the process is killed, start a world war

1:26 chronoducers, which manipulate how the rest of your program perceives time

1:27 schroducers, which are both running and not running simultaneously until dereferenced, at which point your program collapses

1:30 inducers, which make your program do things it would really rather not do

1:31 deducers, which are just a fancy name for core.logic

1:32 LANducers, which distribute your program over every gaming console in the immediate vicinity

1:33 treeducers, which brick your computer to stop wasting electricity

1:34 viducers, which are exactly like transducers but only work if you edit the code in vi or vim

1:35 biducers, which are simultaneously two different types of *ducer

1:35 triducers, which are simultaneously 3, and WHYducers, which are simultaneously all of them

1:38 I'm done ducing

1:38 justin_smith: duck duck transduck

7:38 $ping

7:38 lazybot: justin_smith: Ping completed in 0 seconds.

7:39 justin_smith: wow, exactly 6 hours, that wasn't on purpose

9:28 luxbock: when I use (read-line) in my Emacs nREPL I get prompted for input, but the function hangs after that

9:29 but the next time I call it, the it returns the thing I typed in the previous prompt

9:29 is there some way to make act normal?

9:35 justin_smith: works like normal here, what version are you using?

9:36 luxbock: Clojure 1.6.0, cider 0.8.0-SNAPSHOT

9:36 justin_smith: nrepl 0.2.0 doesn't have that bug (and the Clojure version should be irrelevant here)

9:36 maybe #clojure-emacs can help, or you could open an issue on the cider github?

9:37 luxbock: it works fine when I run it from `lein repl`

9:37 yeah I'll do that

9:38 justin_smith: I maen nrepl.el 0.2.0, in case that wasn't clear

9:38 some day cider will have a stable enough version that I'll feel like migrating, maybe

9:57 visof: quit

11:09 jonasen: Hi! Is it possible to configure the Clojure repl to not print the return value of a repl interaction?

11:09 like this: https://www.refheap.com/89224

11:10 and with "the clojure repl" I mean any of them (REPLy, the built in one, etc..)

11:13 justin_smith: so you don't want return values, only printouts? why not create a fifo, open the fifo for writing, and set that as *out*?

11:13 I don't know if anything like that exists in nrepl though

11:15 jonasen: justin_smith: not totally sure what you mean with "fifo"

11:15 justin_smith: a fifo is a special file that only exists for immediate IO

11:15 file-in-file-out

11:15 a kind of socket

11:19 never mind, it's simple than that

11:20 (defn quiet-repl [] (while true (eval (read)) (print "=> ") (flush)))

11:20 then run (quiet-repl)

11:20 for bonus points, instead of true, you can check an atom that tells it whether you are done with the quiet repl or not

11:21 jonasen: justin_smith: That's great! thank you.

11:21 justin_smith: that doesn't bind *1 / *2 etc. though, and it doesn't let you use the built in readline

11:21 but I guess it might be good enough

11:22 jonasen: and it breaks repl history

11:22 it's at least a starting point

11:22 justin_smith: yeah, the history is part of readline

11:22 make readline work, and you get history back

11:23 or you could just use rlwrap (if it exists for your platform)

11:24 jonasen: rlwrap works fine

11:25 justin_smith: pst still works

11:25 and *e

11:26 oh, I think pst only worked because we did not have a try catch, so the exception threw me back into a normal repl

11:27 so yeah, you may or may not want a try catch around that while

11:27 acagle1: exit

11:27 hostname

11:27 justin_smith: ls

11:27 lazybot: bin dev lost+found mnt proc root run sys

11:45 _ggherdov: hi. I am toying around trying to build a server that offers a REST api. I am following this tutorial from 2010, but the dependancies in project.clj are outdated http://mmcgrana.github.io/2010/08/clojure-rest-api.html

11:45 what was that site where I can check all latest versions of modules?

11:45 justin_smith: _ggherdov: you could use that as is, and then run "lein ancient" to list latest versions

11:45 no need to go to any website

11:45 _ggherdov: ok thanks justin_smith

11:46 justin_smith: np

11:47 also, you could start with "lein new compojure my-app"

11:47 and then adapt that result to the tutorial

11:47 _ggherdov: ok

11:47 justin_smith: that would be much less work actually

11:47 though lein ancient is good if you have an actual project to update, and not just a tutorial to follow

11:49 also, best of luck, and don't be shy to come back with any questions, this is channel is very open to newcomers to the language, and many of us have professional experience making clojure REST services (myself included)

11:50 _ggherdov: justin_smith: thanks!

12:56 jdkealy: in om, if i had a root view that dispatched main-view routes (and had the nav-bar up top), and if i transact on one of the views that it calls, is there any way to get the views it calls to update on an om/transact without having the parent dispatcher view also re-update ?

12:59 rbolkey: has anyone written a transit handler (assuming it's possible) for writing datomic EntityMaps?

13:31 jumblemuddle: Probably a old question around here, but I'll ask it anyways. As far as I can tell there are two main web servers for clojure (compojure and ring). Are there any benefits to learning one over the other? I know that I can probably easily migrate to a different one in the future, but I figured I'd ask.

13:31 llasram: jumblemuddle: compojure is a routing library built on top the ring abstraction

13:31 And neither are servers

13:32 jumblemuddle: Oh, then I'm definitely lost. Is compojure the standard then?

13:32 llasram: Ring an abstraction for describing HTTP requests and responses as (mostly) just Clojure data. This lets HTTP service handlers just be plain functions which accept request data and return response data

13:33 Compojure is a library which lets you build a handler composing other handlers, choosing the backing handler to dispatch to based upon routing criteria in the request (such as the request path)

13:34 Pretty much everything in the Clojure Web ecosystem uses Ring, and there's a spec describing how HTTP requests and responses map to Clojure data for ring

13:35 Compojure is the defacto standard routing library, but there are others

13:36 jumblemuddle: Alright, so compojure is a web framework? I've seen a lot of other clojure web frameworks. (Pedestal?) I just want to make sure I'm starting off on the right track.

13:36 justin_smith: Compojure is more of a utility than a framework

13:37 llasram: Clojure doesn't really have a standard end-to-end web framework. For the most part there are lots of little libraries speaking common abstractions, which you then glue together yourself

13:37 justin_smith: the f-word is not super popular in the clojure world

13:37 llasram: Pedestal is its own thing, not built on top of Ring

13:37 The closes thing to a common-core Web framework is probably Luminus http://www.luminusweb.net/

13:38 But not even really as Luminus itself -- more that the libraries it glues together are (generally) the most popular

13:38 jumblemuddle: Alright, thanks. I think I'm understanding it now. So, starting off with compojure is a good idea?

13:38 llasram: It's definitely a good place to start

13:39 I'd honestly start with plain Ring. You probably won't use it to build full applications on its own

13:39 justin_smith: jumblemuddle: also if for some reason you really miss ORM RoR / Django style development, Caribou is out there (I contributed extensively to it, though I would never have made something like that from scratch - it was made as an RoR replacement by a previous employer of mine)

13:39 llasram: But it'll give you an understanding of the underlying abstractions

13:40 jumblemuddle: llasram: That seems like a good idea. I'll go look into that.

13:40 justin_smith: plain ring is a good idea; yeah, routing is pretty plugable, and for your first couple simple projects you can just use a regex or something

13:40 jumblemuddle: justin_smith: Interesting, I'll look into that.

13:41 ToBeReplaced: lots of routers available and they all do things slightly differently, optimized for slightly different use cases; i think the most basic is clout for "i just want to ship"

13:41 justin_smith: jumblemuddle: it's great for an agency wanting to RaD push out yet another CMS / SQL backed site (comes with a web based admin interface out of the box), but may be a bad way to actually learn clojure

13:42 jumblemuddle: Ya, I think I'll start with the lower level stuff first, so I'll actually learn how it's all working.

13:44 justin_smith: also Caribou has a different use case than most clojure web libs, for example no clojure syntax in the templates and no clojurescript (it is assumed the frontend guys don't do clojure, but the backend do -- tailored to the dynamics of our particular company)

13:45 as opposed to nice things like enlive that you can use if the same person developing the page markup also does clojure

13:45 or garden

13:45 etc.

14:02 jdkealy: how can i tell in should-update exactly what has changed in a component in om ?

14:11 m-r-r: Hello

14:15 luxbock: I'm a bit confused of where the type-hint for a functions return value goes

14:15 before or after the function name?

14:16 m-r-r: I have two strings, i'm wondering how i can get the longest substring at the beginning of both strings

14:17 oskarkv: m-r-r you mean that they share?

14:18 llasram: ,(count (take-while true? (map = "foobar" "foobaz")))

14:18 clojurebot: 5

14:18 m-r-r: oskarkv: Yes. e.g. is the strings are "foobaz" and "foobaz", the function would return "foo"

14:18 oskarkv: m-r-r "fooba" :p

14:18 justin_smith: ,(apply str (map first (take-while (fn [[a b]] (= a b)) (map list "spamtastic" "spamalot"))))

14:18 clojurebot: "spam"

14:18 justin_smith: there is probably a better way to do that

14:18 m-r-r: oskarkv: yes x-D

14:20 justin_smith: ,(apply str (map first (take-while #(apply = %) (map list "spamtastic" "spamalot" "space out")))) ; varargs version

14:20 clojurebot: "spa"

14:20 m-r-r: Wow. In fact i didn't knew (map) could take multiple lists.

14:22 justin_smith: The second code is just what i was looking for, thanks :-)

14:24 justin_smith: it will be less gee-wiz-clojure-sure-is-elegant and more performant if you combine the two maps into one, even more so if you calculate an index for a substring and not use map in the first place

14:25 but if you don't need the best possible performance, at least it will be correct :)

14:30 ben_vulpes: i'm considering writing a page counter backed by datomic using db fns to increment the counter. i'm fairly confident that i should be able to get the value of that counter over an arbitrary range as well by traversing the transaction - does anyone see any problems with this approach?

14:31 spam in #clojure again...

14:35 justin_smith: ben_vulpes: you could also do it in regular sql, even calculating the number of requests in a date range server side, with a simple table having a single timestamp column and nothing else

14:35 not that this is likely to be performance critical of course

14:37 ben_vulpes: justin_smith: not a bad idea. this is for an existing datomic project though.

14:37 justin_smith: in that case I don't see a downside to your plan at all

14:37 ben_vulpes: but now that you mention it a "view" attr consisting of an instant might be a better model.

14:38 justin_smith: you could also have a path/query parameter, so you could get custom data for the whole site, or a single blog post or service, or whatever

14:38 ben_vulpes: that's also a good idea, although there are other constraints that will help me infer that information.

14:39 each venue only shows an ad of one size, so tracking per-venue views is probably adequate.


14:40 justin_smith: adequacy and flexibility, the schylla and charybdis of programming

14:40 ben_vulpes: {venue-entid :van.venue/pageview (.toDate (time/now))}, something like that.

14:42 thanks justin_smith!

14:59 m-r-r: What is an "ISeq" ?

15:00 TEttinger: m-r-r, the interface that all clojure seqs implement in the Java implementation code

15:00 Jaood: m-r-r: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java

15:00 m-r-r: TEttinger: but what is a seq ? Is it an s-expr ?

15:01 justin_smith: m-r-r: it's a thing that implements ISeq, of course :)

15:01 TEttinger: m-r-r, uh, maybe read up on the seq abstraction on the clojure site before getting into the java implementation

15:02 justin_smith: m-r-r: a seq is a sequential datatype where you can do things like "add an item" or "go through the items in order"

15:02 m-r-r: Ah ok :-)

15:03 justin_smith: by implementing ISeq, that means that a bunch of clojure functions will know how to use your data

15:03 (things like map, filter...)

15:04 m-r-r: So, if i have an error "Don't know how to create ISeq form: java.lang.Character", it means the software expected an array or a list, and got a character ?

15:04 justin_smith: array, list, vector, something like that, yeah

15:04 you can even seq a map or set

15:05 ,(seq #{1 2 3 4})

15:05 clojurebot: (1 4 3 2)

15:05 TEttinger: m-r-r, an example that causes that error: ##(map str \c)

15:05 lazybot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Character

15:05 justin_smith: ,(seq "or a string for that matter")

15:05 clojurebot: (\o \r \space \a \space ...)

15:05 TEttinger: m-r-r, an example of one way that doesnt cause that, ##(map str [\c])

15:05 lazybot: ⇒ ("c")

15:06 m-r-r: Ok, i think understood :-) thanks

15:16 arohner: what was the name of the other clojurescript repl project?

15:16 not austin, but ...?

15:16 martinklepsch: weasel

15:16 arohner: thanks!

16:39 there was a blog post that came out last week about using Om with non-react JS. anyone have a link, or remind me something to google for?

16:39 augustl: can (import) do static imports, or even better, :refer style static imports?

16:39 arohner: augustl: wdym by 'static' import?

16:40 rhg135: where class fields have global symbols resolving to them

16:41 arohner: huh? import a single field from a class?

16:41 rhg135: basically

16:42 augustl: arohner: java style static imports

16:43 justin_smith: augustl: the closest thing I think is (def PI Math/PI)

16:43 and we have no import * at all

16:44 (though if you really wanted it that much one could clearly do that via a macro and some reflection)

16:44 arohner: hrm, java.lang.reflect.Method is marked final

16:44 otherwise after IFn becomes a protocol, you could extend it

16:45 final is such a terrible idea

16:45 augustl: justin_smith: I see

16:45 justin_smith: you'd probably want a ^:const metadata on a def like that too

16:45 Bronsa: arohner: what has final have anything to do with protocols?

16:46 arohner: Bronsa: ah, you're right. I'm mixing up my bugs

16:46 Bronsa: anyone got spammed by nanaima here?

16:46 arohner: Bronsa: yes

16:48 justin_smith: Come to think of it, a macro that turns (import-fields Math PI E INFINITY) into (do (intern *ns* PI Math/PI) (intern *ns* E Math/e) (intern *ns* INFINITY Math/INFINITY)) would not be so hard

16:48 Bronsa: justin_smith: there was already something like that in old contrib

16:48 justin_smith: Bronsa: not surprised at all

16:49 of course this would only be for fields, not methods

16:49 thesaskwatch: Hi, I have a question .. why -main function starts with minus?

16:49 Bronsa: justin_smith: why not methods?

16:50 justin_smith: Bronsa: The reflection gets trickier. I guess you could still do it after all.

16:50 Bronsa: justin_smith: it wouldn't that hard, really

16:50 arohner: thesaskwatch: if you use (:gen-class), that indicates 'main' should be a method on the generated class

16:50 justin_smith: OK

16:50 Bronsa: it would not be as trivial as the macro that defines constants from static fields though

16:51 Bronsa: justin_smith: right

16:51 thesaskwatch: arohner: thanks :)

16:53 alxlit: hello, i've been toying around with an asset pipeline with clojure-ish sensibilities

16:53 i've got a working prototype and wanted to get some feedback, github.com/alxlit/venturi

16:54 i.e. it's not a sprockets implementation

16:58 arohner: alxlit: the readme could use more info on how it's different from existing solutions, why I should pick it, etc

16:59 augustl: hmm, cheshire blows up when generating SMILE for a byte array

17:00 as in, (cheshire.core/generate-smile {:body my-byte-array :status :ok})

17:00 justin_smith: augustl: that's odd, because smile was invented by the jackson people, and cheshire is a wrapper for jackson

17:01 augustl: getting a JsonGenerationException, Cannot JSON encode object of class: class [B: [B@40b98fb

17:03 tried passing a ByteArrayOutputStream just for laughs, same problem there

17:03 time to find another format I guess..

17:03 justin_smith: hmm - I see docs of generating byte-arrays from smile, but not for encoding them into smile

17:04 augustl: yeah, same :)

17:05 the smile format itself seems to support it - http://wiki.fasterxml.com/SmileFormatSpec#Token_class:_Misc.3B_binary_.2BAC8_text_.2BAC8_structure_markers

17:05 justin_smith: augustl: look into cheshire.generate/add-encoder

17:05 that should do your trick

17:05 (you would need to also add a decoder on the other end, of course)

17:24 augustl: justin_smith: transit to the rescue :)

17:26 justin_smith: oh, of course

17:27 augustl: it's only being used internally for talking between services so I can use whatever I want ;)

18:03 how do you do MyClass.class with java interop?

18:04 llasram: ,String

18:04 clojurebot: java.lang.String

18:04 llasram: augustl: Just the bare class name refers to the class object

18:04 augustl: ah

18:06 hmm, will that work for a signature like java.lang.Class<T> type ?

18:06 just passing a bare class yields a "No matching method found" error

18:06 llasram: More context?

18:06 augustl: trying to invoke this https://code.google.com/p/metadata-extractor/wiki/GettingStarted

18:07 in particular, metadata.getDirectory(ExifSubIFDDirectory.class);

18:07 (.getDirectory my-metadata com.drew.metadata.exif.ExifSubIFDDirectory) throws "java.lang.IllegalArgumentException: No matching method found: getDirectory for class java.lang.Class"

18:08 llasram: Sounds like you `my-metadata` identifier refers to a class instead of an instance

18:09 augustl: good point, perhaps it's a threading macro gone wrong

18:09 llasram: The basic structure you've posted is right

18:31 justin_smith: any x() is just x followed by ()

18:37 guest43: justin_smith: yeah. got that much. need a way to ensure one function has completed before next is invoked. Single-threaded execution...

18:38 justin_smith: let and fn both have implicit do blocks

18:38 guest43: (do (1st-fn) (then-2nd-fn) (only-after-first-two-complete-call-third-fn) )

18:38 justin_smith: most things in clojure are actually sequential

18:39 ,(let [a 0 b (inc a) c (inc b)] (print a b c) (print a b) (print a))

18:39 clojurebot: 0 1 20 10

18:40 justin_smith: ok, lack of spaces actually makes that weirder than it should be

18:41 thesaskwatch: how to access java style field: Field.Store.YES .. how to translate this to clojure? Field/Store/YES doesn't work.

18:41 SagiCZ1: hi

18:41 bbloom_: thesaskwatch: you can only have one slash in a symbol

18:42 thesaskwatch: symbols have two parts: a namespace and a name

18:42 SagiCZ1: in brave clojure there is thsi sentence "You'll learn how to create new functions with apply,partial, and complement." is really "apply" in the same group as partial and complement?

18:42 llasram: thesaskwatch: Is `Store` an inner class of `Field`?

18:42 bbloom_: thesaskwatch: the namespace may be a classname, and inner classes are separated with $ (which is also true of java internals)

18:42 thesaskwatch: bbloom_: so .. doing this twice should work? Not sure .. I don't have source code.

18:42 llasram: thesaskwatch: If so: Field$Store/YES (after importing Field$Store)

18:43 bbloom_: thesaskwatch: inner classes in java are actually compiled to just specially named normal classes

18:43 thesaskwatch: bbloom_: llasram: thanks .. I'll check it

18:43 I did have to import Field$Store .. but after this it worked .. thanks :)

18:44 justin_smith: SagiCZ1: they all create new functions

18:44 err.. I guess apply doesn't never mind

18:49 virtuous_sloth: Hello, I have a question about the difference between a bare list and a (list) list

18:50 (type '(1 2 3)) => clojure.lang.PersistentList and (type '(list 1 2 3)) => clojure.lang.PersistentList

18:51 but (second (list 1 2 3)) => 2 while (second (1 2 3)) => ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user/eval125 (NO_SOURCE_FILE:39)

18:52 SagiCZ1: i recently read about how lazy sequences work and that they actually produce chunks of their elements 32 pieces in each chunk... but how would this behavior work if the function that creates the next lazy element takes some large amount of time > 5 sec? would i have to wait 32 * 5 sec before clojure constructs one chunk and only then i can get the first element i wanted?

18:52 virtuous_sloth: Is this just a artifact of the inability to consistently parse a bare list as a list? Requiring an explicit list construct for those cases?

18:53 hyPiRion: SagiCZ1: Not necessarily. Some things are chunked, others are not.

18:54 SagiCZ1: hyPiRion: how would i know? for example i create my lazy sequence by using the lazy-seq function..

18:54 justin_smith: virtuous_sloth: that is not what actually happened

18:54 err, I mean 1 is not a function

18:54 hyPiRion: ,(first (map #(do % (print \.)) (range 10)))

18:54 clojurebot: ..........

18:54 hyPiRion: ,(first (map #(do % (print \.)) (iterate inc 1)))

18:54 clojurebot: .

18:55 hyPiRion: SagiCZ1: ^ I test it out like that usually.

18:55 justin_smith: virtuous_sloth: also '(list 1 2 3 4) is a list of 5 elements, one function and four numbers

18:55 SagiCZ1: hyPiRion: ok so you test it by having the function do some side effect right? (aka printing ".")

18:55 hyPiRion: SagiCZ1: right

18:56 at some point you know what's going to be chunked and what isn't though. Using lazy-seq is not chunked

18:56 err, the result of lazy-seq is not chunked, is what I meant.

18:56 SagiCZ1: hyPiRion: i see..

18:57 hyPiRion: i guess its chunked wherever it would make sense

18:57 but it also means that any lazy sequences shorter than 32 elements dont actually have any benefits over non lazy sequence

18:57 justin_smith: ,,(let [chunksize (atom 0)] (first (map #(do % (swap! chunksize inc)) (range 100))) @chunksize)

18:57 clojurebot: 32

18:58 justin_smith: I guess not giving range an argument would be more elegant

18:58 SagiCZ1: ,(range)

18:58 clojurebot: (0 1 2 3 4 ...)

18:58 SagiCZ1: justin_smith: this explained atoms and swap! to me :)

18:59 justin_smith: oh, good

18:59 SagiCZ1: however i should strive to use non-side-effect functions in "map" or "lazy-seq" .. is that correct?

18:59 justin_smith: yes

19:00 this uses side effects because it is measuring side effects

19:00 in pure functional code, chunk size is irrelevant

19:00 (for correctness, not resource usage, obviously)

19:00 SagiCZ1: justin_smith: could you elaborate on why would it be irrelevant?

19:00 ok

19:00 that cleared it up

19:01 off topic - do you guys ever sleep? i've been here in all kinds of different time-zones and i still see the same names.. except amalloy :)

19:02 justin_smith: I leave my client logged in, and browse scrollback

19:02 many people have virtual machines that they leave connected and logged in

19:02 SagiCZ1: well i didnt mean "logged in" i meant actually participating in conversation ..

19:02 amalloy: and others use a bouncer

19:03 SagiCZ1: ok amalloy is here too

19:03 justin_smith: ahh - well, programmers keep erratic hours don't we

19:03 SagiCZ1: amalloy: as in http://cdn5.droidmatters.com/wp-content/uploads/2012/02/bouncer.jpg ?

19:03 akurilin: quick question: does anybody know if there's a way of enforcing "at least one of these optional keys has be present" in prismatic's Schema, within Schema itself and not as a separate check?

19:04 justin_smith: SagiCZ1: http://en.wikipedia.org/wiki/BNC_(software)

19:05 SagiCZ1: ok.. close enough

19:07 akhudek: Looking for a highly available session store. Aphyr, shows all the solutions are faulty. Yay!

19:09 virtuous_sloth: justin_smith: If I understand you correctly, then the list function wraps up an actual clojure list such that partner functions list first and second can operate on them?

19:11 justin_smith: virtuous_sloth: no, it creates a list

19:11 ,(list 1 2 3)

19:11 clojurebot: (1 2 3)

19:12 justin_smith: virtuous_sloth: the tricky part is quoting anything parenthisized also makes a list (instead of an invocation of the first item)

19:12 ,'(list 1 2 3)

19:12 clojurebot: (list 1 2 3)

19:13 justin_smith: that list contains the list function inside it

19:13 ,'(+ 1 2 3)

19:13 clojurebot: (+ 1 2 3)

19:13 justin_smith: and that one the + function

19:13 (well really the symbols, which resolve to the functions...)

19:14 virtuous_sloth: I think I understand now.

19:15 thanks

19:19 justin_smith: virtuous_sloth: try out some corner cases in the repl, see if various things really do what you expect, and when they don't, find out why

19:19 clojure is good for exploration like that

19:19 AeroNotix: s/clojure/anything with a decent repl/g

19:20 virtuous_sloth: I see that its the difference between a list being evaluated and appearing as pure data... I think I was thrown off by the tutorial suggestion to use (type 'foo) to tell me the type of an object

19:21 justin_smith: yeah, 'foo is a symbol

19:21 ,(type '1)

19:21 clojurebot: java.lang.Long

19:21 justin_smith: ,(type 'foo)

19:21 clojurebot: clojure.lang.Symbol

19:21 justin_smith: ,(type 'clojure.core)

19:21 clojurebot: clojure.lang.Symbol

19:22 virtuous_sloth: err, bad terminology, the type of whatever the text foo is... so I expected (second (1 2 3)) to be able to operate on the list (1 2 3) without understanding that it first tries to execute (1 2 3)

19:23 justin_smith: yeah, lisps are usually simpler than you first expect them to be, coming from another language family

19:23 but that simplicity has benefits too

19:24 for example, if I see matched delimiters of any kind, I can figure out what their contents represent without looking outside those delimiters

19:24 which is not true in more conventional languages

19:24 (there are things that fudge those rules, but they are few in number)

19:25 virtuous_sloth: so (list 1 2 3) is an almost-empty function that returns the list

19:25 justin_smith: it's not a function, it's a function call

19:25 there are so many things that implicitly or explicitly create sequences, seeing list use directly in clojure is actually sort of rare

19:26 on the other hand (partial list 1 2 3) is a function :)

19:26 virtuous_sloth: yes, I just find it easier to write the use of the function "list" than to say "list" is regular prose because it is ambiguous when conversing

19:27 <whosh> I'm sure that's a funny joke but I don't know enough to appreciate the humour

19:27 justin_smith: ,(map (partial list 1 2 3) (range 3))

19:27 clojurebot: ((1 2 3 0) (1 2 3 1) (1 2 3 2))

19:29 virtuous_sloth: Thanks Justin... I'm just a systems guy whose programming experience is fairly limited

19:30 justin_smith: OK, you can ignore that fancier stuff if you are not ready yet

19:30 try a site like 4clojure if you haven't yet

19:30 or maybe clojure koans

19:30 ~books too

19:30 clojurebot: Gabh mo leithscéal?

19:30 justin_smith: ~books

19:30 clojurebot: books is book

19:30 justin_smith: ~book

19:30 clojurebot: book is http://clojurebook.com/ http://joyofclojure.com/

19:30 virtuous_sloth: Yes, just a matter of putting in the time ;-)

19:30 justin_smith: (one of these days I'll know how to use the bot properly)

19:32 virtuous_sloth: I was working through Closure from the Ground Up at http://aphyr.com/

19:32 justin_smith: cool, that's a good one

19:33 virtuous_sloth: systems as in OS or as in models and information flows?

19:34 virtuous_sloth: OS, integration... my education is physics though

20:01 BAMbanda: If I want to play with a library from clojars from a repl, but don't want to use lein to build out a full project structure, how can I do this?

20:01 like if I wanted to pull in a networking library from the repl fired by "java -cp clojure-1.6.0.jar clojure.main"

20:03 justin_smith: BAMbanda: you add the apropriate jars to the classpath

20:03 BAMbanda: I find it useful to use lein to create a non-project repl, then have alembic in my profiles.clj as a dependency. I can use alembic to resolve, potentially download, and then load jars at runtime.

20:04 or you can just know all the jars you want ahead of time, and put them all in the java classpath when you invoke clojure

20:04 https://github.com/pallet/alembic

20:04 BAMbanda: justic_smith, sweet thanks

21:08 xeqi: BAMbanda: there is also https://github.com/rkneufeld/lein-try

21:09 imanc: would you say that clojure's let form is similar to python's with ?

21:10 hmmm - just trying to see the purpose of 'let' - I see what it does, I just don't see why it's all that important

21:11 justin_smith: imanc: def is only for globals

21:11 you need something that creates per-form bindings

21:11 imanc: ahhh globals as per the current namespace?

21:12 gfredericks: and defs should be immutable from most of your code's perspective

21:12 justin_smith: yes, so if two threads call your function, and the function uses def, your code will likely break

21:12 gfredericks: i.e., it's unidiomatic to redef something as part of an algorithm or application logic

21:12 justin_smith: gfredericks: arguably that should go for globals in any language

21:13 gfredericks: justin_smith: no argument there

21:14 justin_smith: imanc: don't use def inside a function, any more than you would redefine a class's definition inside a python method

21:14 imanc: justin_smith: if two threads call my function and the function modifies def'd symbol, it'll break?

21:14 justin_smith: imanc: because there is only one copy of the def

21:14 imanc: ok, good rule of thumb

21:14 justin_smith: your algorithm may or may not work any more

21:15 imagine if you had a python method that redefined your class, and it was possible to call it from two overlapping threads - would you expect anything sane to result from that?

21:15 imanc: nope

21:15 makes sense

21:18 justin_smith: luckily for python, its threads cannot actually overlap except at function boundaries - mutation of any sort outside of a local context would be insane otherwise. But in clojure threads can fully overlap, unless you explicitly lock some code body. But luckily we also don't redefine globals at runtime, and we use immutible datatypes, so we can actually use that full concurrency to our advantage.

21:25 imanc: justin_smith: " But luckily we also don't redefine globals at runtime" So are you saying that a global def should not be redef'd?

21:26 justin_smith: right

21:26 except under very specific circumstances (first app startup / config, or at the repl to test new code)

21:27 in a production app, after the first minutes of startup time when configuration gets applied, no redefs happen in any of my code.

21:27 ever so rarely I use an atom for something that can be updated, but that's less commonly needed than you might think

21:28 lpvb: How do I access the enumerations of this nested static class? http://docs.oracle.com/javase/7/docs/api/javax/sound/sampled/AudioFormat.Encoding.html

21:28 imanc: let's say we're building a web app ... where data will change per request, such as the user agent, ip address, etc.

21:28 justin_smith: imanc: those are arguments provided by ring to your handler

21:28 lpvb: I tried AudioFromat/Encoding/PCM_SIGNED

21:28 justin_smith: they are not variables, they are function arguments

21:28 imanc: okay

21:29 justin_smith: imanc: because, for example, you can easily serve as many requests at one time within one app as you have cores on your machine

21:29 imanc: and if you do any disk IO, you can have more than that going on at a time even

21:29 if that data was mutable, how would simultanious requests even work?

21:29 imanc: yeh

21:29 It's slowly sinking in (emphasis on 'slowly')

21:30 justin_smith: sure

21:30 lpvb: got my own answer, use $ to access inner static classes

21:30 justin_smith: imanc: it's actually provable that anything you can do via mutating a variable can be done via recursion and a different function argument

21:30 (modulo the difference in resource usage, if any, of course)

21:31 so instead of changes of state, you have function calls with different arguments

21:31 imanc: right

21:31 justin_smith: in ring, to go back to that example, the request is a big map

21:32 it's trivial to take your mutation of state logic that accesses variables, and instead get each value from a big map

21:32 imanc: yeh in a ways it seems like a reasonably trivial change

21:33 justin_smith: that request map has the client IP, any query data, and also you can define middleware that adds / removes / augments / cleans up your data before the handler sees it

21:34 or even an additional middleware that looks at the response you create (which can be a string, or a stream, or a map, or whatever) and does any post-processing you need

21:34 these things are *possible* when you do things via mutation, but they are much harder to get right

21:38 for another example I like: unit testing with clojure.test. A test is just a function. You can run any test by calling the function it defines. You can redefine the test by reloading the definition. You can make pre and post actions by composing with other functions. It turns out that most of the weird things that testing frameworks need to do in a normal language are trivial to do with standard clojure idioms.

21:40 the way I like to think of it: immutibility is a restriction that gives you extra power, kind of like airbags and seatbelts and bumpers make it possible to drive at highway speeds, immutibility means you can do fancy things like concurrency and high level code transformations without breaking everything.

21:42 lpvb: immutability is like defining a mathematical axiom so you can further your theory

21:42 justin_smith: sure, you really wouldn't want to mutate axioms on the fly either

21:42 that is a good building block metaphor to be sure

21:43 gfredericks: does anybody know of a way to adapt paredit to work with data literals?

21:43 justin_smith: gfredericks: which ones give you problems?

21:43 imanc: I guess imperative code is going to be closer to the underlying hardware/low level OS calls though? And if so, is there a performance to FP?

21:43 * performance hit to FP, particularly clojure?

21:44 gfredericks: justin_smith: {forward,backward}-sexp

21:44 not a big deal in normal life but e.g., the align-cljlet lib breaks because of it

21:44 justin_smith: imanc: sure- clojure can't beat the performance of raw java, but also consider that if code is incorrect, it doesn't matter how fast it is any more

21:45 and fp in general is pretty good at correctness

21:45 TravisD: Is there a command to view the current grammar?

21:45 er.. wc sorry :)

21:46 justin_smith: TravisD: http://ia.media-imdb.com/images/M/MV5BMjEyNjkxODM5N15BMl5BanBnXkFtZTcwMTU3NDE1Mg@@._V1_SY317_CR9,0,214,317_AL_.jpg :P

21:46 TravisD: heh, I dont understand

21:47 justin_smith: his name is Kelsey Grammer

21:47 TravisD: lol

21:47 justin_smith: you just viewed him

21:47 TravisD: And he was current.

21:47 justin_smith: relatively, at least

21:49 imanc: one more thing about performance - since you brought up python before, there are few examples of python being as fast as clojure

21:49 imanc: wow

21:50 justin_smith: clojure is closer to java performance than python is to clojure performance

21:50 clojurebot: Roger.

21:50 imanc: that's good to know

21:50 justin_smith: python is very poorly designed from a performance perspective though, so it's not a super fair comparison

21:51 imanc: there is pypy

21:51 justin_smith: ~clojure

21:51 clojurebot: "[Clojure ...] feels like a general-purpose language beamed back from the near future."

21:51 turbofail: python's better designed for performance than ruby, to some extent

21:51 imanc: ruby is horrid

21:51 nice language, ish, but speed wise...

21:51 justin_smith: imanc: pypy does not really compare even

21:52 turbofail: sure, it's faster than using an abacus too :)

21:52 imanc: How does clojure compare to counterparts e.g scheme, erlang?

21:52 justin_smith: how, performance wise?

21:53 imanc: yep

21:53 turbofail: clojure ime has been faster than most scheme implementations, dunno about erlang

21:53 justin_smith: there are a few faster schemes (and many slower ones). Erlang is also slow (though I don't know how it compares to eg. python)

21:53 turbofail: racket can kick clojure's ass though

21:53 imanc: i know scheme is also built on java

21:53 TEttinger: common lisp is probably faster on single-core, but slower multi-core

21:53 justin_smith: it can be

21:53 turbofail: justin_smith: i haven't had that experience

21:54 justin_smith: really? I could be way off base on that I guess

21:54 imanc: A company I'm probably going to start working for as a python dev, are using clojure - hence my interest in it :)

21:54 p_l: ... performance comparisons between languages are usually useless

21:54 TEttinger: p_l, yeah good point

21:54 p_l: that said, certain languages are pretty much defined by their implementations, and those implementations make kicking their arses in speed easy

21:54 for example, Python

21:54 TEttinger: I will say, clojure can be tricky to optimize sometimes, and extremely easy others

21:54 justin_smith: p_l: certain designs are inherently bad for performance - the language definition itself can act as a bottleneck

21:55 p_l: it's not just one python impl, the semantics of python demand slowness

21:55 p_l: justin_smith: there's this funny old phrase about sufficiently smart compiler ;)

21:55 imanc: then there's the GIL

21:55 turbofail: justin_smith: dunno, i did a fairly idiomatic text processing thing in both clojure and racket and the clojure version was way faster

21:56 justin_smith: p_l: it would have to be a sufficiently wrong compiler, because python guarantees certain behaviors that are incompatible with good optimizations

21:56 TEttinger: I also have had fun times where the official racket IDE crashes if your program does

21:56 p_l: justin_smith: heh, haven't touched python in a long time, so I'll concede on that point ;)

21:56 imanc: justin_smith: can you give an example of the ways in which the python lang is incompatible with good optimsiation?

21:56 justin_smith: turbofail: racket has a very small core language, and a small compiled executable size, so I may just have been wowed by the small scale advantages :)

21:57 turbofail: sure, a racket program will start a lot faster

21:57 TEttinger: I'm guessing the dictionaries everywhere thing is bad for python

21:57 no lookup is direct, IIRC, but I don't use python

21:57 turbofail: i was processing a lot of crap though, so for my purposes throughput was way more important

21:58 p_l: TEttinger: technically you can elide them a bit, but that depends on not doing some magic nor hot patching

21:58 justin_smith: imanc: for a not totally official one, removing the global interpreter lockbreaks massive numbers of commonly used libraries

21:58 turbofail: though i think awk ended up being slightly faster than my idiomatic clojure program

21:58 imanc: there's also issues with obj.__dict__ which has been rectified in python 3.4 with a shared dict, and with __slots__ on earlier versions. But this results in enormous memory usage for large numbers of instances

21:58 turbofail: a less idiomatic version beat awk

21:58 imanc: justin_smith: yep, agreed

21:58 p_l: justin_smith: GIL is implementation detail (that is unfortunately embedded in anything that calls to native code, which means lots of code)

21:59 imanc: yeh it's a cPython issue

21:59 justin_smith: p_l: yes, as I said, not official limitation (but one everyone codes against)

21:59 not just cPython - it also messes with class initialization

22:00 unless you swap it out for per-class locks or something

22:02 imanc: if defs shoud only occur on the module level (not sure if that's the correct terminology) what is the purpose of defonce ?

22:02 justin_smith: also, I am not finding the details now (sorry), but there are also issues with what is redefinable at runtime (where Clojure takes the "it's possible to redefine it, but we don't promise anything doesn't break" route, python allows redefinition, which rules out massive numbers of optimizations

22:02 )

22:03 imanc: a module can be loaded multiple times

22:03 imanc: clojuer is very repl-centric

22:03 imanc: you edit a file, then load it into a repl again

22:03 imanc: ahhh

22:03 justin_smith: defonce means the next time, it doesn't get defined again

22:04 many oddities about clojure become totally understandable once you consider the fact that coding from a repl and loading and running files from a jar should have identical semantics

22:04 (with the big exception of gen-class of course)

22:05 gfredericks: and something else

22:05 justin_smith: which something else is that?

22:05 gfredericks: can't remember :)

22:05 justin_smith: I am sure there are a few examples

22:05 gfredericks: yeah

22:05 justin_smith: I mean protocols and defmethods don't play nicely with reloading

22:05 gfredericks: inevitably

22:06 justin_smith: but within one repl, they do just work if you don't redefine

22:06 and it's informative that we rarely run into these gotchas - which means they are dark corners and they don't affect us day to day

22:07 gfredericks: it's difficult to get a sense for how *ns* works at the repl

22:07 because it's always set to your repl's namespace. but when running non-repl code it's set to user I think

22:07 justin_smith: wait, how often would you use *ns* outside the repl?

22:07 ahh

22:07 gfredericks: depends on how confused you are about how it works :)

22:08 justin_smith: oh, of course

22:08 gfredericks: it's easy to assume it just always refers to the namespace you're typing in

22:08 justin_smith: that makes sense

22:08 brb, dinner

22:08 imanc: I thought ns needed to correlate with the file name/ directory structure?

22:09 justin_smith: ns declared in a file ns statement yes

22:09 but then there is *ns*

22:09 ,*ns

22:09 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: *ns in this context, compiling:(NO_SOURCE_PATH:0:0)>

22:09 justin_smith: err

22:09 ,*ns*

22:09 clojurebot: #<Namespace sandbox>

22:09 justin_smith: the current working namespace

22:09 which is a more repl-centric concept usually

22:10 unless you are trying to do something really weird

22:10 imanc: ahhh

22:11 justin_smith: you can easily declare and create namespaces that don't have any correspondign file via the repl - for example you can invoke ns there

22:11 gfredericks: I think of it as more about compile-time

22:11 in particular macros can use it effectively

22:11 justin_smith: ahh - I am kind of afraid of macros, so I can't address that part very well

22:11 anyway, actually going this time, brb

22:11 gfredericks: e.g., clojure.tools.logging uses it to pick the appropriate logger

22:12 otherwise it would have no idea what namespace you're calling from

22:12 imanc: I read something about haskell developers believing that lisp macros enable 'cowbow coding' and producing faulty dsl's.

22:14 I obviously don't have enough experience to comment either way, but my gut feeling is that it could easily be abused

22:14 gfredericks: there's a reason people yell at you while you write macros

22:15 but that doesn't mean we'd be better off without them

22:15 imanc: heh

22:16 gfredericks: most of clojure's control flow functionality is macros that you could have written yourself, and can write variants of

22:16 i.e., you are not depending on rich hickey having selected the perfect set of language features

22:17 imanc: yeh

22:17 kenrestivo: i like how rich put it "clojure is a consenting adults language"

22:18 gfredericks: clojure makes it easy for you to not overuse the messier parts of clojure :)

22:18 imanc: similar to the python statement re's the lack of class access modifiers "we're all consenting adults here"

22:19 i can imagine disregarding the "don't redefine symbols" you could write clojure that is somewhat imperitive

22:19 gfredericks: ,(def x 38)

22:19 clojurebot: #'sandbox/x

22:19 imanc: even if behind the scenes the same memory addresses are not being overwritten

22:19 gfredericks: ,(dotimes [n 4] (def x (inc x)))

22:19 clojurebot: nil

22:19 gfredericks: x

22:19 ,x

22:19 clojurebot: 42

22:20 imanc: oo

22:20 heh

22:20 gfredericks: here's a fun one

22:20 ,(defn y [] (def z 1))

22:20 clojurebot: #'sandbox/y

22:20 gfredericks: ,z

22:20 clojurebot: #<Unbound Unbound: #'sandbox/z>

22:21 kenrestivo: wat?

22:21 ,y

22:21 clojurebot: #<sandbox$y sandbox$y@1ae541e>

22:21 gfredericks: ,(y)

22:21 clojurebot: #'sandbox/z

22:21 gfredericks: ,z

22:21 clojurebot: 1

22:21 imanc: so z has local scope to teh function?

22:22 gfredericks: the weird part is that z exists at all before you call y for the first time

22:22 bbloom_: gfredericks: i guess the def is resolved during compilation?

22:22 actually, i know it is

22:22 imanc: yeh

22:22 bbloom_: oddly

22:23 gfredericks: it makes sense from a compilation perspective

22:23 the function has to contain a reference to the var

22:23 so it has to exist

22:23 wouldn't want to go checking that it exists every time you call it

22:24 imanc: it doesn't matter that this is weird because you're not supposed to do it anyhow

22:24 kenrestivo: what would be the use case for def'ing inside of a function body? seems fraught with danger to me.

22:24 gfredericks: I don't think there is one

22:27 bbloom_: if you had to do it, you'd use intern

22:27 (doc intern)

22:27 clojurebot: "([ns name] [ns name val]); Finds or creates a var named by the symbol name in the namespace ns (which can be a symbol or a namespace), setting its root binding to val if supplied. The namespace must exist. The var will adopt any metadata from the name symbol. Returns the var."

22:28 rhg135: what's the difference anyway

22:29 bbloom_: intern is a function

22:29 def is a special form

22:29 as a function, intern fully evaluates its arguments

22:30 rhg135: oh ic

22:30 bbloom_: but there isn't much need to be messing with that in normal programming anyway

23:06 ilargs: lets say you wanted to create a new type that has properties of both a vector and a map. how do you find out the clojure/clojurescript protocols you have to implement? browsing source or is there a doc somewhere.

23:07 justin_smith: ilargs: check out (doc deftype) in your repl

23:07 (it's way too long for here)

23:08 long story short, you can specify any number of protocols or interfaces in a deftype declaration, and specify the method implementations for each

23:09 ilargs: so i see the usual background and more detail which is always good. but for example, IPersistentVector, how do you kown which methods you have to define for it? or will compiling tell you which you are missing?

23:10 rhg135: isn't a vector an associative from ints to vals while maps are more general?

23:19 justin_smith: yes, and maps are unordered while vectors are ordered

23:19 Bird|otherbox: yeah, also, maps have amortized constant time lookup (as they're hashtables under the hood) while vector lookup is O(1), just like a diamond is forever.

23:20 justin_smith: ilargs: actually I kind of wish protocols and interfaces had doc strings the way vars do

23:20 kristof: ...What exactly is the difference between "amortized constant time" and O(1)?

23:20 justin_smith: there may be a better way to do it, but I tend to look up the implementation for a protocol or the javadoc for an interface

23:20 kristof: I thought the point of O(1) asymptotic behavior was that the value is constant.

23:21 justin_smith: I think amortized accounts for worst case

23:21 kristof: Hrm. Gotcha.

23:21 justin_smith: while O(x) will sometimes specify the best or average

23:22 "At the heart of the method is the idea that while certain operations may be extremely costly in resources, they cannot occur at a high enough frequency to weigh down the entire program because the number of less costly operations will far outnumber the costly ones in the long run, "paying back" the program over a number of iterations."

23:22 so it's not just worst case, but overall actual usage?

23:22 http://en.wikipedia.org/wiki/Amortized_analysis

23:24 kristof: effective operational complexity, then

23:24 justin_smith: sounds right, not sure

23:27 ilargs: i have a lot to read!

23:27 thanks guys.

23:27 justin_smith: np

23:27 good luck

Logging service provided by n01se.net