2014-08-16
| 01:03 | eric_normand | anyone going to the conj want to split a room? |
| 01:04 | Clarice | Yes, split a room with a total stranger you meet on IRC. |
| 01:05 | abaranosky | Clarice: be a bummer why don't ya |
| 01:05 | Clarice | :) |
| 01:05 | technomancy | we're like a big family in #clojure |
| 01:05 | technomancy | ~group hup |
| 01:05 | clojurebot | I don't understand. |
| 01:05 | Clarice | (inc clojurebot) |
| 01:05 | lazybot | ⇒ 42 |
| 01:06 | abaranosky | best way to meet people |
| 01:06 | Clarice | Is that a fixed number? |
| 01:06 | Clarice | Is that a fixed number? |
| 01:06 | Clarice | (inc clojurebot) |
| 01:06 | lazybot | ⇒ 43 |
| 01:06 | abaranosky | or die |
| 01:06 | Clarice | Oh! No, better keep it at 42. |
| 01:06 | Clarice | (dec clojurebot) |
| 01:06 | lazybot | ⇒ 42 |
| 01:06 | abaranosky | how bad could it be |
| 01:06 | technomancy | some day we hope to have the technology to help you understand, clojurebot |
| 01:09 | TEttinger | eric_normand: try couchsurfing? |
| 01:09 | abaranosky | what do you all think of transducers? |
| 01:09 | TEttinger | they're just as much people as cisducers |
| 01:09 | Clarice | Hahahahah |
| 01:09 | Clarice | abaranosky: I think they're pointless. |
| 01:10 | TEttinger | I haven't used reducers yet, but I see their point |
| 01:10 | eric_normand | TEttinger: hmm. now that would be a total stranger. |
| 01:10 | TEttinger | eric_normand, yes but #clojure doesn't have reviews of strangers |
| 01: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 |
| 01:11 | abaranosky | would it be possible to make them work with other things like futures or promises? |
| 01:13 | TEttinger | abaranosky: megaducers in 1.8.0 |
| 01:13 | Clarice | A promise is not a collection. |
| 01:13 | TEttinger | we're just going to get ducing all over |
| 01:13 | TEttinger | every version a new *ducer |
| 01:14 | mthvedt | i demand recursively enumerable ducers |
| 01:14 | TEttinger | duceducers |
| 01:14 | TEttinger | paraducers, xenoducers |
| 01:15 | mthvedt | nonconstructable ducers |
| 01:15 | Clarice | epiducers |
| 01:15 | abaranosky | yeah sucks... I wish if they'd made a general abstraciton it could've been truly general |
| 01:15 | abaranosky | like in other languages you can map over a future, which is what I was thinkin gof |
| 01: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 |
| 01:16 | Clarice | You can't map over a future in clojure? |
| 01:16 | abaranosky | I hadn't read the implementation of reducers enough to know if it was collection-specific |
| 01:16 | abaranosky | Clarice: no |
| 01:16 | abaranosky | Clarice: futures are very thin wrappers around java Futures |
| 01:17 | Clarice | Why don't you force the future when you come across it? |
| 01:17 | TEttinger | panducers, which generate mexican pastries whenever you run them |
| 01:18 | TEttinger | omniducers, which run over your entire program |
| 01: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. |
| 01:19 | abaranosky | Clarice: I'm not sure I understand your question? |
| 01:19 | abaranosky | it doesn't do that because CLojure doesn't work that way. |
| 01:20 | abaranosky | map would need to be specified as part of some Functor protocol |
| 01:20 | abaranosky | TEttinger: I like it, keep em coming |
| 01:21 | TEttinger | swearducers, which turn your program into swearjure and then overwrite the file |
| 01:21 | TEttinger | preducers, which run before you start the program to evade JVM startup |
| 01:22 | TEttinger | theoducers, which work if you believe they will |
| 01:23 | TEttinger | franzducers, which if the process is killed, start a world war |
| 01:26 | TEttinger | chronoducers, which manipulate how the rest of your program perceives time |
| 01:27 | TEttinger | schroducers, which are both running and not running simultaneously until dereferenced, at which point your program collapses |
| 01:30 | TEttinger | inducers, which make your program do things it would really rather not do |
| 01:31 | TEttinger | deducers, which are just a fancy name for core.logic |
| 01:32 | TEttinger | LANducers, which distribute your program over every gaming console in the immediate vicinity |
| 01:33 | TEttinger | treeducers, which brick your computer to stop wasting electricity |
| 01:34 | TEttinger | viducers, which are exactly like transducers but only work if you edit the code in vi or vim |
| 01:35 | TEttinger | biducers, which are simultaneously two different types of *ducer |
| 01:35 | TEttinger | triducers, which are simultaneously 3, and WHYducers, which are simultaneously all of them |
| 01:38 | TEttinger | I'm done ducing |
| 01:38 | justin_smith | duck duck transduck |
| 07:38 | justin_smith | $ping |
| 07:38 | lazybot | justin_smith: Ping completed in 0 seconds. |
| 07:39 | justin_smith | wow, exactly 6 hours, that wasn't on purpose |
| 09:28 | luxbock | when I use (read-line) in my Emacs nREPL I get prompted for input, but the function hangs after that |
| 09:29 | luxbock | but the next time I call it, the it returns the thing I typed in the previous prompt |
| 09:29 | luxbock | is there some way to make act normal? |
| 09:35 | justin_smith | works like normal here, what version are you using? |
| 09:36 | luxbock | Clojure 1.6.0, cider 0.8.0-SNAPSHOT |
| 09:36 | justin_smith | nrepl 0.2.0 doesn't have that bug (and the Clojure version should be irrelevant here) |
| 09:36 | justin_smith | maybe #clojure-emacs can help, or you could open an issue on the cider github? |
| 09:37 | luxbock | it works fine when I run it from `lein repl` |
| 09:37 | luxbock | yeah I'll do that |
| 09:38 | justin_smith | I maen nrepl.el 0.2.0, in case that wasn't clear |
| 09:38 | justin_smith | some day cider will have a stable enough version that I'll feel like migrating, maybe |
| 09: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 | jonasen | like this: https://www.refheap.com/89224 |
| 11:10 | jonasen | 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 | justin_smith | 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 | justin_smith | file-in-file-out |
| 11:15 | justin_smith | a kind of socket |
| 11:19 | justin_smith | never mind, it's simple than that |
| 11:20 | justin_smith | (defn quiet-repl [] (while true (eval (read)) (print "=> ") (flush))) |
| 11:20 | justin_smith | then run (quiet-repl) |
| 11:20 | justin_smith | 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 | justin_smith | but I guess it might be good enough |
| 11:22 | jonasen | and it breaks repl history |
| 11:22 | jonasen | it's at least a starting point |
| 11:22 | justin_smith | yeah, the history is part of readline |
| 11:22 | justin_smith | make readline work, and you get history back |
| 11:23 | justin_smith | 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 | justin_smith | and *e |
| 11:26 | justin_smith | 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 | justin_smith | so yeah, you may or may not want a try catch around that while |
| 11:27 | acagle1 | exit |
| 11:27 | acagle1 | 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 | _ggherdov | 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 | justin_smith | no need to go to any website |
| 11:45 | _ggherdov | ok thanks justin_smith |
| 11:46 | justin_smith | np |
| 11:47 | justin_smith | also, you could start with "lein new compojure my-app" |
| 11:47 | justin_smith | 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 | justin_smith | though lein ancient is good if you have an actual project to update, and not just a tutorial to follow |
| 11:49 | justin_smith | 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 | llasram | 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 | llasram | 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 | llasram | 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 | llasram | 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 | llasram | The closes thing to a common-core Web framework is probably Luminus http://www.luminusweb.net/ |
| 13:38 | llasram | 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 | llasram | 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 | justin_smith | as opposed to nice things like enlive that you can use if the same person developing the page markup also does clojure |
| 13:45 | justin_smith | or garden |
| 13:45 | justin_smith | 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 | luxbock | 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 | m-r-r | 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 | justin_smith | 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 | ben_vulpes | 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 | justin_smith | 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 | ben_vulpes | each venue only shows an ad of one size, so tracking per-venue views is probably adequate. |
| 14:39 | ben_vulpes | FAMOUS LAST WORDS. |
| 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 | ben_vulpes | 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 | justin_smith | (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 | justin_smith | you can even seq a map or set |
| 15:05 | justin_smith | ,(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 | arohner | not austin, but ...? |
| 15:16 | martinklepsch | weasel |
| 15:16 | arohner | thanks! |
| 16:39 | arohner | 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 | justin_smith | and we have no import * at all |
| 16:44 | justin_smith | (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 | arohner | otherwise after IFn becomes a protocol, you could extend it |
| 16:45 | arohner | 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 | justin_smith | 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 | justin_smith | 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 | alxlit | i've got a working prototype and wanted to get some feedback, github.com/alxlit/venturi |
| 16:54 | alxlit | 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 | augustl | 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 | augustl | tried passing a ByteArrayOutputStream just for laughs, same problem there |
| 17:03 | augustl | 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 | augustl | 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 | justin_smith | that should do your trick |
| 17:05 | justin_smith | (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 | augustl | 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 | augustl | hmm, will that work for a signature like java.lang.Class<T> type ? |
| 18:06 | augustl | 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 | augustl | in particular, metadata.getDirectory(ExifSubIFDDirectory.class); |
| 18:07 | augustl | (.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 | justin_smith | ,(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 | bbloom_ | 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 | thesaskwatch | 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 | justin_smith | 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 | virtuous_sloth | (type '(1 2 3)) => clojure.lang.PersistentList and (type '(list 1 2 3)) => clojure.lang.PersistentList |
| 18:51 | virtuous_sloth | 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 | justin_smith | 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 | hyPiRion | at some point you know what's going to be chunked and what isn't though. Using lazy-seq is not chunked |
| 18:56 | hyPiRion | err, the result of lazy-seq is not chunked, is what I meant. |
| 18:56 | SagiCZ1 | hyPiRion: i see.. |
| 18:57 | SagiCZ1 | hyPiRion: i guess its chunked wherever it would make sense |
| 18:57 | SagiCZ1 | 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 | justin_smith | this uses side effects because it is measuring side effects |
| 19:00 | justin_smith | in pure functional code, chunk size is irrelevant |
| 19:00 | justin_smith | (for correctness, not resource usage, obviously) |
| 19:00 | SagiCZ1 | justin_smith: could you elaborate on why would it be irrelevant? |
| 19:00 | SagiCZ1 | ok |
| 19:00 | SagiCZ1 | that cleared it up |
| 19:01 | SagiCZ1 | 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 | justin_smith | 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 | justin_smith | ,(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 | justin_smith | ,'(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 | justin_smith | ,'(+ 1 2 3) |
| 19:13 | clojurebot | (+ 1 2 3) |
| 19:13 | justin_smith | and that one the + function |
| 19:13 | justin_smith | (well really the symbols, which resolve to the functions...) |
| 19:14 | virtuous_sloth | I think I understand now. |
| 19:15 | virtuous_sloth | 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 | justin_smith | 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 | justin_smith | ,(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 | justin_smith | but that simplicity has benefits too |
| 19:24 | justin_smith | 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 | justin_smith | which is not true in more conventional languages |
| 19:24 | justin_smith | (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 | justin_smith | there are so many things that implicitly or explicitly create sequences, seeing list use directly in clojure is actually sort of rare |
| 19:26 | justin_smith | 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 | virtuous_sloth | <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 | justin_smith | try a site like 4clojure if you haven't yet |
| 19:30 | justin_smith | or maybe clojure koans |
| 19:30 | justin_smith | ~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 | justin_smith | 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 | BAMbanda | 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 | justin_smith | 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 | justin_smith | 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 | justin_smith | 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 | imanc | 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 | justin_smith | 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 | justin_smith | 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 | imanc | 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 | justin_smith | except under very specific circumstances (first app startup / config, or at the repl to test new code) |
| 21:27 | justin_smith | 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 | justin_smith | 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 | justin_smith | imanc: and if you do any disk IO, you can have more than that going on at a time even |
| 21:29 | justin_smith | if that data was mutable, how would simultanious requests even work? |
| 21:29 | imanc | yeh |
| 21:29 | imanc | 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 | justin_smith | (modulo the difference in resource usage, if any, of course) |
| 21:31 | justin_smith | 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 | justin_smith | 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 | justin_smith | 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 | justin_smith | these things are *possible* when you do things via mutation, but they are much harder to get right |
| 21:38 | justin_smith | 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 | justin_smith | 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 | justin_smith | 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 | imanc | * performance hit to FP, particularly clojure? |
| 21:44 | gfredericks | justin_smith: {forward,backward}-sexp |
| 21:44 | gfredericks | 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 | justin_smith | and fp in general is pretty good at correctness |
| 21:45 | TravisD | Is there a command to view the current grammar? |
| 21:45 | TravisD | 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 | justin_smith | 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 | imanc | nice language, ish, but speed wise... |
| 21:51 | justin_smith | imanc: pypy does not really compare even |
| 21:52 | justin_smith | 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 | justin_smith | 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 | p_l | 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 | justin_smith | 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 | TEttinger | 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 | justin_smith | not just cPython - it also messes with class initialization |
| 22:00 | justin_smith | 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 | justin_smith | ) |
| 22:03 | justin_smith | imanc: a module can be loaded multiple times |
| 22:03 | justin_smith | imanc: clojuer is very repl-centric |
| 22:03 | justin_smith | 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 | justin_smith | 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 | justin_smith | (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 | justin_smith | 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 | gfredericks | 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 | justin_smith | 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 | justin_smith | 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 | justin_smith | but then there is *ns* |
| 22:09 | justin_smith | ,*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 | justin_smith | ,*ns* |
| 22:09 | clojurebot | #<Namespace sandbox> |
| 22:09 | justin_smith | the current working namespace |
| 22:09 | justin_smith | which is a more repl-centric concept usually |
| 22:10 | justin_smith | 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 | gfredericks | 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 | justin_smith | anyway, actually going this time, brb |
| 22:11 | gfredericks | e.g., clojure.tools.logging uses it to pick the appropriate logger |
| 22:12 | gfredericks | 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 | imanc | 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 | gfredericks | 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 | gfredericks | 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 | imanc | 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 | gfredericks | ,x |
| 22:19 | clojurebot | 42 |
| 22:20 | imanc | oo |
| 22:20 | imanc | heh |
| 22:20 | gfredericks | here's a fun one |
| 22:20 | gfredericks | ,(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 | kenrestivo | ,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 | bbloom_ | 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 | gfredericks | the function has to contain a reference to the var |
| 22:23 | gfredericks | so it has to exist |
| 22:23 | gfredericks | wouldn't want to go checking that it exists every time you call it |
| 22:24 | gfredericks | 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 | bbloom_ | (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 | bbloom_ | def is a special form |
| 22:29 | bbloom_ | 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 | justin_smith | (it's way too long for here) |
| 23:08 | justin_smith | 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 | justin_smith | "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 | justin_smith | so it's not just worst case, but overall actual usage? |
| 23:22 | justin_smith | 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 | ilargs | thanks guys. |
| 23:27 | justin_smith | np |
| 23:27 | justin_smith | good luck |