#clojure log - Jan 11 2015

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

0:00 rritoch: arrdem: The way I see it, there are potentially an infinite number of possible operators and no language could ever include them all. It may be beneficial to algorithmic thinkers to develop such a capability in an algorithmlic language.

0:01 arrdem: I also believe, based on some proofs provided by a "friend" of mine, that it could provide a higher level of security, since without knowledge of the operators and their implementation, the language could have "perfect secracy".

0:01 arrdem: see http://rosuav.com/1/?id=683

0:03 arrdem: I don't particularly agree with all his conclusions, but the fact that the same source code can represent multiple different programs is a potential benefit for providing security.

0:06 arrdem: I do agree with one point though. As soon as you make operators that can be changed, source codes no longer contain any information, therefore meeting the condition of perfect secracy.

0:07 arrdem: Though, I"m not sure if that conclusion was in the document I sent, or in personal emails.

0:08 andyf: rritoch: Reading your original message, are you saying that you are having difficulty parsing a language, because the formal grammar of that language is changing during run time?

0:09 rritoch: andyf: The grammar itself becomes ambigous is the problem, so either operators need to be replaced with functions prior to parsing or the parser itself needs to consult some algorithm to determine a resolution to those conflicts.

0:10 andyf: There are parsing algorithms for context-free grammars that can handle ambiguous grammars. I believe Instaparse implements one such algorithm.

0:11 But there can still be ambiguity of not knowing what an identifier means during parsing, so you don't even know what kind of token it should be in the parsing process.

0:12 If the latter case, then those parsing algorithms I mentioned won't help you.

0:12 rritoch: andyf: Thanks. I'll take a look at it. The simplest representation of the problem I found is the grammar rule "symbol spaces symbol spaces? semicolon" This could represent a variable declaration or a unary operation.

0:13 andyf: Lisp using a 'everything is prefix notation, with parentheses around each operator/function, plus its arguments' makes some things easier to parse, certainly. Postfix notation has the same benefit.

0:13 rritoch: andyf: During parsing the resolution can be provided, the problem is the resolution rules can't be defined by the grammar since they need to be determined algorithmically.

0:14 andyf: Unfortunatly I want to allow multiple inheritance in the language, if that wasn't the case than I'd simply be doing a search/replace, shifting the parenthesis, and sending it to the clojure runtime to handle.

0:14 arrdem: andyf: working on Grimoire ATM, adding support for platforms (clj, cljs, cljclr etc)

0:14 andyf: not sure what you mean by a resolution rule there. Do you mean rules for deciding whether a particular 'lexical token' is, say, a number, variable, function, or something else?

0:14 arrdem: andyf: thoughts on how I should resolve a namespace qualified symbol to documentation in the case of implementations on multiple platforms?

0:15 andyf: arrdem: Nice.

0:15 arrdem: I'm thinking that I default to clj, and otherwise "first" wins

0:15 rritoch: andyf: The parser I'm using, and I believe any LALR parser will report a conflict if it can't resolve an ambiguity on it's own.

0:16 andyf: LALR parsers are one class of algorithms that handle a subset of context free grammars. There are other algorithms that can handle all context free grammars, even handling ambiguity in those grammars (meaning that the algorithms can produce correct parse trees even if there is more than one parse tree that produces the parsed string).

0:16 LALR can't do that, though.

0:17 arrdem: &(sort ["clj" "cljclr" "cljs"])

0:17 lazybot: ⇒ ("clj" "cljclr" "cljs")

0:18 arrdem: okay well that "just worked"

0:19 aaand now I have to fix my datafiles because I've successuflly upgraded (and broken) all my clients.

0:19 rritoch: andyf: Thanks, I'll look at instaparse. I wasn't aware that there was anything more advanced than LALR available

0:20 andyf: I simply need to be able to resolve conflicts via a method call from the parser, with that capability the language becomes possible, but I believe it is still computationally expensive.

0:20 andyf: At least during the compilation phase.

0:20 arrdem: .... shit

0:21 accidental git reset –hard

0:21 there goes my evening

0:21 g'night gents

0:21 andyf: sorry, have company for a few mins -- will be back soon

0:29 rritoch: (inc andyf)

0:29 lazybot: ⇒ 23

0:30 ryancole: (inc ryancole)

0:30 lazybot: You can't adjust your own karma.

0:30 ryancole: fml

0:31 rritoch: andyf: I haven't finished reviewing instaparse but from the description I think it is exactly what I need. Using a ambiguous grammer with say 255 recursion depth for operator precidence, and instaparse may solve the problems.

0:34 andyf: Once I figure out exactly how the ambiguity resolution process is implemented.

0:34 ncthom91: hey all. What's the customary approach to config files for clojure apps? For example, with javascript, config files are fairly typically a json file.

0:35 a clj file?

0:35 like project.clj for leinengen?

0:36 arrdem: ncthom91: do you have a specific platform/app in mind or are you just asking generally

0:36 ncthom91: arrdem generally, though I guess I'm thinking about just running a web app that can be configured with a set of rules

0:37 basically a web app that can be pinged with post-receive hooks from a git repository, and the rules govern what to do with those events

0:37 arrdem: ncthom91: TL;DR there is no standard. Everyone I know of rolls their own.

0:37 ncthom91: arrdem ah, interesting

0:38 arrdem how might I do it with a clj file? I notice leinengen specifies a `defproject` function?

0:40 arrdem: ncthom91: there is no technique which I will commend with a straight face for loading a configuration from a .clj file. It's not unheard of to eval an arbitrary "config.clj" off of the classpath, or to read some "config.edn" off of the classpath but both have their downsides.

0:41 ncthom91: arrdem heh, ok. What approach would you take for my situation? Mind you, I'm *very* new to clojure

0:41 arrdem: ncthom91: you just want to configure responses to webhooks?

0:41 ncthom91: yea basically

0:42 arrdem: is there some reason you can't write as a dispatch table in your program propper?

0:42 rritoch: ncthom91: I would suggest putting it on your classpath, in your resources folder, end-users could adjust their classpath to override the provided configuration file. Something like (read-string (slurp (clojure.java.io/reader (.openStream (clojure.java.io/resource "config.clj"))))

0:44 ncthom91: It certainly isn't a best practice, but it is an easy "hack"

0:44 ncthom91: rritoch would I then have to eval/parse the clj file?

0:44 arrdem yea I guess I just wanted to make a generic server that someone could spin up on their own with a different rule set

0:45 Lanzafame: Ok feeling like I am missing the obvious solution here. Installing leiningen. It successfully installed to my ~/bin/ folder but the `lein [command]` is only executing from that folder. I have added it to my PATH (.profile), and then run `source .profile`. I just can't get it to execute from any other location? Please point out the stupid mistake I am making... (OS: Ubuntu 12.04 Vagrant VM)

0:45 arrdem: ncthom91: then having an EDN file that specifies finite configurations would be my suggestion rather than having a full "configuration program" which is what rritoch's proposal allows.

0:45 Lanzafame: what's `echo $PATH` come out too for you?

0:46 rritoch: ncthom91: No, you only need to eval if your configuration file is a clojure form, if it is just data, like { :key "val" ...} than read-string will return a map.

0:47 arrdem: having read-eval'd the string, which allows arbitrary code execution

0:47 Lanzafame: "/home/vagrant/.rvm/gems/ruby-2.1.3/bin:/home/vagrant/.rvm/gems/ruby-2.1.3@global/bin:/home/vagrant/.rvm/rubies/ruby-2.1.3/bin:/home/vagrant/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/opt/vagrant_ruby/bin:/home/vagrant/.rvm/bin:/home/vagrant/.rvm/bin:/home/vagrant/bin/leiningen"

0:47 arrdem: use tools.reader if you want a "safe" reader

0:48 Lanzafame: you don't have to add the file ~/bin/leiningen to your path

0:48 Lanzafame: otherwise that looks fine...

0:48 ncthom91: rritoch interesting thanks

0:48 arrdem do you knwo of any examples of writing/reading edn files?

0:49 Lanzafame: arrdem I didn't... Should I remove it?

0:49 arrdem: ncthom91: for various (bad) reasons we don't have a "print-edn" operation, however pr-str is equivalent most™ of the time

0:50 ncthom91: you can use clojure.edn/read-string, but pr-str is the only way to "write" edn

0:50 $grim clojure.edn/read-string

0:50 lazybot: http://grimoire.arrdem.com/1.6.0/clojure.edn/read-string

0:50 rritoch: ncthom91: Just remember to close the stream when your done with it. The exact code I provided is a memory leak.

0:52 ncthom91: I use similar code in my project.clj files to load my repository lists from a configuration file in my home directory.

0:53 ncthom91: So in my case the memory leak isn't a problem since the code is only executed during compilation

0:54 ncthom91: rritoch cool, ok

1:17 rritoch: andyf: It looks like I need to continue looking for a better parser. Instaparse is certainly better than what I'm using. I especially like the look-ahead features, but it trades processing time for memory usage (via the parses function) which with a highly ambiguous recursive structure it would only take a small source code to exhaust all memory resources.

1:17 Lanzafame: arrdem Solution: Uninstall from ~/bin/ and install in /usr/local/bin/... Contrary to the leiningen install docs, but that is life aye :)

1:18 arrdem: Lanzafame: heh best of luck to you

1:19 rritoch: andyf: What I really need is a LALR that utlizes callbacks to resolve any conflict instead of aborting the parse.

1:19 Lanzafame: arrdem thanks

1:31 rritoch: I get the feeling I have just entered a bottomless pit. This all started with the need for a dynamic language, which brought me to lisp. The need for more features and preference for algorithmic syntax brought me to compiler design, not even the existing parsers provide the features I need. I suspect I should quit the project now before I end up having to design a new processor on an ASIC.

1:55 dagda1_: If I am returnign a lazy-seq here https://gist.github.com/dagda1/d99bf42f31e99ae3b07c is it possible to loop..recur lazily over the list or how do I avoid eager evaluation

1:56 will calling (rest se) on the lazy seq mean the whole thing is evaluated?

2:08 tomjack: (seq (rest s)) is, I believe, (next s)

2:09 and it won't realize the whole thing

5:31 hellofunk: hypothetically what happens if you use pmap to process something in parallel, and then each item in the collection is a collection that is then also processed with pmap, would each thread be spinning off more threads, like a tree?

5:42 kenrestivo: has anyone else besides me tried to get core.async and swing to work together, and run into what appear to be eventqueue deadlocks?

5:43 j.u.c.locks.LockSupport.park() is used by awt, it seems.

5:45 and all this breaks only on a single-cpu machine. on a multi-core machine, everyting works perfectly.

6:23 hellofunk: amalloy: rather enjoying reading through the flatland utilities. cool stuff

7:05 jonathanj: i don't understand gen-class

7:06 (ns foo.Bar (:gen-class :extends java.io.InputStream :main false))

7:06 how do i use this foo.Bar thing i've supposedly defined?

7:09 cljsn00b: when I turn this into a def, the javascript generated by cljs crashes in node: (defn published [] (pub output #(get % "channel"))) any idea what could be causing this?

7:51 AeroNotix: define crashes

7:52 cljsn00b: (L.b ? L.b(aj) : L.call(null, aj)).call(null, Rh); ^ TypeError: Cannot read property 'call' of null

7:52 something indecipherable

8:03 Biofobico: is (print "test") an expression?

8:04 AimHere: Yes. It evaluates to 'nil' though

8:04 The side-effect may occasionally be useful

8:05 Biofobico: (+ 2 2) also an expression right?

8:05 clojurebot: 4

8:05 AimHere: Yes.

8:05 AeroNotix: Biofobico: it might be easier to ask what isn't an expression

8:06 Biofobico: so why (do (print "test ") (+ 1 1)) evaluates the print?

8:06 AeroNotix: Biofobico: what do you think is happening?

8:06 AimHere: ,(do (print "test") (+ 1 1))

8:06 mi6x3m: Biofobico: because print is in the function position

8:06 clojurebot: test2

8:06 AeroNotix: what does do, do?

8:06 mi6x3m: AeroNotix: do evaluates all of the provided forms

8:06 one by one

8:07 Biofobico: from docs : Evaluates the expressions in order and returns the value of the last.

8:07 AeroNotix: mi6x3m: I know, duh

8:07 mi6x3m: I wanted to guide Biofobico through it instead of just giving them the answer.

8:07 mi6x3m: AeroNotix: oh :D

8:07 AimHere: ,(do (+ 100 100) (+ 2 2))

8:07 clojurebot: 4

8:08 dagda1_: when I call rest on a lazy seq is the whole thing evaluated or what actually happens?

8:08 AimHere: ,(rest (range))

8:08 clojurebot: (1 2 3 4 5 ...)

8:09 AeroNotix: ,(class (rest (range)))

8:09 clojurebot: clojure.lang.ChunkedCons

8:09 dagda1_: I also see (seq (rest s)) used a lot

8:09 AeroNotix: (rest '(1))

8:09 ,(rest '(1))

8:09 clojurebot: ()

8:09 AeroNotix: ,(seq (rest '(1)))

8:09 clojurebot: nil

8:10 AeroNotix: ,(if (rest '(1)) :t :f)

8:10 clojurebot: :t

8:10 AeroNotix: ,(if (seq (rest '(1))) :t :f)

8:10 clojurebot: :f

8:10 AeroNotix: dagda1_: ^

8:11 dagda1_: what about (recur (rest s)) on a lazy seq?

8:11 AeroNotix: dagda1_: what about it?

8:11 Does it evaluate the lazy seq you mean?

8:12 dagda1_: AeroNotix: yes

8:12 AeroNotix: No, it doesn't.

8:12 dagda1_: AeroNotix: that is interesting,

8:16 Biofobico: so (do (* 2 2) (* 3 3)) returns 9 but (do (print "test ") (+ 2 2)) returns test 4. If do evaluates the expressions in order and returns the value of the last, shouldn't return only 4?

8:16 sorry if it is a stupid question, but clojure is my first programming language so bear with me please

8:17 AeroNotix: Biofobico: it does not return test 4

8:17 it prints test and returns 4

8:18 it may look in the repl as if it "returns" test4 but it does not

8:18 ,(do (print "test") (+ 2 2))

8:18 clojurebot: test4

8:18 AeroNotix: ,(+ (do (print "test") (+ 2 2)) 1)

8:18 clojurebot: test5

8:18 AeroNotix: see?

8:19 if it "returned" test4 then the + operation would've failed.

8:19 ,(def v (do (print "test") (+ 2 2)))

8:19 clojurebot: test#'sandbox/v

8:19 AeroNotix: ,v

8:19 clojurebot: 4

8:19 AeroNotix: Biofobico: see^?

8:20 the print function has a *side-effect* (very important to understand, go look it up) of sending characters to the screen.

8:21 Biofobico: thank you

8:21 understand it now. the repl induced me into error

8:21 AeroNotix: nw

8:22 Biofobico: does that *side-effect* is in the docs?

8:22 Lanzafame: How would I go about sending weather api data from server-side (Clojure) to client-side (ClojureScript)? I use a handler to get the client's ip and process that through geolocation then a weather api to get json formatted data. I want to now send that through? Any help would be appreciated

8:25 AeroNotix: Lanzafame: send it as the response from the request the client initiated?

8:25 Otherwise, if you need a persistent connection and you want to do async communication or something, look into WebSockets.

8:26 hellofunk: Lanzafame: simple ajax would be straightforward. i use the cljs-ajax library for this type of stuff: https://github.com/JulianBirch/cljs-ajax

8:27 Lanzafame: websockets are a possiblity but require more overhead to setup and probably aren't needed for your task.

8:28 Lanzafame: Thanks for the pointers.

8:29 ticking: I always found websockets to be simpler to set up than ajax :P

8:29 hellofunk: ticking: are you using http-kit?

8:55 ticking: hellofunk: yeah

8:57 ticking_: hellofunk: there are plenty of helper libs (sente, chord), but doing it by hand takes about 30-200 loc depending on how much bels and whistles you want (calback style or core async)

9:05 lodin: ,(deftype Foo.bar []) (Foo.bar.)

9:05 clojurebot: sandbox.Foo.bar

9:06 lodin: Which version is clojurebot running?

9:06 ,(clojure-version)

9:06 clojurebot: "1.7.0-master-SNAPSHOT"

9:07 Bronsa: ,(Foo.bar.)

9:07 clojurebot: #<CompilerException java.lang.ClassNotFoundException: Foo.bar, compiling:(NO_SOURCE_PATH:0:0)>

9:07 Bronsa: lodin: "Foo.bar" is not a valid class name

9:07 lodin: Bronsa: You can deftype it.

9:08 And you can resolve it.

9:08 Bronsa: lodin: still not a valid class name

9:08 lodin: if you use ns-resolve.

9:08 Bronsa: Good. :-)

9:14 hellofunk: ticking: my understanding is that currently http-kit does not support secure websockets (wss:) and thus ajax is the only option if you want to encrypt the transfers.

9:14 ticking: hellofunk: yes true

9:14 hellofunk: ticking: which may not matter to most people

9:14 ticking: hellofunk: yeah its annoying as heck

9:14 hellofunk: ticking: and websockets without http-kit are pretty much a no-op if i understand correctly, unless you go down a rabbit whole of significant custom engineering on jetty

9:15 *hole

9:16 ticking: hellofunk: even with this? https://github.com/sunng87/ring-jetty9-adapter

9:16 hellofunk: ticking: oh i haven't tried that, but remember reading about it. there are so few people actually using it, so made me nervous to dependon it

9:17 ticking: seems reasonably maintained though

9:17 hellofunk: ticking: i wonder if secure sockets are available with that

9:18 ticking: hellofunk: I'm not sure how capable aleph is with wss but it's a very nice lib

9:18 https://github.com/ztellman/aleph

9:18 hellofunk: yeah, might work out of the box but I'm not sure

9:19 hellofunk: ticking: do you have other reasons for preferring/using http-kit besides websockets?

9:21 cljsn00b: is there a way to make function calls partial by default?

9:22 or is that a terrible idea?

9:22 hellofunk: cljsn00b: what do you mean "partial by default" ?

9:23 cljsn00b: ((partial + 1) 1)

9:23 opqdonut: like (#(+ %1 %2 %3) 7) would return a function taking two arguments

9:23 I think it'd be a pain in the ass when coupled with lack of typing

9:23 ticking: hellofunk: there has been some interesting discussions on this lately, ztellman (the guy behind lamina and aleph and a pretty smart guy) argued against it (when using websocket) because it lacks the ability to produce backpressure on connections https://groups.google.com/forum/#!msg/clojure/TVMQJwaij1U/ikNVo-58WggJ

9:23 arrdem: opqdonut: no we don't have currying. what you just typed would apply a function of three arguments with one argument.

9:24 opqdonut: arrdem: I know, see cljsn00b's question

9:24 arrdem: Ah.

9:24 opqdonut: also, due to how clojure is implemented on the jvm, it would cause lots of unnecessary closures that would need new optimizations to disappear

9:25 razum2um: opqdonut: but still, what's the "pain in the ass" if such will exist?

9:25 ticking: cljsn00b: you can build a macro that produces curryable functions, but that creates speciall functiosn that always call partial with not enough args and be pretty confusing, so yeah it's possible in a proof of concept scenatio

9:25 opqdonut: razum2um: weird errors because you made a typo / forgot one argument 3 levels up the stack

9:25 cljsn00b: ticking: alright

9:25 arrdem: yeah odds are you'll just increase source to sink distances :c

9:26 hellofunk: ticking: i've always found sockets a bit unstable, i wonder if it's just me. lot of people love them. even the figwheel stuff which is cool when it works often hangs for me with socket errors. at least ajax is an old and dependable technique

9:26 ticking: hellofunk: yeah, if it works for you use it :D

9:27 hellofunk: ticking: that thread you linked to is all greek to me. i don't know what backpressure is nor do i have a deep understanding of http and server architecture

9:28 ticking: hellofunk: the idea is, when a consumer can't keep up with the producer of messages, there should be some way to cause the producer to slow down

9:29 hellofunk: ticking: i see. so if jetty provides a max of 50 simultaneousl requests (because there are about 50 threads in teh pool, one thread per request) and the server has more than 50 requests... hm, i wonder what happens in that case. the requests are tossed out by default unless you have a channel in place somewhere?

9:30 opqdonut: what FP languages would provide that default currying behavoir?

9:30 does Haskell maybe do that?

9:30 opqdonut: hellofunk: haskell & ML languages

9:30 ticking: hellofunk: haskell

9:30 hellofunk: interesting i didn't know that

9:31 opqdonut: once you get used to it, higher-order programming feels rather weird without it

9:31 hellofunk: opqdonut: so the explicit requirement in clojure to use partial slows you down?

9:31 ticking: hellofunk: The backpressure thing doesn't work for new connections, but for existing ones if you have a constant stream of data say from a websocket

9:31 opqdonut: hellofunk: or rather makes the code more verbose

9:31 nuwanda_: opqdonut: well, it's way less confusing in a strongly typed language

9:32 opqdonut: yeah, that's what I said earlier

9:32 I don't think it would be a good fit for clojure

9:32 hellofunk: opqdonut: so in Haskell, funcation calls with fewer than required arity actually result in a returned function, otherwise, a returned value from the function

9:32 opqdonut: hellofunk: yeah

9:32 hellofunk: also haskell is lazy so the evaluation just works differently in general

9:33 (graph reduction instead of function calls)

9:33 hellofunk: opqdonut: that is actually pretty cool. in a sense, a transducer seems to sort of do that, though i realize that's a different application

9:38 ticking: interesting quote from that thread: "This means that any attempt to use http-kit in conjunction with core.async will be subtly but fundamentally broken"

9:38 ticking: hrhr yeah

9:39 hellofunk: "Arguably, even without core.async in the equation it's broken. This is not a good state of affairs."

9:39 well, tell us how you really feel

9:41 mavbozo: well, if i'm a author of library that wraps REST api and using http-kit as client, should i use another http client library?

9:48 hellofunk: mavbozo: unless impossible i'd consider letting your library work with any server the user chooses, jetty or http-kit, etc

9:49 mavbozo: hellofunk: i'm considering another simpler case, where my library is a wrapper for a http rest api, for example, twitter-rest-api

9:50 obviously, my library use a http-client library

9:50 there is a blocking http client--clj-http or non-blocking http-client, like http-kit

9:51 another quote from that thread "using core.async should be an application-level decision, not one made for you by your libraries"

9:51 makes me question, should the nature of http-client (blocking/non-blocking) made by me--the author of library, or consumer of my library

9:53 ticking: I think a lot of people would disagree with that quote though :)

9:54 hellofunk: mavbozo: i certainly agree

9:54 tvanhens: Are there any other authentication libraries out there other than friend and buddy?

9:55 mavbozo: ticking: but it is an interesting challenge for wanna-be library author, such as myself

9:56 ticking: yeah

9:57 mavbozo: provide wrapper for a http rest api, but not depend on any http client library and let the consumer of my library choose their own http client to be used by my library

9:58 lodin: If the library uses core.async and you don't want that in your application code, then you can make blocking wrappers, no?

10:00 mi6x3m: mavbozo: I am a wanna-be author also, just finishing my first clojure lib :)

10:00 lodin: Maybe not in the general case.

10:00 But for things like http?

10:02 mavbozo: lodin: maybe the library can provide 2 public function for blocking and non-blocking

10:03 example, if you want to block use get-block, else get-nonblock

10:03 lodin: mavbozo: In cases where applicable I'd prefer passing the async output to a function that blocks.

10:04 Like I once wrote a chan->seq function that returned when the channel closed.

10:04 Or actually, I think it was lazy.

10:04 hellofunk: ticking: look, Einstein disagreed with Bohr, even though he was wrong to do so. so there.

10:05 lodin: mavbozo: But the point is that the rest of the code didn't need to care about channels or go blocks.

10:17 Is foo_bar illegal as a namespace?

10:18 dysfun: ,(ns foo_bar)

10:18 clojurebot: nil

10:18 dysfun: nope

10:18 not that i'd advise it

10:18 lodin: I know it works, but that question was about being legal. :-)

10:18 dysfun: well if it works, it's legal

10:19 but be aware you may enrage your coworkers

10:19 lodin: dysfun: Scroll up to my conversation with Bronsa about (deftype foo.bar []).

10:19 dysfun: heh

10:19 again, perfectly legal, and perfectly likely to make your coworkers violent

10:26 hellofunk: what are clojure's analogs to haskell's fold left and fold right? i assume reduce is foldr?

10:27 arrdem: yes, reduce is foldr, we have no foldl built in

10:27 jackhill: dysfun: I'm new to clojure, why would that make people upset? (I assume because it's confusing or difficult to work with, but I'm interested in what way it could be confusing, etc.)

10:27 arrdem: jackhill: because _ is not part of the "conventional" naming scheme.

10:28 lodin: jackhill: And in the namespace part of class names "-" is replaced with "_".

10:28 arrdem: https://github.com/bbatsov/clojure-style-guide#naming

10:29 jackhill: arrdem, lodin: ah, thank you!

10:30 lodin: ,(do (in-ns 'foo-bar) (clojure.core/deftype T []))

10:30 clojurebot: foo_bar.T

10:34 lodin: ,(do (ns foo_bar) (deftype T []) (defn T? [x] (= x T)) (foo_bar/T? foo_bar.T))

10:34 clojurebot: true

10:34 lodin: ,(do (ns foo_bar) (deftype T []) (defn T? [x] (= x T)) (ns foo-bar) (deftype T []) (foo_bar/T? foo_bar.T))

10:34 clojurebot: false

10:34 lodin: jackhill: That's confusion. :-)

10:38 si14_: oh wow. is it by design?

10:38 https://www.irccloud.com/pastebin/SAfQGrJ6

10:40 si14: seems buggy to me tbh

10:42 hellofunk: si14: https://clojure.github.io/clojure/clojure.data-api.html#clojure.data/diff

10:43 si14: hellofunk: yeah, I've seen that. I don't see how #{} gets converted to nil

10:43 arrdem: si14: "sets are never subdiffed"

10:44 si14: arrdem: there is no "nil" in the second map

10:44 "subdiff" is a diff on elements

10:44 arrdem: &(= #{} nil)

10:44 lazybot: ⇒ false

10:44 mavbozo: ,(clojure.data/diff #{1 2 3} #{1 2})

10:44 clojurebot: #<ClassNotFoundException java.lang.ClassNotFoundException: clojure.data>

10:45 si14: ,(do (require '[clojure.data]) (clojure.data/diff #{1 2 3} #{1 2}))

10:45 clojurebot: [#{3} nil #{1 2}]

10:46 si14: and "no subdiffing" rule is about this

10:46 ,(do (require '[clojure.data]) (clojure.data/diff #{#{1} #{2}} #{#{1 42} #{2}}))

10:46 clojurebot: [#{#{1}} #{#{1 42}} #{#{2}}]

10:47 si14: it didn't subdiff #{1 2}, as stated in docs

10:49 lodin: sil4: What output would you expect from your pasted example?

10:51 * si14 lodin: somewhat like ({:foo #{[:a :b]}} #{:foo #{}} nil)

10:51 si14: (sorry, misplaced /me)

10:53 lodin: And what do you think about (diff #{1 2 3} #{1 2})?

10:54 si14: lodin: there is no items in b that are not in a, so it's fine

10:55 lodin: whereas {:foo nil} is actually a *new value* of foo

10:55 lodin: sil: I think that :foo nil means that "there are no values in (:foo y) that are not in (:foo y)".

10:55 si14: ,(do (require '[clojure.data]) (clojure.data/diff {:foo #{[:a :b]}} {:foo #{}}))

10:55 clojurebot: ({:foo #{[:a :b]}} {:foo nil} nil)

10:55 si14: ,(do (require '[clojure.data]) (clojure.data/diff {:foo #{[:a :b]}} {:foo nil}))

10:55 clojurebot: ({:foo #{[:a :b]}} {:foo nil} nil)

10:56 si14: but

10:56 &(= #{} nil)

10:56 lodin: si14: What should (diff #{1 2 3} #{}) return?

10:57 si14: lodin: as I said, it returns a thing that is logically sound (there is nothing in b that is not in a)

10:59 lodin: si14: So there should be a :foo in both elements, because (:foo x) is not equal to (:foo y), right? (Assume (diff x y).)

10:59 si14: And there is nothing in (:foo y) that is not in (:foo x), so (:foo y) should be nil, right?

11:00 si14: lodin: nope. #{nil} is more correct

11:00 lodin: (:foo y) for the output, that is.

11:00 si14: But there's no nil in (:foo y).

11:00 si14: lodin: there is nothing *in the set* that is different

11:01 nope, disregard this, I'm wrong

11:02 lodin: si14: #{nil} would imply that (:foo y) has a nil, and (:foo x) doesn't.

11:03 si14: "there is nothing in (:foo y)" can be conveyed by #{}

11:03 lodin: si14: But that doesn't match how (diff #{1 2} #{}) works.

11:03 si14: there is no possible misinterpretation in this case

11:04 lodin: si14: There is.

11:04 si14: lodin: "top-level" difference doesn't match what's done in the "subtree", too, so it's a bad analogy

11:04 lodin: si14: Try diffing {:foo 3} and {:foo #{}}.

11:05 si14: uhm. what's more common — changing value to nil or changing value to empty set?

11:05 lodin: si14: How do you interpret the output of (diff {:foo 3} {:foo #{}})?

11:08 si14: lodin: I see your point. What do you think is more common — {:foo #{1 2 3}} → {:foo nil} (you can't differentiate the two with current behavior) or {:foo 3} → {:foo #{}} (the problem you are pointing at)?

11:08 with current model it's a tradeoff, both behaviors are broken, but one breaks more common case

11:12 lodin: si14: Yeah I know. nils are a problem. Is that what you meant by "changing to nil"?

11:13 That is, some value happen to change to nil, and then you don't get a clue from diff?

11:14 si14: lodin: yes. "value changes to nil" is way more common than "value suddenly changes type to a set"

11:23 lodin: si14: What if (diff #{1 2} #{}) returns [#{1 2} nil #{}]? (It would be the same for other containers as well.)

11:24 hellofunk: if anyone has some thoughts: https://github.com/clojure-emacs/clj-refactor.el/issues/110

11:26 mmitchell: anyone here using the Prismatic Schema lib? I'm trying to find the best way to create a "default" instance of a schema

11:26 arrdem: hellofunk: I'll paste mine if you paste yours

11:28 si14: lodin: it will return it then

11:28 lodin: si14: ?

11:29 si14: mmitchell: can you give an example of what you mean?

11:31 mmitchell: si14: sorry, actually now I realize I'm approaching this wrong. The data will already exist, all I need to do is validate

11:32 si14: mmitchell: ah, ok. Good luck with Schema, personally I like it a lot

11:33 lodin: si14: Wouldn't returning (empty v) disambiguate both cases above?

11:34 mmitchell: si14: Thanks! And good to know. I use it on a web api project, but it's been a few months since I've touched the code, so now trying to update to the latest schema version, and see what I can do to improve things. All of the code uses the schema records, but I'd like to see if I can get away with just defs

11:34 si14: lodin: I believe it would be better

11:34 mmitchell: you may also like https://github.com/metosin/ring-swagger to get Swagger (http://swagger.io) integration

11:43 mmitchell: si14: cool, thanks!

11:45 mavbozo: sil4: i didn't know about swagger but it looks great

11:45 (inc sil4)

11:45 lazybot: ⇒ 1

11:46 mmitchell: (inc sil4)

11:46 lazybot: ⇒ 2

11:48 seangrove: dnolen_: May be faster to talk about https://github.com/swannodette/mori/issues/129 here - What about mut.conj_f1, mut.conj_f2 to avoid the extra lookup? It's likely negligible, but I'm not sure there's a downside to it.

11:49 dnolen_: seangrove: this not how JS engines work, there isn't going to be an extra lookup

11:50 seangrove: dnolen_: Ok, wasn't aware of that. Irrelevant then

11:51 dnolen_: seangrove: semantically there is a lookup but every major engine optimizes this away

11:51 seangrove: dnolen_: I had a suspicion, but wasn't sure

11:53 mavbozo: what are good books to understand more about backpressure?

11:55 hellofunk: mavbozo: check out #chiropractor

11:55 arrdem: (dec hellofunk) ;; that was just bad

11:55 lazybot: ⇒ 0

11:55 hellofunk: aw come on

11:56 (dec arrdem) ;; for no sense of humor

11:56 lazybot: ⇒ 40

11:56 justin_smith: (dec hellofunk)

11:56 lazybot: ⇒ -1

11:56 hellofunk: geez this is a touch crowd

11:56 arrdem: justin_smith: it's early, not enough coffee and tests are failing for no obvious reason. bite me.

11:56 hellofunk: *tough.

11:56 but, i'll be here all night. tips welcome

11:57 justin_smith: arrdem: err... you need coffee - yed you do

11:57 mavbozo: (inc hellofunk)

11:57 lazybot: ⇒ 0

11:57 mavbozo: for sense of humor

11:57 hellofunk: (inc mavbozo) ;; right on

11:57 lazybot: ⇒ 2

11:58 * arrdem returns with coffee

11:58 si14: mavbozo: it's "one", not "L" :)

11:58 mavbozo: (inc si14)

11:58 lazybot: ⇒ 1

12:00 arrdem: (inc hellofunk)

12:00 lazybot: ⇒ 1

12:01 justin_smith: hellofunk: decs for bad puns are s longstanding tradition, nothing personal

12:03 hellofunk: justin_smith: well it should be the opposite. :)

12:16 Kristien: Is there something like a lazy var? With delay I need @ and with memoize I need a call.

12:17 mmitchell: Anyone know if it's possible to add descriptions to prismatic.schema keys? I thought I saw someone talk about that once

12:18 dnolen_: Kristien: there is not

12:18 Kristien: And Var is final so I guess it's impossible to achieve. :L

12:20 I'll use delay then. Thanks!

12:45 instilled: hi! how can i chain a vector of fns, e.g. [fn1 fn2 fn2 …] -> (fn1 (fn2 (fn3 …)))

12:47 justin_smith: instilled: comp

12:47 ,((apply comp (inc inc inc inc)) 0)

12:47 instilled: justin_smith: cheers! i couldn't remember what it was called.

12:48 clojurebot: #<CompilerException clojure.lang.ArityException: Wrong number of args (3) passed to: core/inc--inliner--4221, compiling:(NO_SOURCE_PATH:0:0)>

12:48 justin_smith: instilled: with a vector you want apply

12:48 ,((apply comp [inc inc inc inc]) 0)

12:48 clojurebot: 4

12:48 instilled: awesome! thanks a lot/

13:27 Kristien: What's the reason case requires constant clauses?

13:27 seangrove: dnolen_: For iterating over arities in a macro and putting out properties on a defn'd form that'll survive munging, is this the final form you're expecting the cljs side to look like? - e.g. (do (defn my-fn [] (cljs.core/my-fn)) (set! (.-fn1 my-fn) (fn [x] (cljs.core/my-fn x))))

13:30 Kristien: Maybe you want cond or condp if you don't want constant clauses?

13:30 Kristien: Yeah. But still.

13:32 hellofunk: isn't case more or less analogout to "switch" ?

13:32 *analogous

13:33 Kristien: Yeah, but I don't see why it shouldn't work on everything that = works on.

13:34 hellofunk: Kristien: it's a macro, and: "The test-constants are not evaluated. They must be compile-time

13:34 literals"

13:35 another key point: "Unlike cond and condp, case does a constant-time dispatch"

13:35 seangrove: hellofunk: Makes sense, yeah

13:38 andyf: Kristien: compile-time constants enables case to generate very efficient 'jump tables', effectively, that do not depend on anything at run time other than the value in the first expression of the case.

13:39 Kristien: With a hypothetical case that uses = you can still do that if you can at compile detect that all cases are constants, which you can.

13:39 andyf: having variable values to compare to would not permit such an optimization, and in fact different invocations of case could have conflicting branches, e.g. what if two branches of the case had equal values? What would you want to happen then?

13:40 hiredman: Kristien: is you want to use = use cond or condp

13:40 if

13:41 case is just not for that

13:42 Gaza: (defn print-hello [nome] (print "Digo olá a " nome) (str "Olá " nome)) . What's the point of print if only the (str "Olá " nome) appears?

13:42 andyf: I can imagine creating a new construct that is 'between' case and cond/condp that optimizes to what case does if all test values are compile time constants, and behaves like condp with = if they are not. That isn't in Clojure, though.

13:48 nuwanda_: Gaza: the (str "Olá" nome) is the return value of the function, the print...prints :)

13:55 seangrove: dnolen_: Actually, looks like just a normal (do (defn stdFn []...) (goog/exportSymbol "mori.stdFn.fn1" (fn [x] (stdFn x)))) would work well

13:55 rberdeen: is there a way to skip :prep-tasks for a leiningen task?

13:55 or some other way to ensure "cljx" always runs before "compile"?

14:20 Gazaf: (ns test) - what ns stands for here?

14:22 ticking: namespace

14:22 creates a namespace called test

14:22 Gazaf: thank you

14:22 ticking: everything below that in a file will be in that namespace

14:24 Gazaf: is it like a container? like <div id="container">stuff here</div>

14:25 nuwanda_: what's your background in other programmming languages? Other analogies are simpler

14:26 Gazaf: have no background. Only html and css

14:28 gfredericks: a namespace is a collection of functions

14:28 a logical grouping

14:30 Gazaf: so any clojure program must have a namespace in the beginning?

14:30 gfredericks: more or less, yeah

14:31 ticking: Gazaf: a clojure program consists of many namespaces

14:31 you have one file per namespace usually

14:31 and thus a clojure program will consist of many files

14:32 nuwanda_: ticking: s/will/may/

14:32 otherwise it may be a little confusing on the guy :)

14:32 ticking: yeah

14:35 Gazaf: say contact.html, blog.html, gallery.html.

14:35 each one needs to have a namespace

14:36 is that it?

14:36 I trying to learn clojure for web dev so I tend to think that way

14:38 nuwanda_: Gazaf: generally speaking, yes, each clojure file will declare a namespace

14:47 Gazaf: thank you. I guess things will became clearly as I dive in the language

15:02 justin_smith: Gazaf: namesoaces make explici which definitions you are using. This makes code simoler to read, and prevents certain kinds of errors.

15:19 ssideris: hello, could anyone confirm whether with-redefs has any effect with core.async? I thought it would, but from my experimentation is seems that it doesn't

15:21 justin_smith: ssideris: depends what you are redef'ing - many things in core.async are special macro markers and not vars you can redef

15:22 go is a marvelous and frightening beast

15:24 ssideris: justin_smith: I'm redefing functions that were originally def'ed with defn

15:24 snippets:

15:24 (defn aa [] (log/info 10))

15:25 (with-redefs [aa (fn [] (log/info 33))] (aa))

15:25 (with-redefs [aa (fn [] (log/info 33))] (thread (aa)))

15:25 but I see the same behaviour with future:

15:25 (with-redefs [aa (fn [] (log/info 33))] (future (aa)))

15:25 which makes me think it's not core.async

15:26 chouser: the effect of with-redefs is global, and goes away as soon as flow control leaves the with-redef's block

15:27 ssideris: chouser: that's what I thought, but in the last snippet I should be getting 33, right?

15:27 I get 10!

15:27 chouser: you've set up a race condition

15:28 ssideris: oh the future gets to it first?

15:29 chouser: apparently your redef is ending before the future fires. You can add a delay to tip the race the other direction.

15:29 (with-redefs [aa (fn [] 33)] (let [f (future (aa))] (Thread/sleep 100) f))

15:30 ssideris: oh of course, the redef will exit right away

15:31 chouser: well, the future will also happen "right away", so they're racing.

15:31 Various unpredictable things like OS or JVM scheduling, garbage collection, etc. could tip the race either direction, potentially.

15:35 justin_smith: (inc chouser)

15:35 lazybot: ⇒ 17

15:35 * chouser bows

15:35 ssideris: sorry, but I'm not sure we your code works (and it does!): there is a delay after we've created the future, so it still starts immediately, right?

15:35 *why

15:36 chouser: yes, the future happens "immediately" in both your code and mine.

15:37 ssideris: so how do we avoid the race condition in yours?

15:37 chouser: Mine delays the end of the redef block for a tenth of a second, which will usually be enough for the future to complete. Then when the redef block finishes, the value of aa goes back to normal.

15:38 I am NOT recommending this as a fix or as working code. In fact, just the opposite: this shows how fragile it would be to depend on *either* outcome.

15:39 The race condition is there in both expressions, the sleep just handicaps the race in favor of the future.

15:39 ssideris: ok thanks, I get it now. So the lesson is: make sure the code you're running in with-redefs, blocks for the whole duration for which you need the redefined things

15:39 * kenrestivo mutters something about locks

15:40 chouser: Depending on what you're trying to do, you may consider dynamic vars and 'binding' instead. I believe core.async go blocks capture dynamic value bindings so they may be more predictable.

15:40 oh yes, locks are a good way to exchange race conditions for deadlocks. :-)

15:40 ssideris: I'm using real threads with (thread)

15:41 so I'm not sure if it would work

15:41 chouser: me either. I haven't played with the combination of dynamic vars, core.async, and real threads. Sounds a bit terrifying, actually.

15:42 ssideris: I just want to stub out some functions to do a "dry-run" of my code

15:42 do nothing instead of calling an API etc

15:43 justin_smith: would having the with-redef deref a promise filled in the other thread (at its end of course) be too much of s hack?

15:44 ssideris: hm, like a signal to block it until everything is done, right?

15:45 it's possible, but it makes my (dry-run) macro way less generic

15:47 but thanks in any case, I understand it now

15:47 (inc chouser)

15:47 lazybot: ⇒ 18

15:47 justin_smith: ssideris: the deref eould ensure thst the with-redef block won't exit until someone delivers to the promise

15:47 ssideris: (inc justin_smith)

15:47 lazybot: ⇒ 168

15:48 kenrestivo: i can attest that combining core.async with real threads, and with a library that does its own thread management, is... challenging.

15:49 actually terrifying is a much better choice of word

15:49 ssideris: justin_smith: I get it, but it means the prod code would have to handle a promise that wouldn't be there otherwise

15:52 kenrestivo: actually i've been wrestling with almost a month with a heisenbug deadlock that appears on a single-core ARM but does not appear on a multi-core intel

15:53 ssideris: I'm only using this as a dev tool to exercise my code, so the solution with sleep is probably ok

15:54 kenrestivo: when i see code where someone put in a sleep() to deal with a race, i usually run away screaming.

15:55 when i've had to do it, it's usually with a comment that says "XXXX HACK FIX THIS"

15:56 * kenrestivo goes back to battling the concurrency demons.

15:57 justin_smith: ssideris: a wrapper that takes a function and a promise as args, runs the function, then felivers to the promise

15:58 *delivers

15:59 ssideris: justin_smith: just a second, if the function is asynchronous, it will unblock to early, the promise will be delivered too early, and the redef block will exit too early

15:59 which is exactly the same as the original problem

15:59 SagiCZ1: how do i imitate while in clojure? some loop that repeats until certain condition is met?

15:59 maybe while?

15:59 Bronsa: &(doc while)

15:59 lazybot: ⇒ "Macro ([test & body]); Repeatedly executes body while test expression is true. Presumes some side-effect will cause test to become false/nil. Returns nil"

16:00 Bronsa: SagiCZ1: or loop/recur (or even reduce) if you don't need side-effecting

16:00 SagiCZ1: thanks bronsa.. is calling a function of some remote api a side effect? probably yes huh

16:08 justin_smith: ssideris: oh, yeah, you're right

16:17 hellofunk: justin_smith: what does it mean to store and replay a ring request, i.e. via groundhog?

16:18 justin_smith: hellofunk: provide the ssme headers and body, to diagnose a bug or be sure it is fixed

16:19 hellofunk: thanks to the api, unless you have state outside the session driving things, the request should be perfectly replayable

16:20 *the ring api, that is

16:20 hellofunk: justin_smith: interesting

16:22 justin_smith: hellofunk: it was developed as a way to turn backend bug reports into unit tests

16:39 Bahman: http://www.bahmanm.com/blogs/responsibly-upgraded-your-lisp-machine

16:39 Just to have a bit of fun.

16:39 :-)

17:17 dnolen_: seangrove: sounds promising

17:20 cfleming: w/ a Maven project how do I setup a REPL? Is it the same as w/ a Cursive Leiningen project?

17:50 espinho: can anyone point me a good beginner web development tutorial please?

17:51 found this book https://pragprog.com/book/dswdcloj/web-development-with-clojure but im unsure if it is a good investment

17:52 cfleming: dnolen_: Almost, but you should use the "Use normal process" option rather than "Run with Leiningen"

18:05 dnolen_: cfleming: ok thanks

18:12 hellofunk: espinho: check out cemerick's youtube channel for web dev tutorial for beginners

18:13 $mail espinho espinho: check out cemerick's youtube channel for web dev tutorial for beginners

18:13 lazybot: Message saved.

18:28 whodidthis: what's an easy way to execute a postgresql .sql file

18:31 AeroNotix: whodidthis: try yesql

18:32 whodidthis: i mean the entire file

18:34 AeroNotix: whodidthis: you'd just (slurp "/path/to/file") then and pass it to a psql execute call

18:41 whodidthis: sweet, execute

18:51 dnolen_: pondering Google Closure Module support https://gist.github.com/swannodette/0eaf17815d49b7b77a95

18:51 feedback concerns welcome

18:56 rhg135: that's cool but having to write code to load your code seems a bit... pointless

18:59 dnolen_: rhg135: I don't see what needs to be written here other than ... script tags same as today.

19:00 rhg135: if you don't have a large ClojureScript application this isn't for you :)

19:00 rhg135: ah, then wouldn't the browser actually do MORE work? multi[le http requests

19:01 dnolen_: rhg135: for many applications 2, core & whatever is needed for a sub page.

19:01 rhg135: I don't think you've seen a large ClojureScript application

19:01 we're talking 140,000+ lines of generated JS

19:01 second request isn't going to matter than much

19:01 breaking up the build will

19:02 rhg135: ah now it makes sense, what clicked for me are multipage apps

19:02 dnolen_: rhg135: yep

19:03 squeedee: David your dedication and sharing rocks man

19:03 rhg135: i've only worked on spas so i wouldn't know much

19:05 squeedee: I wish labs NY would poach you and bring your attitude and skills to getting us out of plain-old-js.

19:13 ticking: is there a list of reusable om components somewhere? or are there only the three listed on oms website?

19:16 cfleming: squeedee: Was I imagining a tweet from you asking about Cursive keybindings? I can't find it now.

19:16 squeedee: I deleted it

19:17 I didnt realise most of its already set up

19:17 fyi we met at conj. I was the Aussie at the unconf about #ifdef

19:18 cfleming: squeedee: Ok - there's some doc here: https://cursiveclojure.com/userguide/keybindings.html and some explanation that hasn't made it into the doc yet at: https://github.com/cursiveclojure/cursive/issues/552#issuecomment-60475268

19:18 squeedee: cfleming: I did throw in a few bindings that made some sense. A little sad that I cant use alt-(

19:18 cfleming: Yeah, I remember :-)

19:18 squeedee: Yeah, are you using JDK 7+? I think that changed there.

19:18 squeedee: and alt-shift( and alt{ etc... lots of them dont bind at all (on a mac)

19:18 i don't know to be honest

19:19 cfleming: It's a JVM problem

19:19 dnolen_: gist updated with approach for dealing with avoiding enumeration of all transitive deps thanks to the-kenny, https://gist.github.com/swannodette/0eaf17815d49b7b77a95

19:19 squeedee: Yeah looks like i am

19:19 cfleming: wow, thats annoying

19:20 cfleming: squeedee: IIRC it was to bring Java in line with some Mac UI guidelines, I'd have to dig the link up

19:20 squeedee: Im sitting in an airport on standby for a flight to SF. 2 weeks in SF, and im going to spend all my spare time getting better at clojure.

19:20 cfleming: squeedee: But yeah, Java on the Mac is becoming more of a PITA

19:20 squeedee: cfleming: no big deal. I bound to ctrl instead

19:21 Maybe its how I'll make an argument to buy myself a surface pro 3 :P

19:21 "coz my keybindings dont work"

19:21 my wife will understand

19:21 i need a paredit trainer

19:22 I've had a mac for 4 years now, and I still cant move to the start or end of a line without several false starts first.

19:22 ticking: ssideris: yeah but a surface has no unix aka most tools will suck

19:23 incredible hardware though :(

19:24 the-kenny: dnolen_: Do I get that right? With 'modules' we could advance-compile some namespaces to file A, some to file B, and some to lib.js and then load lib.js once in a webworker (A) and once in the 'page' (B) without having to export all functions in lib.js explicitly?

19:26 (and use functions from lib.js in both A and B as if they were included in both)

19:26 squeedee: ticking I love the digitiser on the surface, it's like having a Cintiq built right in.

19:27 dnolen_: the-kenny: in truth everything is actually compiled together as far as I understand. it's one build that can be broken apart. so yes no exporting here.

19:27 ticking: squeedee: yeah it's really great, but windows development is horrible most of the time unless doing .net

19:27 squeedee: I havent tried in a while. I got a mac in the end because I was so annoyed with ruby dev in windows

19:28 ticking: squeedee: I'm not sure how well linux is supported on that thing :(

19:28 squeedee: I love .net but thats pretty limiting.

19:28 ticking: yeah

19:28 squeedee: cygwin was the order of the day back then

19:28 probably still is

19:28 i figure i just need one of each :D

19:29 it's not like I'd throw my macbook away :D

19:29 the-kenny: dnolen_: so basically it's advance compilation, same shortened identifiers etc., but split into three files. Sounds quite good

19:29 dnolen_: the-kenny: yes that's exactly right, same as before you just get to define the split.

19:30 the-kenny: should really simplify a lot of patterns w/o futzing w/ multiple builds

19:30 the-kenny: Yup, I needed exactly that a year ago :)

19:30 Not so much in our current project, but it might come to it

19:30 ticking: squeedee: if clojurescript had an eval *cough* one could probably push all development into the browser and thus onto any device

19:30 dnolen_: the-kenny: one thing that's hard to cover here is foreign JS libs (non-Closure stuff)

19:30 squeedee: cfleming: this is what i ended up with: https://docs.google.com/document/d/1yyqDNGLJpzWZyF9SDZmPn_4NskrCrEMJ-Txah3SBOUY/edit?usp=sharing

19:30 scuse the link-of-doom

19:31 i hear both boot and lein work fairly well on windows. cfleming which platform do you do most of your dev on?

19:32 the-kenny: dnolen_: why is that? Do you want to define different externs for each output?

19:32 ticking: squeedee: mikera does all development on windows, in a pretty strange maven only environment I think

19:32 squeedee: maven is yuck :P

19:33 dnolen_: the-kenny: in the example you might have "codemirror" as dep for the editor ns

19:33 ticking: squeedee: yeah but core.matrix is pretty nice

19:33 dnolen_: the-kenny: in a single build it's easy to preamble codemirror ourselves, but for modules it's not as simple

19:34 squeedee: ticking: took me a while to understand the context. :D

19:34 ticking: hrhr

19:34 squeedee: i wish this airport had a desk and a 27" second monitor

19:34 the-kenny: dnolen_: I understand. Tricky :/ Luckily I don't have to rely on external stuff yet.

19:35 dnolen_: Btw. thank you very much for tackling the tooling stuff for ClojureScript. The last releases were really great

19:35 squeedee: some people are just really ace eh

19:36 Although, he doesnt have kids. Thats my excuse for being no damn use.

19:37 dnolen_: the-kenny: no problem, lot more to do before I'm happy :)

19:37 the-kenny: haha

19:37 that's the right way of thinking

19:42 dnolen_: the-kenny: actually foreign deps might not be such a problem after all due to CLJS-965

19:42 https://gist.github.com/swannodette/0eaf17815d49b7b77a95

19:42 something to stew on, night all

19:44 the-kenny: good night, I'm gonna head to bed too.

19:49 squeedee: I just met a woman at the airport named dijkstra. A lot better looking than the mathematician, and not in slightest bit interested in talking to a nerd about proofs and path finding.

19:52 AimHere: So much for that strategy for picking up women then

19:56 cfleming: squeedee: Thanks, I'll take a look.

19:56 squeedee: I do all my dev on a mac.

19:57 squeedee: Oh I dont know why i got the impression you used windows

19:58 cfleming: squeedee: No, I switched years ago, after a brief dabble with Linux

20:00 squeedee: Linux desktop is just infuriating :D

20:06 cfleming: squeedee: Yeah, although I liked the window management better than any other OS I've tried

20:06 squeedee: i always liked windows for that (win 7 especially)

20:07 I know a lot of its subjective

20:07 But windows just felt consistant and relatively straight forward.

20:07 Mac only becomes tolerable once you have shift-it or similar installed

20:50 justin_smith: right now my ui is literally bluetooth keyboard (full sized but very thin) logged into a linux server via a reverse port forward to a vps

20:51 I could have this UI with any usable OS (currently using a nokia cell phone that came with ssh installed(!))

20:52 haha, keyboard is logged in, sic, I guess it just shows which part is most important here usability wise

20:55 seangrove: Man, struggling with this cljs.analyzer stuff

20:55 Don't seem to be able to get the arity metadata about symbols like I'd expect

20:56 Or rather, :arglists doesn't seem to be present

20:56 justin_smith: seangrove: isn't js really weird about argument count?

20:56 dunno if that's actually related or not...

20:56 seangrove: justin_smith: This should be before it's in js-land

20:56 Still at macro-expansion time

20:57 justin_smith: ah, never mind then

20:57 so it's the jvm doing this analysis

20:57 seangrove: ,(resolve count)

20:57 ,(resolve 'count)

20:57 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.core$count cannot be cast to clojure.lang.Symbol>

20:57 #'clojure.core/count

20:57 seangrove: ,(meta (resolve 'concat))

20:57 clojurebot: {:ns #<Namespace clojure.core>, :name concat, :added "1.0", :file "clojure/core.clj", :static true, ...}

20:57 seangrove: ,(:arglists (meta (resolve 'concat)))

20:57 clojurebot: ([] [x] [x y] [x y & zs])

20:58 toxmeister: hi! can i bother you with a macro question? i'm trying to rewrite some array lookups with this macro here: (defmacro foo [buf & body] `(let [b# ~buf] ~@(postwalk-replace {'x '(aget `b# 0)} body)))

20:58 seangrove: so, I'd expect the cljs.analyzer equivalent to be (:arglists (meta (cljs.analyzer/resolve-var 'concat)))

20:59 toxmeister: the macro is almost doing it's thing: e.g. (foo buf (+ x x)) results in: (clojure.core/let [b__8468__auto__ buf] (+ (aget (quote b__8467__auto__) 0) (aget (quote b__8467__auto__) 0)))

21:00 however, how do i get rid of the quoting in the rewritten (aget) ??? i've tried so many things already...

21:00 seangrove: Ah, ok, looks like it's not in :arglists, it's in a few other places - :method-params looks promising

21:00 justin_smith: you want b# without the `

21:01 you have a bunch of redundant ` in that macro actually

21:01 you should only need the outermost

21:02 err - wait, maybe you also want it in that postwalk arg, but not directly on b# that's for sure

21:04 toxmeister: justin_smith: thx, i know it's not right infront of the b#, but if i remove it i get a compile error... my general confusion is still how to deal with quoting inside a ~@ form.. does my head in every time and so not easy to find systematic docs for this

21:05 justin_smith: toxmeister: if you need the ` on the postwalk arg, then you need ~b# to get the binding unquoted

21:06 because ##(do `b#) is not the value you want

21:06 lazybot: ⇒ b__12184__auto__

21:06 justin_smith: you want the thing that resolved to in the let form

21:08 toxmeister: justin_smith: hmmm... if i put the backquote for the whole aget form like this: (defmacro foo [buf & body] `(let [b# ~buf] ~@(postwalk-replace {'x `(aget b# 0)} body))) ...

21:08 justin_smith: and of course ##(quote `b#) is not much better

21:08 lazybot: ⇒ (quote b__12194__auto__)

21:09 justin_smith: you need to have a ~ before b# if you want to reference that let value

21:10 toxmeister: justin_smith: if i put a ~ before the b# in the above version it won't even compile

21:28 gfredericks: toxmeister: you can't use the b# syntax if you're using it across different backtick instances

21:28 because:

21:28 ,[`[b# b#] `b# `b#]

21:28 clojurebot: [[b__25__auto__ b__25__auto__] b__26__auto__ b__27__auto__]

21:29 gfredericks: ^ they end up being different symbols

21:31 toxmeister: gfredericks: thanks! i just worked around it via an extra outer let like this: (defmacro foo [buf & body] (let [b (gensym)] `(let [~b ~buf] ~@(postwalk-replace {'x (list 'aget b 0)} body)))) - works at last! :)

21:31 gfredericks: toxmeister: aw man I just did that too https://www.refheap.com/95992

21:31 justin_smith: I find it weird that you would need nested backtics at all...

21:32 but I don't use macros much, so I could be missing something here

21:32 gfredericks: well it's inherently code-walking

21:32 it's not nested backticks in the strictest sense

21:32 which I've never used in my life because it's scary and I don't understand it

21:33 toxmeister: gfredericks: hehe - like minds! :) here's to hoping i'll remember that in the future

21:33 justin_smith: &````````a

21:33 hellofunk: gfredericks: it is the scary code that is by far the most exciting and inspirational to all of us

21:34 justin_smith: $ping lazybot

21:34 gfredericks: ~nested backticks are a code obfuscation technique that can only be used by ztellman

21:34 clojurebot: Titim gan éirí ort.

21:34 gfredericks: wait did that work

21:34 ~nested backticks

21:34 clojurebot: Huh?

21:34 gfredericks: ~nested backticks |are| a code obfuscation technique that can only be used by ztellman

21:34 clojurebot: Alles klar

21:34 justin_smith: ,```a

21:34 clojurebot: (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list (quote sandbox/a))))

21:34 justin_smith: ,````````````a

21:34 toxmeister: true words (both @hellofunk & @gfredericks)

21:35 clojurebot: #<OutOfMemoryError java.lang.OutOfMemoryError: Java heap space>

21:35 justin_smith: oh man, is `````````````````````` a bot dos?

21:35 hellofunk: now this is some art that is transpiring in here right now!

21:35 gfredericks: always has been

21:35 justin_smith: ,``````a

21:35 clojurebot: (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/seq)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/concat)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/list)) (clojure.core/list (clojure.core/seq #))))) (clojure.core/list (clojure.core/seq (clojure.core/concat (clo...

21:35 justin_smith: fascinating

21:35 gfredericks: I've been backticking the bots since aught twelve

21:35 justin_smith: it's exponential

21:36 hellofunk: what the heck is going on. this is some quantum entanglement shit going on in here right now

21:36 gfredericks: bot backticking is like cow tipping

21:36 justin_smith: gfredericks: when you say that, I picture you in a cowboy hat, with a 3 inch diameter cigar hanging from your mouth "I remember it well, was the big bot roundup of '12..."

21:37 hellofunk: gfredericks: no it's not: no one has ever actually cow tipped.

21:37 gfredericks: it's only once a millennium that you get to refer to "aught twelve"

21:38 hellofunk: believe me i have searched far and wide. it is impossible to actually meet someone who has gone cow tipping. it is a great urban legend.

21:38 jackjames: greetings. transforming a map's keys: is one of these (or something else entirely) preferable? https://www.refheap.com/95994

21:39 gfredericks: jackjames: that second one isn't complete is it?

21:39 you want an (apply hash-map ...) around it or something?

21:39 justin_smith: hellofunk: "urban"

21:40 gfredericks: in any case the first one is what we normally use in absence of a library; I use plumbing.core/map-key

21:40 map-keys*

21:40 jackjames: gfredericks: wow, yeah, definitely

21:42 gfredericks: somehow misread the parens for brackets at the repl so i thought it was magically giving me what i wanted. thanks much

21:48 hellofunk: without starting a lecture series, i'm curious about thoughts on the proper use of eval in clojure code... when where and why?

21:53 gfredericks: I don't think I've ever used it for production business code; but there are lots of other reasons to write code

21:54 hellofunk: gfredericks: seeking examples.

21:55 gfredericks: if you are generating code for some reason, testing that it evaluates to what you think requires eval

21:56 hellofunk: sure, but i'm interested in the "generating code for some reason" part.... examples of those reasons

21:56 gfredericks: e.g., maybe you're the strange sort of person who does this in their free time: https://gist.github.com/gfredericks/96e284ce2d52b91d481e

21:57 hellofunk: gfredericks: rec-lazy-seq looks interesting

21:57 andyf: hellofunk: I haven't written a lot of Clojure projects, but the only one I can recall that uses eval is Eastwood, a Clojure lint tool, because it needs it (or would not check nearly as much as it does without it).

21:59 hellofunk: man can someone explain to me like i'm 5 years old what linting is

22:00 andyf: linting: Look for constructs in programs that might be mistakes, ones that a compiler usually doesn't catch, because the kinds of things caught aren't always mistakes.

22:01 hellofunk: andyf: i see. i should look at Eastwood to see exactly how one uses that meaningfully, i'm curious

22:20 justin_smith: hellofunk: linting is good at catching the kind of bugs thst make you facepalm

22:21 hellofunk: now.. i wonder if it would be too much to ask for an example of the type of bug linting catches?

22:25 mfikes: hellofunk: Regarding eval, there was a ML thread that appeared to make use of eval to gain a performance benefit in an interesting case: https://groups.google.com/forum/#!searchin/clojure/eval/clojure/mWrZhnFlhxs/RQz88fGeXTUJ

22:31 hellofunk: mfikes: for performance benefits, related is this macro observation that i've always been a bit curious about: https://gist.github.com/hellofunk/7d424d173125b5dc9640

22:35 that is quite an interesting read

22:38 justin_smith: hellofunk: regarding linting bugs: file name / ns mismatch, wrong arg count, doc string in the wrong place, likely keyword typos

Logging service provided by n01se.net