#clojure log - Jun 27 2017

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

7:13 Rovanion: Does a symbol reference a value or is there a more correct term than references one can use?

7:13 dysfun: a symbol names a value

7:14 possibly

7:14 a symbol may or may not name a var which contains a value

7:14 oh, but that doesn't cover local bindings

7:14 Rovanion: Are functions held in vars?

7:15 dysfun: if it's a value accessible through the namespace, it's a var

7:15 Rovanion: But local bindings made with let are not vars?

7:16 dysfun: i don't think so, but i couldn't tell you what they are

7:16 the point of vars is that they provide a thread safe mechanism for changing the value of something

7:17 and there's no need for thread safety for locals

7:17 Rovanion: While namespaced things can be adressed and potentially mutated from anywhere in the program?

7:18 dysfun: exactly

7:18 whereas a binding isn't updateable, so no worries

7:18 (with the exception of dynamic binding, obviously)

7:18 Rovanion: :D

7:19 dysfun: those i am afraid i do know about, but you'll forgive me for not wanting to talk about how they work

7:21 Rovanion: I've not needed dynamic binding thus far so I'm absolutely fine being ignorant about how they work right now.

7:21 dysfun: when you need it, you really need it

7:21 naturally it plays terribly with lazy sequences

7:22 in general, a great way to add confusion to your codebase

9:50 Rovanion: What is the difference between a form and an expression?

9:51 justin_smith: in a language without statements (like clojure), there is none

9:52 in other languages a form could be a statement

9:53 Rovanion: Thank you!

11:05 tallpants: Hi

11:05 dysfun: hello

11:07 tallpants: Is it normal to feel skullfucked when you're starting off learning >_>

11:07 dysfun: utterly

11:09 tallpants: How long did it take for you to get over the hump?

11:09 Not to get good, just to get to "not utterly incomprehensible wtf is happening"

11:10 dysfun: it starts to fade fairly quickly, but i don't know i felt properly comfortable in clojure for at least a year

11:36 dnolen: ClojureScript 1.9.660 released https://clojurescript.org/news/2017-06-27-faster-compilation-runtime-and-spec-caching-fixes

12:11 osfabibisi: gah, how annoying that < doesn't work for all compare'able things

12:12 colleagues have written #(< (compare %1 %2) 0) instead, which seems less pleasant than it ought to be

12:12 technomancy: (comp neg? compare)

12:13 osfabibisi: yeah, that's still pretty horrid though

12:13 technomancy: sure

12:26 which is nicer? (mapcat (comp file-seq io/file) src-paths) vs (for [p src-paths f (file-seq (io/file p))] f)

12:27 I feel like this is one place where `for' making you choose a name for the intermediate seqs isn't helpful

12:39 (.lastModified (java.io.File. "does not exist")) ; -> 0

12:39 ugh

13:01 justin_smith: technomancy: it's Borges' Library of Babel - every possible file with every possible name existed on january 1st 1970

13:02 "Despite—indeed, because of—this glut of information, all books are totally useless to the reader, leaving the librarians in a state of suicidal despair."

13:03 sounds a lot like the Internet actually

13:04 technomancy: ah man I really need to read that

13:05 justin_smith: wow, Quine wrote about it https://en.wikipedia.org/wiki/The_Library_of_Babel#Quine.27s_reduction

13:05 dysfun: technomancy: i would be interested to see your 'fur' macro which is like for but removes the need to assign names

13:09 technomancy: dysfun: oh, I just meant mapcat

13:20 wickedshell: Does anyone have any recommendations on parsing an input stream into a lazy sequence? The best I've been able to find is https://github.com/jpalmucci/clj-yield looks quite reasonable for what I want to do, but I notice it hasn't been updated in 6 years (still works as expected in the REPL) I'm just curious if there is a more idiomatic way to transform an input stream into a lazy sequence

13:23 hiredman: a lazy sequence of what?

13:24 wickedshell: maps (each message that was encoded in the file essentially)

13:25 hiredman: don't use clj-yield

13:25 amalloy: clj-yield is a weird idea

13:26 hiredman: you may want to checkout https://github.com/ztellman/byte-streams

13:26 amalloy: it's very easy to just write a recursive function that uses lazy-seq and cons

13:27 wickedshell: I've never messed around with lazy-seq, but I was struggling on paper to see how to maintain the locally needed state for the input stream to build the next cell (probably missing something obvious on it, but thats where I ended up last night)

13:28 justin_smith: (lazy-seq (cons (f input-source) (self-call input-source)))

13:31 wickedshell: hmm will play with that a bit then, see if I can make sense out of it in the REPL

13:31 Thanks

13:53 With the above calls how do you manage the with-open context? I succesfully cooerced the code into justin_smith's recommendation (was easier then expected), however it has the downside I had to remove the with-open inside my function that was creating it's own DataInputStream

13:54 justin_smith: right, you need to embed the ability to close and clean up the stream into f (and only conditionally do the self-call if the stream is still open)

13:55 with-open and laziness are not compatible

13:56 hiredman: https://ce2144dc-f7c9-4f54-8fb6-7321a4c318db.s3.amazonaws.com/reducers.html

13:56 wickedshell: ... right, thats actually obvious in hindsight and something I think I had realized last night, and now spaced today...

13:58 justin_smith: reducers, as hiredman linked, seem like they could be an interesting alternative to a lazy-seq here, but I can't say anything about using them

13:58 I should try them out one of these months

14:00 amalloy: well, with-open is *sorta* compatible with laziness. you can produce a sequence lazily inside of a with-open, so long as you fully consume it before leaving the scope of that with-open. laziness is still a useful way to reduce coupling

14:00 wickedshell: The current target for why I was pursuing laziness was to allow working with a moving window over a large file (on the assumption that if I don't hold onto the head I won't blow up memory) I could be wrong on that, but the files I'm poking at are just to large to hold the entire represenation in memory, but I still want to be able to play with external use of filter/look into transducers

14:00 I could be chasing this the wrong way, but it's been intresting thus far :)

17:52 Rick77: Hi, does anyone knows how to start leiningen with a specific version of clojure (I have to work around CLJ-1743 and I use a patched jar)?

17:54 TEttinger: you mean the version of clojure that lein itself uses, not your project?

17:55 Rick77: TEttinger, I guess I can change the clojure in my project easily enough with project.clj (correct me if I'm wrong), so I'd say the one leiningen uses

17:56 TEttinger: maybe this? https://github.com/technomancy/leiningen/blob/stable/doc/PROFILES.md#replacing-default-repl-dependencies

17:57 I don't know what CLJ-1743 is off the top of my head. I mean I don't even know where the JIRA is...

17:57 amalloy: TEttinger: it is very easy to find if you just type CLJ-1743 into google

17:58 Rick77: i think you should figure out whether you need to replace the one lein uses or the one your project uses, not just assume you want to do the harder one of those

17:58 i doubt the version of clojure used by lein matters to you at all, in the context of CLJ-1743

17:58 i would expect it to do AOT compilation inside of a JVM that's in your project context, not lein context

17:59 Rick77: amalloy, that's *very* helpful, thanks

17:59 amalloy: my guess would be, make sure the patched version of clojure you need is published in a maven repo somewhere, and then depend on that in your project

17:59 Rick77: since we are at it, is there any way to reference a jar in a leiningen project without maven? I'm doing a quick company hackaton, and the dependencies are messy...

18:00 amalloy, also a very good suggestion: thanks

18:00 TEttinger: if it's a public git repo, you can use jitpack

18:00 Rick77: no, it's a naked jar I have in a dir somewhere. Don't ask ;D

18:00 (or better, a dozen of them...)

18:01 amalloy: normally when publishing a fork you'd do it under a different artifact id, but since you want to override the version of clojure seen by the whole universe, i'd publish it to a maven repo (preferably a private one you own) under the name "org.clojure/clojure" but with a weird version number that nobody else will ever try to use, like "rick77-1.9-alpha500"

18:02 Rick77: amalloy, I'll follow the way of the slacker(Tm) and look for one around first ;-)

18:05 is there any leiningen plugin that allows referencing a "naked" jar anyway?

18:05 amalloy: naked jars are a recipe for sadness

18:07 Rick77: amalloy, agreed, and I have already installed all the jars I need in my local repo with custom names, but still it would be nice to be able to do that, if else for quick tests...

18:07 TEttinger: if the bug has been fixed in Clojure but hasn't yet been released, this gets the latest commit as it is built by JitPack https://jitpack.io/#clojure/clojure/d7e92e5d71 (lein is an option)

18:08 if it has been fixed by someone else, use their repo instead of clojure/clojure

18:08 Rick77: Thanks TEttinger: I'll check it out!

18:08 TEttinger: commit could be broken, but that seeems to be a release

18:08 amalloy: TEttinger: the problem with that is, if you use something other than org.clojure/clojure, you end up pulling in both the patched clojure and normal clojure

18:08 Rick77: also, no custom repo: there is a patch, and I'm applying and compiling right now

18:09 amalloy: the same thing would happen if you added a local naked jar to the classpath: you'd get its stuff, but lein would still also pull in org.clojure/clojure for you, as other stuff depends on it transitively

18:09 TEttinger: amalloy: would that still have issues with AOT compilation then?

18:09 amalloy: maybe you could make it work, but i would not want to deal with the issues caused by having two clojures in the same jvm

18:09 i dunno, maybe, maybe not

18:09 TEttinger: maybe you should google it

18:09 Rick77: the jar inclusion was for something else, actually, not necessarily the clojure jar itself

18:10 but that's good to know, thanks

18:13 wait... I didn't check whether 1.9 already has the patch!

18:13 nope ;(

18:16 lxsameer: which name do you prefer for a function which is responsible for fetch a value of a key from a config file ? 1) fetch-config 2) <-config 3) suggestion

18:16 luma: coming from enterprisey java background, get-property

18:16 technomancy: "fetch" implies over a network to me

18:16 jeaye: Agreed with technomancy.

18:16 Also, sounds like that function is doing a lot.

18:17 Consider separating the slurp from the pure key lookup.

18:18 TEttinger: good point for composability, jeaye

18:18 lxsameer: jeaye: that function implemented by smaller functions

18:20 jeaye: So why not just have a fn which gets you the config and you can do the key lookup like you would normally?

18:20 amalloy: jeaye: yes, but having done that be careful not to write something like [(:k (get-config)), (:q (get-config)) ...]

18:20 jeaye: (::meow (kitty/config)) ; for example

18:21 lxsameer: jeaye: basically that's the implementation of that function. and if i do that in every place in my code it going to violate the DRY rule

18:21 amalloy: that is, it's great to split up, but this imposes on you the extra burden of tracking already-loaded configs to avoid lots of pointless re-lookups

18:21 jeaye: amalloy: What I tend to do is (def config (slurp ...)) and then just treat it like a map.

18:22 amalloy: fine, but now you've made a global singleton

18:22 jeaye: Any "redundancy" is in the syntax of looking up a key, which is the the majority of code.

18:22 lxsameer: jeaye: let's say you need to provide a default value for missing keys

18:22 technomancy: there's nothing wrong with a global singleton of immutable data

18:22 amalloy: and introduced weird compile-time vs runtime dependencies: you're slurping that at compile time

18:22 technomancy: you merge in the defaults at boot

18:22 jeaye: lxsameer: clojure.core/get does that.

18:22 lxsameer: jeaye: now, you spread your default values in your code

18:22 jeaye: technomancy: Agreed, immutable globals ar eno problem.

18:23 lxsameer: If you're using defaults quite often, I can see that as causing an issue.

18:23 technomancy: it's not a problem; merge them when you def

18:23 amalloy: they're less of a problem, but i disagree that they are no problem at all. it means you can't have two copies of your thing in the JVM at once, because they have an implicit dependency on this global

18:24 often this is fine, but it's not so rare that a thing you thought you would only need one of suddenly turns into something you want more of

18:24 jeaye: lxsameer: I almost never do, so it didn't come to mind. In that case, consider get-config

18:24 technomancy: amalloy: it's not a good pattern for libraries, granted

18:24 amalloy: heh, i would say the same thing but emphasized differently: it's excusable for apps

18:24 lxsameer: jeaye: ;) thanks

18:26 amalloy: even for apps i prefer not to do that, but it is the expedient path and usually causes little harm. component is a good way to avoid global singletons while still keeping the convenience of not having to wire stuff together yourself

18:26 technomancy: we have our config managed using mount in one of our services and it's really stupid

18:26 because it means you can't repl in without having mount started =\

18:27 because the repl port is a config value

18:27 amalloy: as someone who only hears about mount when someone is having enough trouble with it to ask for help in irc, i conclude that mount always causes a great deal of trouble

18:27 technomancy: amalloy: that's exactly how I feel about component

18:28 {blake}: Is it possible to capture stdout globally? Such that all the output that would normally appear on the command-line (I guess that might include stderr) would be saved as a string?

18:28 technomancy: (they're both annoying to me)

18:28 amalloy: but this problem would be just as bad with component

18:29 amalloy: technomancy: well, so long as you and i both recognize that we have biased perspectives based on where we hear about it. that's why i prefaced my statement with the obvious reasons it's a bad observatoin

18:30 technomancy: I'm sure component solves problems for people

18:31 jeaye: {blake}: Wrap your main in with-out-str?

18:31 Honestly, the easiest way would probably be in the shell, not in Clojure.

18:32 {blake}: Yeah. My issue is that I can't control anything outside the code and I'm not allowed to see the logs. =)

18:32 jeaye: java -jar my-app.jar 2>&1 | tee my-saved-output

18:32 Ah.

18:38 {blake}: And the log tool I have access to shows each line of the stack trace as a single, clickable entity... Whee!

18:42 Rick77: amalloy, building a custom jar, slapping it in the local repo and just changing the dependency worked (no need to mess with the profiles): thank you! :)

18:59 thank you all for the help, always a pleasure to be here! Bye.

21:52 kenrestivo: jar in repo? hmm.

21:53 i am always deeply suspicious of compiled objects in repos

21:54 amalloy: kenrestivo: i think you are confused about what is meant by repo there. clojars.org is a repo with loads of jars; the earlier discussion was about maven repos, not git repos

21:57 kenrestivo: aye

Logging service provided by n01se.net