#clojure log - Sep 16 2015

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

1:14 nowprovision: whats the best way to unzip all dependencies into a reference folder somewhere for viewing

1:15 all dependencies -> all first level lein dependencies (not the complete graph)

1:16 say I had a project that depended on midje and clj-http, defined in dependencies: [] in project.clj, i want to do something like `lein magic-something src-ref/` and then have them unzip there for viewing

2:23 crocket: What is the best way to learn clojurescript?

2:26 dbasch: crocket: it depends on your background and what you want to do with clojurescript. What language(s) do you know already?

2:27 crocket: Java, javascript, clojure

2:28 I'm looking for the best self-learning material.

2:28 dbasch, ^^

2:29 dbasch: crocket: probably this one https://github.com/magomimmo/modern-cljs or the one by dnolen

2:29 crocket: What about clojurescript wiki?

2:30 dbasch: crocket: you may want to try asking at #clojurescript too

2:31 if you know clojure, the main difference is the tooling and the development process

2:32 and of course the fact that you have to deal with js instead of java interop

3:34 rritoch: Hi, is there a good resource to get up to date on the changes to clojure over the past year?

3:35 oddcully: changelog clojure 1.7?

3:36 rritoch: oddcully: Cool, thanks :) Does it include the transducers?

3:37 nm, I see it in the clojure 1.7 press release.

3:39 Has there been any significant improvement in providing http async by addon libraries? Last I knew there wasn't any good http async library for clojure.

3:54 Sorry, but one more question. I see that 1.7 introduces "Reader Conditionals". Do these deprecate cljx?

3:55 oddcully: rritoch: it's not mentioned and it has still valid use

3:56 rritoch: oddcully: Thanks again :)

3:56 ,+oddcully

3:56 clojurebot: #error {\n :cause "Unable to resolve symbol: +oddcully in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: +oddcully in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: +oddc...

3:56 rritoch: Hmm, what's the syntax for upvoting someone?

3:57 oddcully: it was inc. but i doubt it works

3:57 Bronsa: it works when lazybot is around

3:58 rritoch: Ok, thanks. I'll try to catch it later when lazybot returns from siesta

4:02 My return to this community is somewhat conditional on some meetings I have next week, but I'm optimistically trying to debrief myself back to Clojure. I spent the last month working with common lisp and returning to clojure is a bit like trading in a pinto for a lexus. So many new features :)

4:04 I do have one crossover question, does clojure have anything comparable to common lisp "Random-State"?

4:06 I see the new UUID feature, which is very cool, but there is something to be said for a clonable, serializable stream of random numbers.

4:06 It's the only feature from common-lisp that I haven't noticed within clojure.

4:08 dstockton: rritoch: what about java? https://docs.oracle.com/javase/8/docs/api/java/util/Random.html

4:08 rritoch: dstockton: That isn't quite the same thing since Random doesn't expose it's internal state.

4:08 dstockton: i see

4:11 rritoch: I was able to produce this feature in ABCL but my implementation is a bit sluggish for large seed sizes https://github.com/rritoch/jrelisp-abcl/blob/master/impl/src/main/java/org/armedbear/lisp/RandomStateObject.java my complexity I believe is polynomial O(n^2) since every random number requested needs to recalculate each value in the seed.

4:11 My implementation wrapps java's native random function

4:12 The value of the random numbers produced by it, are questionable at best. I never truly tested it to ensure that it has a decent amount of entrpy. I just assume there's a direct relationship between seed size and entropy for the algorithm.

4:16 Either way, I was just wondering of Clojure has a comparable feature. I'm not sure how significant the usage cases are, but in grid computing it is probably useful to have a duplicatble random state.

4:18 I'm not trying to make waves, or push this feature into clojure, I just wanted to know if the feature was already there someplace.

4:20 gilliard: rritoch: Does the SplittableRandom class added in Java 8 help? https://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html

4:22 rritoch: gilliard: That is very close, unfortunatly it doesn't implement serializable or in some other way export it's internal state.

4:23 gilliard: rritoch: do you mean that you want to serialize the RNG to send somewhere else so you have 2 identical sequences of numbers?

4:23 rritoch: I don't know what the CL random-state is used for.

4:24 rritoch: gilliard: Yes, that's what CL random-state is for, it implements the same functionality of SplittableRandom but is serializable (Readable/Writable)

4:26 dstockton: Random implements Serializable

4:28 rritoch: dstockton: I never noticed, but as far as I can tell Random isn't splitable. Probably why Java 8 introduced the new class.

4:33 dstockton: SecureRandom may be comparable https://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html

4:34 dstockton: oh, looks like it

4:34 getSeed

4:35 rritoch: dstockton: The documentation for it isn't so good though. It doesn't export how many bites of seed you need to get the complete internal state.

4:35 bites=bytes

4:36 It seems to make SecureRandom splitable you would need to still wrap it, and re-seed on each random value received from it. Re-seeding is basically how my CL random-state implementation works.

4:37 It is serializable though, that may be the key to splitting it.

4:38 gilliard: rritoch: What is the difference between an RNG which has generated another one by splitting, and 2 independently-created RNGs? My attempts to teach myself about this aren't going too well..

4:40 rritoch: gilliard: A split RNG will produce the same random number sequence while independently-created RNGs will typically have a different random state and therefore produce a different sequence.

4:42 luxbock: gilliard: see this talk by gfredericks https://youtu.be/u0t-6lUvXHo

4:42 rritoch: Ex: {:split {:a [9 5 3]} {:b [ 9 5 3]} , { :independent: {:a [4 5 1]} {:b [5 3 9]}}

4:42 hyPiRion: rritoch: use test.check. See https://github.com/clojure/test.check/blob/master/src/main/clojure/clojure/test/check/random.clj

4:43 gilliard: rritoch, luxbock: Thanks!

4:51 rritoch: hyPiRion: Thanks. As far as I can tell from my initial review I don't see how that's serializable. Take the case where you split after pulling 5 random numbers. You should end up with soemthing like {a: [5 9 6 4 6 3 9 7 4 3] } {b: [3 9 7 4 3 5 2 1 9 6]} (note first 5 of :b are last 5 of :a as a was split to b after 5 integers were extracted)

4:53 hyPiRion: That implementation you pointed out probably works fine within a single JVM, but if you need to export the RNG to another JVM, or store it in a database, I don't see an option.

4:56 lodin_: gilliard: Consider how you would create two independent RNGs, then move the need to create them into a function that only depends on its arguments. That leads you inevitably to splitting, unless you want to rewrite your code to pass in a new seed every time you need a new RNG somewhere down the call chain..

4:57 rritoch: lodin_: What your stating is exactly what I've been doing, unfortunatly. Creating a new seed on each use is a bit expensive depending on your seed generation algorithm.

4:59 mungojelly: i was surprised when i got to random number generation in knuth how simple it can be

5:00 of course if you just choose some random randomish algorithm it's not perfect by whatever standards, but as long as you don't use them for the keys to your bank vault i'm sure they're fine

5:01 in a couple of my projects i used the generator knuth calls the "superduper" generator because my husband I X Key! is also called Superduper so i just used that one for fun

5:06 tdammers: some PRNGs have properties that make them ridiculously unsuitable for a bunch of non-security things too

5:06 e.g., noise generators for audio purposes (synthesizers, noise shaping, etc.)

5:06 you really need something reasonably uniform there, otherwise the noise will be colored in some way

5:07 mungojelly: well if they make things in your synth sound different then all the more reason to make the RNG pluggable, then people can talk about which RNGs sound the coolest :)

5:07 lodin_: haha

5:07 tdammers: sure, you can use suboptimal PRNGs for effects :x

5:08 my guess is it'd be easier to start with a good one though, and then filter it to sound the way you want

5:08 easier to introduce non-randomness than to get rid of it

5:10 mungojelly: sure generally usually if you happen to have some really good randomness around that fits your other needs, but i was saying just btw making sloppy randomness is surprisingly easy, it's just a few operations and then you have a stream of randomishness

5:10 rritoch: As a note, my implementation generated a random number of seed values in a specific range, and then used a custom hash algorithm to extract a seed usable by Java's random function. Each time a new seed is needed it would randomize the seed values using the current (seeded) random object.

5:11 mungojelly: until i read in knuth that it's just those few operations i didn't know where random came from i just bowed down and asked the computer for it and didn't know what it was

5:11 rritoch: I'm not sure that this is cryptographically secure, but it did seem to work.

5:11 mungojelly: apparently even our actual cryptography approved by actual cryptographers had nonrandomness sneakily inserted by the NSA, so that is really quite not easy at all

5:13 tdammers: mungojelly: RNG != PRNG

5:13 *actual* randomness is excruciatingly hard to get

5:14 modern kernels do a fairly decent job by sampling "noisy" system components such as NICs and HDDs, and deriving randomness from those

5:14 mungojelly: computers could just ship with one of them radioactive decay random bit generators, maybe we'll add that feature next sometime after the 12th camera

5:14 tdammers: and then we use PRNG's to derive more randomness from that

5:14 oddcully: microphones

5:15 tdammers: radio static seems to work pretty well, too

5:15 (as long as you're really picking up static and not some malicious signal, that is)

5:15 but, anyway, if you run servers that are somehow security relevant, it's a good idea to add some hardware RNG devices

5:16 lodin_: The problem is that I also want pseudo-randomness because I want a reproducable system.

5:17 rritoch: mungojelly: Knowing the size of the key used to generate random numbers greatly helps in cracking cryptography. If the complexity and randomness of an algorithm increases over time I theorize that it would be unbreakable. My method was loosly based on how SHA complexity is produced. There are actually laws in some countries limiting key size so while this may be possible, it isn't 100% legal.

5:17 mungojelly: i used to enjoy making things random but then i realized there's no information in it and it just makes you hallucinate something interesting

5:19 rritoch: mungojelly: An erlier iteration of my algorithm used these concepts but I eliminated them from the code due to the potential legal ramifications of it.

5:20 mungojelly: i thought we won the crypto wars

5:23 rritoch: tdammers: Static is unfortunatly not very random. If it was we wouldn't have decent sound quality as all recordings introduce some amount of static. It isn't that difficult to predict static with decent computing power.

5:25 tdammers: rritoch: the "we wouldn't have decent sound quality" argument is nonsense

5:27 the reason we have decent sound quality is because the devices in question add relatively small amounts of noise, and the noise is uniform

5:27 so it affects all frequencies equally

5:27 rritoch: tdammers: This isn't an "argument", these are known facts, and they're not even new facts. A government can place static detectors at enough locations to match your static to a specific geo-location and easily hack everything your static driven random number generator produces.

5:27 tdammers: that part I agree on

5:29 the part about audio quality however... no. We have decent quality audio recordings because the devices in questions have reasonable SNR

5:29 mungojelly: most of the noise removal tools i know of just throw the baby out with the bathwater and attenuate everything in the frequencies there seems to be noise in

5:30 tdammers: mungojelly: these things usually work in the frequency domain; frequencies below a certain threshold are muted, leaving only those that are louder than the noise floor

5:30 mungojelly: which works great because the problem isn't really usually "this recording technically contains less information about the source event" and more "this recording has an unpleasant hiss"

5:31 tdammers: mungojelly: you get better results by sampling the noise floor first, and deriving per-frequency thresholds from it, but other than that, that's how it works, yes

5:31 also, if it's a pitched hiss, notching out the offending frequencies often works much better

5:35 rritoch: tdammers: I'm actually referring to multi-dimensional FFT calcuations which can be applied at some multiplier of the speed static travels at which is ~ c (speed of light)

5:36 mungojelly: i've never actually written my own noise remover, just played with other people's. i'd think of squishing the noisy freqs twice, squish them if they're below a floor, also squish them by that much even if they go above the floor to punish them for being noisy. idk if that would work. could i write that in overtone you think? i don't know what overtone's model is.

5:36 tdammers: rritoch: I am unaware of anything in professional audio recording that does stuff like that, and it's certainly not necessary to produce decent quality audio

5:37 mungojelly: you don't want to punish those frequencies when they're above the threshold - statistically speaking, the noise is going to make the sound louder half of the time and quieter the other half

5:38 rritoch: other than that, I guess sampling existing static at various locations and then using that information to calculate the static at the target location and time, yeah, sure, that's at least theoretically possible, given enough computing power

5:39 mungojelly: tdammers: do you use clojure for audio stuff? do you have any code up i could read? :)

5:39 tdammers: mungojelly: haha no... usually C++

5:39 mungojelly: c++ is very efficient and useful but in a way that makes me sad :(

5:39 tdammers: mungojelly: but actually most of the knowledge on the topic comes from doing home recording and studio work

5:41 rritoch: Anyhow, so far off topic.. I just was asking if clojure has a serializable, splitable, random number generator. Instead we're designing security systems for clojure which for ethical reasons shouldn't ever be produced.

5:44 lodin_: rritoch: I would love to see you adapt gfrederick's code in test.check and make it available as a standalone library. :-)

5:48 rritoch: lodin_: Making it serializable is simply a matter of your original post, generating a new seed on each use. It's computationally expensive and I can't say with any certainty that it produces a quality RNG.

5:51 lodin_: If I find a solution that isn't computationally expensive, I would have no problem making it open source or applying it in an existing API.

5:52 lodin_: To give you an example of the cost involved, a 1000 integer key literally trippled the amount of CPU time used by the CL ansi test suite.

5:53 lodin_: It isn't practical for a random number generator to consume 66% of CPU resources.

5:53 mungojelly: so does anyone have any recommendations of code in clojure i should read? what's well written, what do you like?

5:53 lodin_: rritoch: Ah. Reality. Bummer.

5:54 mungojelly: do y'all not read clojure as well as write it? it's like going to a writers chat and saying "what's your favorite book" and people are like "idk i read a short stort once that was ok." have you never read a program in clojure that was inspiring to read?

5:56 rritoch: lodin_: Yeah, I'm really annoyed about that to. As far as I know, "entropy" is the natural state, and it takes energy to create "order". Why my algorithm works in reverse, consuming more energy to create entropy, I can't quite figure out.

5:56 mungojelly: what i'm reading right now is the clojure agents tests. i'm learning about agents but it's a little dry.

5:57 lodin_: rritoch: haha.

5:57 mungojelly: entropy and order are enemies and so it's very hard to make one if you have the other. but secretly they're deeply the same. that's why you can use a bunch of order-- all the data on a disk drive-- to easily make a bunch of chaos. or vice versa if you can produce enough noise-- test.check-- you can produce perfect solidity.

5:59 that's the dichotomy that's at the source of our apparent experience of time. anyway so no recommendations what to read?

5:59 rritoch: mungojelly: That is a very good explaination. I'm sure there's some scientific law I'm not aware of that explains my problem, but what you described is exactly the dilema I ran into.

6:01 mungojelly: justin smith when i asked before linked me to something called useful with some assorted nice ways to say things

6:04 i'd really like to read something medium sized that's a coherent idea so i can see how things relate to one another

6:04 lodin_: mungojelly: I think that while there are lots of open source Clojure libraries, there's a general lack of open source systems. See e.g. http://www.uswitch.com/tech/more-open-source-clojure-systems-please/

6:06 mungojelly: lodin_: ok interesting. but what library should i read?

6:06 lodin_: mungojelly: See also https://www.youtube.com/watch?v=loL7_lvsDBo.

6:06 mavbozo: mungojelly, i don't like reading code without understanding the reason the code was written and also how the code got into the current form

6:07 but, for clojure, i like code and comment written in this format http://fogus.github.io/marginalia/

6:07 that's the code for marginalia leiningen plugin

6:08 mungojelly: do y'all not read assorted clojure code in general, just to learn about it or for fun?

6:10 tdammers: I tend to read source code for libraries that I consider using

6:10 mavbozo: mungojelly, not the whole library code but the part that interests me or the part where there's lack of documentation

6:10 tdammers: at least scan it to get a feel for the overall approach and quality

6:11 mungojelly: tdammers: and what's one that you've especially liked the overall approach and quality? please? :)

6:11 i don't know if i'm asking people to play favorites, or if you really don't have favorites, or..?

6:11 rritoch: mungojelly: I can't speak for the rest of the clojure community, but 80% of the code I've written in clojure was for proprietary (non open-source) systems.

6:11 tdammers: haha, hum, my mind tends to remember mostly the "stay away from this" type libraries

6:12 mungojelly: hmm yeah there's this whole intentionally keeping secrets thing. it seems like open source is more part of the game than an actual practice today. :'(

6:14 another possibility i guess is that nothing beautiful has been written (and published) in clojure, but i can't believe that, it's a beautiful language, surely someone has something meaningful to say in it somewhere

6:15 rritoch: mungojelly: I'm finding it difficult to explain my view of the issue without upsetting "the powers that be". So I'll explain my view of the open source community like this. When a developer has obligations that aren't compatible with his personal vision of computing, the developer usually opts to place their work in open source to protect their intellectual property from being misused or stolen.

6:16 mungojelly: I'd say PGP is a good example of this concept. The person who released it faced many legal problems, but they did it to keep their vision in the hands of the people who need it, and so that they themselves could freely use it for any future project they were involved in.

6:17 mungojelly: I suspect Clojure open source projects fall into the same category. When developers are making something for a proprietary system that they need to use outside of that proprietary system, they generally produce it "off the books" as open source to protect themselves from legal obligations, such as employment contracts which grant ownership of all your work to the company

6:17 your employed by.

6:18 When you release an open source clojure library, you strip all of it's financial value, making it not worth stealing.

6:18 mungojelly: i guess i understand these things in general in theory, but come on, how can that really work all the time to constrain the flow of clojure, when the people in this community could easily put together interesting fun things with a few paragraphs of text

6:19 there's some taboo on even stating short simple things, like to say a sentence is to Release that sentence As Open Source

6:20 tdammers: actually, releasing code under an open source license is often a very valid financial trade-off

6:21 you give up the opportunity to make money on the software by selling licenses, but that's only one possible profit model

6:21 quite often, the software you're writing is a means to an end, and writing it is not your core business

6:22 e.g., google's core business is serving targeted ads; the browser they build is a means to an end - better browser means better advertising

6:22 by releasing things as open source, you lose the ability to sell licenses, but you gain in terms of user base, and often this results in people doing a lot of work for you for free

6:23 even if it's just running the thing through its paces and reporting bugs

6:23 mavbozo: mungojelly, i find pedestal library's concept of interceptors to handle web request processing and its route as a data elegant. it's open source.

6:23 mungojelly: but i mean beyond large systems which obviously there's various economic factors that can get involved with the amount of effort involved in making them, what about just little systems we could spin up just chatting right here

6:24 tdammers: most open source projects start small

6:24 mungojelly: mavbozo: ok i'll check that out thanks!

6:24 tdammers: emacs, one of the most popular programmer's text editors, started as a loose collection of macros for another editor

6:24 visof__: hi guys

6:25 tdammers: it wasn't even a project, just a bunch of people using that other editor (teco), and then at some point someone decided to collect everyone's macros and package them into something more structured

6:25 mungojelly: like what if we just had in this chat a bot that instead of forgetting everything we had a way to make it store data (and thus code), then we'd be able to build a large interesting system just as easily as we chat in the form of examples

6:26 btw does anything collect the code people say here?

6:26 tdammers: programming doesn't work that way

6:26 visof__: i'm trying to implement this method, it should return number of first 0 on list, so when it's gaved (0 0 1 2) -> should return 2, (0 1 2 3) -> 1, (1 2 34) -> 0, i did this https://gist.github.com/aibrahim/e3c99d53a2d003501189 but seems wrong

6:26 can anybdy help

6:26 ?

6:26 tdammers: services like github do, in fact, implement most of what you're proposing, but in a way that is more suitable to programming

6:26 mungojelly: in #lojban we collect all the lojban people say, it'd be even easier to grab all the clojure people say here

6:27 tdammers: there's also Literate Programming, which tries to instate a programming workflow that is identical to writing prose or even having a discussion

6:27 mavbozo: mungojelly, as i recall, justin_smith tries to do it. i don't know if that is still his priority

6:27 rritoch: tdammers: Emacs was developed by MIT. Expanding on mungojelly's statement. The financial model for a college isn't based on selling software, it's based on selling education. For them producing a technology which made their students more efficient technology professionals built their brand attracting more income.

6:27 mungojelly: tdammers: github has been a very interesting social explosion, but it still feels to me like it's tremendously slowed by continuing taboos on speaking anything partial or participatory or silly or easy or fun

6:28 lodin_: mungojelly: https://pragprog.com/book/vmclojeco/clojure-applied just came out. Maybe that's what you are looking for? Depends on how well you are familiar with the basics. I have not read it btw.

6:29 tdammers: rritoch: yeah, that's the thing - their core business is education, and a text editor is a means to an end. Making it open source means there will be more contributions, more scrutinity, and better documentation, than they could afford to produce using a proprietary model, and selling software licenses is not the business they're interested in anyway

6:29 mungojelly: lodin_: hmm maybe! there's so many books about clojure i haven't even started to try to look through them and pick one

6:30 tdammers: likewise, when your core business is selling web hosting, then you benefit more from using and contributing to an open-source platform than you would if you were to develop your own proprietary platform

6:31 gilliard: visof__: something like (count (take-while zero? [0 0 1 2 3])) ?

6:31 rritoch: Speaking of financial models, my wife wants me to start a youtube channel on programming. Now that's certainly a case where I'd open source everything I produced.

6:32 Somehow I doubt the world is ready for the number of Fb0mbs I drop while coding, lol

6:32 wasamasa: hm

6:32 perhaps take a look at this livecoding website

6:33 I've heard some of the people there play the guitar for their viewers

6:34 tdammers: rritoch: when I'm programming, people can judge progress by the amount of swearing radiating from my desk - at first the frequency increases monotonically, then at some point it drops off dramatically, with just an occasional mild "oh fuck" every now and then for a few hours while I get my documentation and formatting in order

6:34 TEttinger: I like this stream http://livestream.com/tinykittens/tip

6:36 gilliard: visof__: I think the problem you're having is that your initial loop variables include a seq and separately the first item of the seq. But when you (recur) you are passing a seq and the first item from the previous seq.

6:40 rritoch: tdammers: I think I was like that at some point, but my wife is sensative to swearing so I've learned to hold it back somewhat, now it's more like a tsunami, once it passes everything just seems to work, but anyone or anything standing in my way tends to get their feelings hurt.

6:42 In extreme cases, hardware ends up getting RMA'd

6:42 gilliard: visof__: I commented on your gist, too.

6:42 tdammers: my abuse is strictly verbal

6:43 rritoch: tdammers: Heh, my abuse is strictly code, CPU & GPU cooking code in some cases.

6:48 tdammers: I suppose that's why I like clojure. It is very resitant to abuse and doesn't cry when you hand it expontential complexity +, it just does what you asked it to do without crying. (Stack overflow, out of memory, etc.)

6:48 tdammers: maybe I do things wrong, but I get a lot of crying from clojures

6:48 footlong stack traces, cryptic errors, surprising behavior

6:49 mavbozo: ,(get get get get)

6:49 clojurebot: #object[clojure.core$get 0x2eac0d45 "clojure.core$get@2eac0d45"]

6:49 tdammers: maybe the problem is that it won't tell me when I'm asking something that doesn't make sense

6:50 rritoch: tdammers: Hmm, I really don't know what design pattern your using, but it sounds like you need to make more use of clojure's lazy methods. I don't recall ever breaking the stack or running out of memory in clojure.

6:51 tdammers: no, I'm not breaking the stack or anything, just triggering all sorts of runtime exceptions

6:59 rritoch: tdammers: Aaa. Well runtime exceptions aren't so bad. Since clojure is open source you can usually use the clojure source code to see why clojure isn't doing something the way you expected it to. Runtime exceptions are soft limits and there are usually fairly clear paths around them, including CPU intensive "paranoid" defensive programming.

6:59 tdammers: I'm talking about my own code doing surprising things and exceptioning out

7:00 and defensive programming being CPU intensive at runtime is kind of really bad in my book

7:03 rritoch: tdammers: I'm not a by-the-books developer. I have no problem throwing out all of the rules to get something to work. Once it works than you can optimize. Those books were written to make money, they weren't written to solve every problem that you will be faced with.

7:05 tdammers: I find that when I try "get shit done" mode, by the time I end up with something that almost works, the only meaningful thing I can do with it is throw it out the window and start from scratch

7:06 I prefer evolving my abstractions and my code along with my understanding of the problem

7:06 I form a hypothesis, write a solution based on it, see if it fits the problem, adjust the hypothesis, adjust the code to match it, rinse and repeat

7:07 and it works best when I aim for the best possible quality from the get-go, more or less

7:12 rritoch: tdammers: Your solution, while by the books, will only work to solve problems that are logical and solvable with current technology. The scientific process itself can't solve paradoxes, to solve many paradoxes you have to create a new system which operates outside the rules and doesn't contain the paradox. Comparable to using calculus isntead of algebra to solve a problem.

7:15 tdammers: rritoch: if it's not solvable with current tech, trying to solve it anyway and ignoring the theory doesn't make it the slightest bit more solvable

7:15 rritoch: tdammers: I can give you an exact example https://github.com/rritoch/clj-osgi-namespaces , while that code works, it breaks many rules.

7:16 tdammers: it runs on actual hardware, doesn't it?

7:17 the rules it breaks are conventions; it is still limited by formal logic, just like any other computer program

7:17 rritoch: tdammers: Sure, but it breaks the "rules" of clojure, by using reflection to bypass the rules of java, specifically the modification of static final's.

7:17 tdammers: yes, so?

7:17 rules still exist

7:18 and they're just as rigid and formal

7:18 just not explicit maybe

7:18 rritoch: Sure, the rules still exist, but to solve that particular problem I needed to develop code that operated outside of those rules.

7:18 tdammers: the rules you're breaking are not the ones I'm talking about

7:19 rritoch: tdammers: No, every problem is different, and in many cases there is a solution within the rules of best practices. In many cases you need to break best practices and get something functional before you'll see a solution that is within best practices.

7:20 tdammers: but again, that's not the kind of rule I'm talking about

7:21 rritoch: tdammers: Again using the same system as an example, when that project started it was a fork of clojure as I couldn't find a way to do it within the rules of clojure. Eventually I found a way around it, with the help of some #java experts.

7:22 tdammers: It sounds like you have a specific problem your trying to solve. Why not just post the code and let this room find the solution?

7:22 tdammers: the thing is, I break rules like these all the time, when that's appropriate - but when I do, I do it because the programming language I'm using doesn't have the expressive power to encode the abstractions I need; I don't fool myself into thinking that I am somehow transcending the realm of formal logic

7:23 no, I have about a hundred small specific problems every day, and I can solve them, that's not the problem

7:23 rritoch: tdammers: This isn't a case where I transcended formal logic, but I have.

7:24 tdammers: There's a specific problem I needed to solve that only had a solution in the realm of high dimensional fuzzy logic (~7 dimensions).

7:24 tdammers: you always end up with a formal system to express what you want the computer to do

7:24 whether you do that on purpose or not is a different matter

7:24 as is the question how sure you can be that that formal system matches your requirements and expectations

7:25 you are always going to simplify things, too, in order to make them fit into such a formal system

7:25 (almost always, anyway)

7:27 rritoch: The exact problem was this. 1. The system must be able to determine the users X address, where X is one of (mailing, physical, billing, primary, primary-*). 2. Do not require users to enter X

7:28 This solution doesn't exist in the realm of logic, it is a paradox. The solution exists within the realm of fuzzy logic.

7:28 With a little bit of AI "magic".

7:28 tdammers: That's not the exact problem, and it's not a paradox either

7:29 if what you wrote there were the full problem exactly, the correct solution would be to make a random guess

7:29 rritoch: tdammers: lol, wrong

7:29 tdammers: you used more information

7:30 rritoch: tdammers: Randomly choosing an address wouldn't have solved the problem, but that would have been a funny solution to use.

7:30 tdammers: with the information at hand, that solution is as good as any

7:30 rritoch: tdammers: It would have saved me from solving the problem

7:31 tdammers: my point is, you had more information about the problem than that

7:31 rritoch: tdammers: Anyhow, what I did was developed a 7 dimensional fuzzy logic system, where each address type is represented as a dimension

7:32 tdammers: fuzzy logic is a well-defined formal system you know

7:32 it's not boolean logic, but it's just as formal

7:32 rritoch: tdammers: A weighted average of known implications is computed such that a mailing address is a mailing address 1, but a maybe mailing address (.5) that is a billing address, is probably a mailing address by implication that most billing addresses are mailing addresses.

7:32 tdammers: yes, I know how fuzzy logic works

7:33 I still don't see a paradox there

7:33 rritoch: tdammers: So I coded in all of the implications, producing the solution without just randomly selecting an address because the client's specification wasn't logical.

7:33 tdammers: I still maintain that you had more information

7:34 rritoch: This is just one example where the scientific process which leads you to the conclusion of picking a random address, is wrong, because there is still enough information to come up with a solution that will be accurate 99% of the time.

7:34 tdammers: you didn't disclose the extra information

7:35 rritoch: tdammers: There isn't any extra information, other than the establishment of weighted implications that address X[1] -> X[2] at some probability.

7:35 tdammers: so where do those probabilities come from?

7:36 what do you know about the user?

7:36 what do you know about addresses in general?

7:36 what's the situation, even?

7:36 you know a lot about these things

7:36 and you encode that knowledge in your code

7:36 the knowledge isn't formal, but the code is

7:37 it has to be, because we haven't yet figured out how to build computers that can reliably interpret vague requests

7:37 rritoch: tdammers: That isn't entirely true

7:37 tdammers: not for programming purposes anyway

7:38 rritoch: tdammers: See https://en.wikipedia.org/wiki/Cyc

7:38 Now that would be a nice clojure project :)

7:39 tdammers: haha

7:40 https://en.wikipedia.org/wiki/Cyc#Knowledge_base

7:40 note how that part describes a very rigid grammar

7:40 rritoch: Either way, my theory stands. To find solutions to some problems you have to work outside the rules of traditional logic or current technologies.

7:40 tdammers: clojure is a current technology

7:41 you cannot make clojure do something that clojure cannot do

7:41 you are bound by its hard rules

7:41 rritoch: Well, cyc is barely a current technology, unless you happen to have Mark Zuckerberg money

7:41 tdammers: they may not align with the stated rules, or the conventions...

7:42 rritoch: tdammers: Sure you can. The link I provided earlier produces a feature in clojure that clojure cannot do in it's current state. It uses Java and Reflection to bypass those rules.

7:42 tdammers: what you *can* do, however, is tear down existing abstractions and build new ones

7:43 using Java and Reflection are explicitly things that clojure can do

7:44 rritoch: Ok, well now your just playing games with the concept of "rules". Using reflection to bypass restrictions is not within the "rules" of best practices.

7:44 tdammers: time travel, allocating more RAM than your machine can provide, traversing infinite lists in finite time, calculating all the digits of Pi, accurately predict the future, actually losslessly reversing lossy compression, etc., are things clojure absolutely cannot do

7:45 I'll say it again, "best practices" aren't the rules I'm talking about

7:45 rritoch: tdammers: Ok, so let me solve these impossible problems you present.

7:46 First, time travel. Solved, solved again. We are already traveling through time at different rates.

7:46 tdammers: dude.

7:46 oddcully: wasn't there some clojure-ot channel?

7:46 rritoch: Second of all, allocating more ram than machine can provide. Compression, solved. Has been solved for awhile.

7:46 oddcully: sorry for beeing a party pooper

7:46 tdammers: oddcully: np, this is getting ridiculous anyway

7:49 rritoch: Well, as it is extremly relevant, and not to continue this useless conversation, traversing infinite lists in finite time, clojure not only does, but does so elegantly with lazy lists.

7:52 tdammers: no, it doesn't. It traverses unbounded lists in linear time and in constant space, but if the list is actually infinite, so is the traversal.

7:53 you can *create* lists that are actually infinite, and you can pass them around and perform finite operations on them in finite time, but a full traversal of an infinite list cannot be done in finite time

7:54 it's not even possible to devise a completely accurate finiteness checker for lists that is guaranteed to run in finite time

7:54 (the halting problem, basically)

8:05 rritoch: This poor room is silent. Can we at least debate how a clojure implementation could solve the lossy compression problem?

8:10 kavkaz: Whattup Clojure fam

8:11 mungojelly: i just made my first finger tree! wow these seem super useful

8:14 kavkaz: mungojelly: Haha congrats, I'm looking it up right now

8:17 mungojelly: it's like, build me this list, but while you're at it, keep track of quality X of the things in the list, so i can quickly get to wherever in the list the X adds up to the amount i want, and then seamlessly invisibly maintain that accounting of everything as meanwhile i heedlessly mess around with the contents

8:37 snowell: Anybody know of an easy way in cursive clojure to "fix" the indentation of a block?

8:37 Or is that more of a "set up IntelliJ to do that" sort of thing?

8:37 If I'm writing code live, it does the indentation perfectly, but if I copy/paste somewhere, it can be misaligned with what I'm pasting it into

8:39 oddcully: snowell: in regular intellij its ctrl-alt-l (or `=` if in vi mode). if nothing is selected the whole file gets indented

8:40 snowell: oddcully: I love you

8:40 (inc oddcully) ; And my brain thanks you

8:40 oddcully: hehe, yw

8:44 kavkaz: snowell: How are you liking cursive?

8:44 How does it compare to emacs + Clojure mode + CIDER?

8:44 snowell: kavkaz: After being against it for no reason, I'm actually loving it, especially with the structural editing

8:45 And having never used emacs, I can't really make a fair comparison

8:45 kavkaz: snowell: structural editing?

8:45 snowell: https://cursiveclojure.com/userguide/paredit.html

8:45 I can really only compare it to Light Table, and it's light years better

8:47 kavkaz: snowell: so basically it's editing focused on the selected expression?

8:47 snowell: And easily moving elements into/out of structures

8:48 kavkaz: Ah cool

8:53 mungojelly: i assume there's some way to get your expression processed by some clojure and given back to you?

8:54 in cursive i mean, so you can say in clojure how you want to change things

9:05 kavkaz: mungojelly: I don't understand what you're saying lol

9:06 But code is data, you can change how the Clojure language works

9:06 haven't really done that myself though

9:06 snowell: Well you can use a REPL

9:06 Cursive isn't a language, it's an IDE

9:07 Apologies if I misunderstand what you're asking :)

9:07 mungojelly: what interface does cursive present to you if you're a clojure program

9:08 kavkaz: mungojelly: Which specific part of cursive? Are you talking about the REPL?

9:08 oddcully: mungojelly: you want to pass an expr from the ide into a clojure program, transform it have the result placed, where the original went off?

9:09 mungojelly: oddcully: sure well or somewhere else too i'd think why not

9:10 i can't find cursive source, is it closed source? :o

9:10 oddcully: yes

9:10 and it will cost money at some point in the future

9:10 mungojelly: weeeeeiiiiiiiird why

9:11 snowell: I don't think it's weird that a dev wants to get paid for his/her effort and time

9:11 mungojelly: so then of course you don't get proper hooks into anything because then plugins would easily transport to a different ecosystem and dissolve the supposed value of holding you there. :(

9:15 oddcully: mungojelly: the audience for cursive to me seems clearly the "im fed up with fiddling vim/emacs/younameit" folks. it's easy to setup, debugger, refactoring, ...

9:15 the platform to add new things is the intellij api

9:15 everything beyond that, cfleming, the author, can for sure shed more light on

9:15 mungojelly: ok well i can cross cursive off my list of things to look into then, one down

9:18 pvinis: hello. i want to make a little daemon-kind application, that i can control through command line and also a little gui based on reactjs. i was thinking, should i make the application in clojure, and have a server to connect to and control it, or should i make the application with the gui in clojurescript and react, and just connect the command line app to that somehow?

9:22 Igor___: How can I catch exception when I run Aleph with Gloss frame (string :utf-8) and send non utf8 byte (e.g. "^c" - ctrl+c byte) via telnet?

9:22 kavkaz: mungojelly: If you're really planning to modify your environment, look into emacs

9:26 mungojelly: kavkaz: i do use emacs but i'm not very good at it, i just poke around at characters with it like any boring text editor mostly

9:51 ane: is it good practice to have unit tests run satisfies? checks for protocols?

9:51 that is to test whether record X satisfies some protocols

9:52 opqdonut: I think that's a good first step

10:17 gfrederi`: gilliard: luxbock: lodin_: I always meant https://github.com/gfredericks/four to be a good supplementary lib for randomness; e.g., the test.check splittable generator could be copied over there

10:17 there could also be a contrib lib or two eventually I imagine

10:18 srbaker: heya folks

10:19 hopign someone can help me figure this out, i've been beating on it for days. just waiting for a paste

10:19 https://www.refheap.com/109615

12:34 mungojelly: i like the idea of #_ for comments

12:39 sobel: in clojure?

12:39 oh right, you don't like to leverage existing solutions. i remember you.

12:40 mungojelly: this is a suggestion from Ron Toland, apparently his company uses it in their dialect

12:40 all very dialectical around here with the no sharing

12:41 but anyway it's a good idea! that's much more harmonious. ;; is a textual syntax, no? that's a weakness.

12:42 TEttinger: ; is until end of line

12:42 ;; is the same as ;

12:43 mungojelly: yeah, "end of line" is a funny concept, why have a construct that starts ; and ends \n among ( ) { } [ ] are much clearer and less fragile, #_"comment" fits in better

12:43 TEttinger: true, but most code does have the need for line comments at least sometimes

12:43 mostly inline docs

12:44 mungojelly: couldn't you put #_"This line sucks!" at the end of the line?

12:44 TEttinger: indeed you could, though I'm not sure it would highlight super well

12:45 even the dumbest syntax highlighters can do ; to EOL

12:46 and on the web there's plenty of bad ones

12:46 mavbozo: mungojelly, so you prefer multiline comment like this https://www.refheap.com/109618 ?

12:47 TEttinger: well that actually is something I like for multiline comments

12:48 mungojelly: idk if it were up to me i'd like to put lots of metadata, way more explanation and decoration than action

12:48 like i think it would be nice if we decorated all our functions with colors. then you could colorize everything very distinctively and sensibly.

12:49 TEttinger: it would provide a nice visualization for profiling, up to about 8 colors

12:50 blake_: I'm trying to figure out if core.logic is useful for what are essentially giant if/case/cond type setups.

12:51 Here's a sample table: https://www.refheap.com/109619

12:52 hiredman: you likely want a rules engine

12:52 like https://github.com/hraberg/mimir or drools

12:53 blake_: Maybe so. Our situations don't seem to be as complex as drools allows, such that drools seems like serious overkill.

12:53 hiredman: core.logic is more like, here are the relationships between these variables, here are values for some of the variables, what possible values are there for the other variables such that all the relationships still hold

12:53 it is search

12:54 blake_: hiredman: OK, cool. Thanks! I'll save my digging into that for later.

12:55 hiredman: the classic algorithm for rules engines is called RETE, and there are a number of pure clojure implementations that are likely easier to work with than drools

12:55 mimir was just one of the hits on google for `clojure rete`

12:58 ane: is it possible to have two sets of annotations for a fn, like (defn foo ([^String x] ...) ([^Number y] ...)), a kind of pattern matching based on type

12:59 hiredman: no

13:08 justin_smith: ane: you can effectively do that with a protocol or multimethod

13:08 but not with that specific syntax

13:09 ane: oh? it supports types?

13:09 justin_smith: both can dispatch by type

13:10 ane: how do protocols do it?

13:11 justin_smith: ,(defprotocol IFoo (frob [this]))

13:11 clojurebot: IFoo

13:11 justin_smith: ,(extend-type String IFoo (frob [this] (clojure.string/reverse this)))

13:11 clojurebot: nil

13:11 justin_smith: ,(frob "hello")

13:11 clojurebot: "olleh"

13:12 justin_smith: ,(extend-type Number IFoo (frob [this] (* this this this)))

13:12 clojurebot: nil

13:12 justin_smith: ,(frob 42)

13:12 clojurebot: 74088

13:12 justin_smith: ,(frob 1/8)

13:12 clojurebot: 1/512

13:12 justin_smith: ane: with a protocol you get better performance, and you can implement multiple methods in one protocol

13:13 ane: with multimethods you get more flexibility of dispatch (which you don't actually need)

13:15 ane: yah i was doing something like (defn foo [x y] (let [t1 (type x) t2 (type y)] (cond (and (identical? x String) (identical? y String)) (concatenate the strings))))

13:16 TEttinger: (identical? t1 String), you mean?

13:16 ane: yeah oops

13:17 i wonder if that's possible with a protocol, a multimethod worked just fine, in fact it's bloody brilliant, but i have two types i need to dispatch on

13:18 TEttinger: that's the multi in multimethod

13:18 ane: yeah

13:18 justin_smith: TEttinger: no, if that was the case they would be called "arbitrarymethods"

13:19 because the dispatch is an arbitrary function of the inputs

13:19 hell, you could use a random number generator to dispatch and ignore the args

13:19 ane: (defmulti (fn [x y] [(class x) (class y)])) and so on

13:19 TEttinger: am I confusing multimethod with CLOS stuff?

13:20 justin_smith: well, multimethods are related to the CLOS stuff, but the multi refers to "multiple implementations" not "dispatches on multiple values" I thought

13:21 TEttinger: from http://clojure.org/multimethods : Clojure multimethods are not hard-wired to class/type, they can be based on any attribute of the arguments, on multiple arguments, can do validation of arguments and route to error-handling methods etc.

13:21 I suspect the multiple arguments thing is what we're after

13:22 ane: i would think it's multiple implementations

13:28 TEttinger: Your dispatching function can return any arbitrary value using any or all of its arguments. The next example defines a multimethod that takes two arguments and returns a vector containing the type of each argument, and a method that matches when each argument is a string:

13:28 http://www.braveclojure.com/multimethods-records-protocols/

13:28 *cough justin_smith* Incidentally, this is why they're called multimethods - they allow multiple dispatch, or dispatch on more than one argument.

13:29 ane: maybe it's not the cardinality of the arguments of the methods but the number of argument types

13:29 TEttinger: they also use an RNG to dispatch and ignore the args on the wikibooks examples

13:29 ,(defmulti types (fn [x y] [(class x) (class y)]))

13:29 clojurebot: #'sandbox/types

13:29 ane: i think i'm wrong about this though, dynamic dispatch is where there's just one

13:30 justin_smith: TEttinger: eh, I wouldn't call braveclojure an authoritative source

13:30 TEttinger: ,(defmethod types [java.lang.String java.lang.String] [x y] (str "Strings! " x " " y "!"))

13:30 clojurebot: #object[clojure.lang.MultiFn 0x7503eb9f "clojure.lang.MultiFn@7503eb9f"]

13:31 TEttinger: ,(types "hey" "justin")

13:31 clojurebot: "Strings! hey justin!"

13:31 sobel: is there a section on other authoritative sources, on clojure.org?

13:31 TEttinger: ,(types "hey" 1)

13:31 clojurebot: #error {\n :cause "No method in multimethod 'types' for dispatch value: [java.lang.String java.lang.Long]"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "No method in multimethod 'types' for dispatch value: [java.lang.String java.lang.Long]"\n :at [clojure.lang.MultiFn getFn "MultiFn.java" 156]}]\n :trace\n [[clojure.lang.MultiFn getFn "MultiFn.java" 156]\n [clojure.lang.Mult...

13:31 TEttinger: sobel: http://clojure.org/multimethods

13:31 sotojuan: What's a good fun project I can write in Clojure? Been learning through math-y problems so far.

13:32 TEttinger: it's not a super great intro it seems, the official one

13:32 justin_smith: TEttinger: it's an excellent intro I think

13:32 TEttinger: justin_smith: but... it didn't tell you important stuff about it actually doing multiple dispatch

13:33 justin_smith: ? it absolutely does!

13:34 TEttinger: a quote from that page: "(defmulti bar (fn [x y] [x y])) (defmethod bar [::rect ::shape] [x y] :rect-shape) (defmethod bar [::shape ::rect] [x y] :shape-rect)"

13:35 and it also covers things like heirarchies and prefer-method that almost no other source touches

13:35 TEttinger: yeah, I had no idea what that did tbh. it doesn't help that it links to the docs on http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/defmethod ... and defmethod has essentially no docs

13:36 justin_smith: TEttinger: the text on that page (outside the examples) explains what is happening there, but would have been more tedious to quote into this channel

13:36 ane: justin_smith: is the performance improvement in protocols due to compile time magic? i understand multimethods are runtime

13:36 TEttinger: I mean I read it and still didn't get it

13:36 justin_smith: ane: the dispatch has less work to do

13:37 ane: ok. is it possible for it to work on two parameters then?

13:37 TEttinger: yes.

13:37 err

13:37 justin_smith: TEttinger: it's a multimethod that dispatches based on the values of the two args, and it uses heirarchies to pick the apropriate method

13:37 ane: how do you extend two types at the same time o_O

13:37 TEttinger: for protocols? no idea. I pasted an example for multimethods

13:37 justin_smith: ane: protocols only dispatch on the first arg

13:38 so if you can't differentiate impls to call based on the first arg alone, you might need multimethods

13:47 ane: ok. used a multimethod, was the simplest

13:47 is there any difference between using [(class x) (class y)] and [(type x) (type y)]

13:48 justin_smith: ,(type ^{:type "FOO"} {})

13:48 clojurebot: "FOO"

13:48 justin_smith: ,(class ^{:type "FOO"} {})

13:48 clojurebot: clojure.lang.PersistentArrayMap

13:48 ane: hm

13:48 justin_smith: so type gives you extra power

13:48 in case you want to differentiate an existing IMeta by metadata

13:48 Bronsa: I can't imagine why that'd be useful

13:49 I guess it predates the existence of records?

13:49 justin_smith: Bronsa: when all you want is the type dispatch, and don't need the other features of defrecord?

13:49 or that

13:50 Bronsa: not totally clear on how it's best used (or even if it has a great use), just answering the "what's the difference between type and class" question succinctly :)

13:50 Bronsa: justin_smith: I'd rather the type be explicit if I want to dispatch on it, either by concrete class or by an :op/:type field

13:50 justin_smith: yes, I'd agree

13:51 Bronsa: justin_smith: yeah yeah I wasn't antagonizing you, just wondering if `type` is still useful in clj 1.7

13:55 amalloy: Bronsa: it's used for print-method

13:56 but it certainly predates defrecord/deftype, and was mostly used to let you pretend user-defined "types" (that are just maps) are a distinct type

13:57 Bronsa: amalloy: I was looking at that, but it seems like print-method just supports `type`, it doesn't *use* it

13:57 amalloy: well, right

13:59 if print-method didn't support type, it would be kinda hard to create a user-defined type that acts like a map and prints differently. defrecord doens't let you override toString, and you don't want to have to implement ILoookup by hand for every deftype

13:59 otoh, nobody is actually using this feature really, so maybe it is not an important one

13:59 Bronsa: amalloy: one could just extend print-method to the record type

14:00 amalloy: oh, indeed

14:02 justin_smith: this might not be helpful, but here's a crossclj snapshot of who uses clojure.core/type (of course it's harder to look up where it's being used intentionally for the metadata feature) https://crossclj.info/fun/clojure.core/type.html

14:03 Bronsa: (inc crossclj)

14:03 :(

14:04 justin_smith: I'm pretty sure I've at least once used `type` instead of `class` because it's one char less to type

14:04 justin_smith: haha

14:06 Bronsa: oh I never realized struct maps instances don't preserve the struct type

14:07 amalloy: what do you mean, the struct type?

14:07 Bronsa: the struct name

14:08 like, (defstruct point :x :y) (def p (struct-map point :x 1 :y 1)) < there's no way to know that p is a `point`

14:09 justin_smith: I guess that's part of why we don't use structs any more

14:10 Bronsa: I wonder if there's still instances where structs might have some performance advances over maps/records

14:10 I never actually read their implementation

14:11 looks like it's an array+extmap instead of fields+extmap of records

14:49 sdegutis: Do you find that your top-level System component often has like a dozen subcomponents directly under it?

14:51 justin_smith: sdegutis: as in a dozen components that each have sub-components, or just a dozen subcomponents?

14:52 because I have more like 8 sub-components, but it totally depends on how many stateful moving parts your project is going to have...

14:52 sdegutis: Right.

14:52 clojurebot: excusez-moi

14:52 justin_smith: but I don't have nested sub-components

14:53 because I avoid the whole information-hiding thing in app level code

14:53 sdegutis: Yeah, I don't have nested subcomponents. I have a top-level System, which has 9 components, and sometimes a function in one component will take another as an argument, but they aren't hierarchically structured.

14:53 justin_smith: yeah, totally normal then

14:53 sdegutis: And because of this, my System defrecord takes like 9 or 10 arguments. It feels a bit unweildly.

14:54 or whatever that words supposed to be

14:54 justin_smith: wait, I just have a system-map and dep map literals, and I don't do a defrecord for my top level...

14:55 in fact I even use optional args to filter components out (eg. start up everything but the http server, and those components which depend on the http server)

14:55 sdegutis: Hmm yeah I don't think I technically need a defrecord for the System map. That said, I think a map might suffice for any of my components.

14:56 justin_smith: well, you still want a custom start/stop for most of them don't you?

14:56 sdegutis: But I'm pretty sure there's value in using defprotocol/defrecord for at least some of the components, I just can't remember what.

14:56 Oh right, that's the value. Different start/stop methods.

14:56 Great, thanks.

14:56 justin_smith: right, you don't need that at the top level

14:56 it's just a call to component with a map of components and a map of maps of deps

14:56 sdegutis: Right. It just calls interface functions, so it's the same at that level.

14:57 The only different thing is the creation of the System component, which is just a function anyway.

14:57 so (memory-system) vs (live-system)

14:57 Thanks justin_smith.

14:57 I like keyword-based APIs on account of how I have to import/require fewer things.

14:58 I wonder if it makes sense to just turn all my components into functions that return maps, some of the keys of which are functions.

14:58 Like, why even bother with defprotocol/defrecord?

14:58 justin_smith: sdegutis: you should check out how onyx does things

14:58 keyword all the things!

14:58 sdegutis: http://www.macupdate.com/app/mac/11582/onyx ew

14:59 justin_smith: I mean onyx as in the clojure distributed processing tool that mdrogalis makes

14:59 sdegutis: oh cool

15:00 justin_smith: in your opinion when would you use a defprotocol/defrecord rather than just a map?

15:01 justin_smith: sdegutis: when I need to use or support protocols

15:18 sdegutis: justin_smith: with protocols you didn't write, right?

15:19 justin_smith: so then do you often have :keys refer to functions, that you call like ((:key m) args ...)?

15:28 pseudonymous: I'm trying to wrap my head around loop&recur - and failing miserably at that (yay!). Matters are made worse by me having to kill my cider repl session buffer and making a new one each time it gets into an infinite loop (with lots of printing involved). Is there a way to safeguard against this ? (yes, I'm using emacs)

15:30 tcrayford____: sdegutis: also reminder that defrecord is much faster than maps for known key lookups

15:31 sdegutis: tcrayford____: Ah, didn't think of that!

15:31 tcrayford____: see like, KeywordLookupSite and such

15:31 sdegutis: tcrayford____: Does that count function-like method-calls, like (foo r) where foo is defined inside a defprotocol?

15:32 justin_smith: sdegutis: well, protocol method calls are faster than function calls, yes, but this is a separate speedup - field access for defined record fields is faster too

15:32 tcrayford____: protocol calls are noticeably faster if the implementation is defined inside a defrecord/deftype rather than outside it

15:32 sdegutis: Ah, like (:foo r)

15:32 justin_smith: sdegutis: in both cases hash lookups are replaced by direct index, more or less

15:33 tcrayford____: because var lookup is avoided right?

15:33 sdegutis: This, plus typo-safety, plus a defined list of public methods, seems like a good reason to keep my current protocol/record based setup.

15:33 tcrayford____: justin_smith: it's worse than that. Go look at how protocols *actually* work

15:33 amalloy: pseudonymous: C-c C-c probably cancels the loop

15:35 justin_smith: i would be surprised to find that protocol method calls are any faster than an ordinary function call; rather, they are probably a bit slower. the reason protocols are faster on the whole is because calling them avoids the type-dispatch you'd otherwise do inside your ordinary function instead, and *that* would slow you down

15:36 if the type dispatch is unnecessary (because you are replacing a monomorphic function with a protocol method), just using a regular function is probably faster

15:36 tcrayford____: amalloy: reminder that the JVM can optimize type based conditionals inside function definitions as well though

15:36 the jvm: how does it work

15:36 like if you do code like

15:36 (if (instance? java.util.Map x) thing1 (if (instance? java.util.Collection x) thing2))) the JVM can PIC that

15:38 amalloy: PIC?

15:38 the only thing i can guess that sorta fits there is per-instance callsite

15:38 sdegutis: amalloy: I thought protocol calls were just Java method calls and thus really fast?

15:38 tcrayford____: polymorphic inline cache

15:38 amalloy: sdegutis: calling a function is just a java method call

15:38 sdegutis: oh.

15:38 nm then

15:38 tcrayford____: + a var deref + +

15:39 sdegutis: Which protocol calls still have I presume

15:39 amalloy: a protocol function is looking something up in a hashmap and then calling some java method

15:39 tcrayford____: amalloy: not always

15:39 it's

15:39 amalloy: tcrayford____: calling a *global* function involves a var deref. we call lots of non-global functions

15:40 tcrayford____: "check if the thing implements the interface that's hidden inside the protocol, if it does, call the interface method that corresponds to this function, otherwise look up the thing in the cache"

15:40 * tcrayford____ knows how the sausage is made

15:40 amalloy: oh, that's right, the interface check is before the hashmap lookup

15:43 tcrayford____: anyway most judgements about "is X faster than Y" are BS anyway because of the JVM. Benchmark it if it matters, with a good benchmarking mechanism, otherwise ignore it. In most clojure apps I don't expect this level of thinking about performance to matter all that much

15:45 TEttinger: I'm curious what the clojure community's ideas on this are. There's an open issue on a java lib that I've inherited and am actively adding to, relating to taking a heavily-used Coord type (currently just two mutable ints, x and y) and making it immutable

15:46 clojure had good immutable collections that also share structure, and I'd like to have a way to minimize GC on Coords

15:47 ed-g: Hello, has anyone used BYTEA columns in Postgres? How do I insert and retrieve files using them via JDBC? (exec-raw db ["insert into files (file) values (? :: bytea)" [ (slurp "/path/to/file") ]]) gives errors

15:47 TEttinger: the fastest way we've thought of so far in java is to bitwise or the two ints into one long (could also be shorts and an int, x and y never should go above 2^15 under any circumstance).

15:48 tcrayford____: TEttinger: bitwising them seems dope to me

15:48 TEttinger: it would be better if I could somehow alias the type...

15:48 tcrayford____: means you can stick a tonne of em in an array without the usual JVM problem of cache misses everywhere you look as well

15:48 yeah haha :(

15:49 TEttinger: now there's no way to restrict values to always being Coords, you could pass total garbage in easily

15:50 a possibly weirder solution involves two factors: strings are already immutable, chars are 16-bit, and strings can be interned

15:50 tcrayford____: just carry on praying real values land properly in java 9 and that all of your clients can upgrade to java 9 when it releases?

15:51 TEttinger: Android is a target, hence the concern about GC and static

15:51 tcrayford____: ah yeah

15:51 and likely android ain't getting dem values either :(

15:51 TEttinger: (static variables can outlive your application in some cases, and persist into the next run)

15:51 tcrayford____: oh for a typedef

15:57 amalloy: TEttinger: what does clojure's immutable shared-structure collections have to do with minimizing gc on coords?

16:01 TEttinger: clojure seems to have a better way of handling immutable stuff

16:02 I'm sorta lost on the best way to have type safety, low-GC, and immutability on a pair type

16:05 tcrayford____: TEttinger: right now on the JVM: there's no good way of doing that :(

16:07 TEttinger: ...maybe. this is getting into black magic territory, but could an annotation produce a typedef-like effect?

16:08 ed-g: Is there a standard library function to convert a byte-array to a string containing hexadecimal digits?

16:09 TimMc: If there is I'll be annoyed because I've wanted something like that.

16:10 tcrayford____: there's one in apache commons

16:10 ed-g: TimMc, :-) It's not like its hard to write my own but I'm sure it will be slow for my gigs of data I need to load into DB.

16:11 tcrayford____: org.apache.commons.codec.binary.Hex/decodeHex

16:11 amalloy: http://stackoverflow.com/a/9855338/625403

16:12 tcrayford____: " Performance is equivalent to Commons Codec, which uses very similar code"

16:13 xemdetia: TEttinger, how static are these coords out of curiousity? I mean I am thinking more of 3d float sense which is not helpful :)

16:13 TEttinger: xemdetia: static as in unchanging or static in the belongs-to-class java sense?

16:13 xemdetia: static as in unchanging

16:13 sorry

16:14 TEttinger: they should never change, new ones should be different values. a long would correctly handle most of it

16:14 essentially I want either C++ or C# features and Java is right in the middle with neither

16:16 xemdetia: well would it be worth just *doing* it in c++ with android ndk? I forget if that is still supported

16:16 because it isn't like you have speed problems you just have memory management problems

16:18 TEttinger: hang on, you just gave me an idea

16:27 it's possible that the points could be mutable, then become immutable? I could have a "final int x, y;" pair of fields, an "int tempX, tempY" pair of fields, and a finalize() method that assigns x and y the values of tempX and tempY

16:33 amalloy: TEttinger: if you were going to actually do that you'd rather have a bool frozen

16:34 TEttinger: gah, I was fearing that.

16:34 a lot of the usage of the existing Coord stuff just uses the fields, not getX() and getY()

16:37 noncom|2: justin_smith: from your experience: what is better: having all state in one namespace or is it possible to have small local states on various pages?

17:04 justin_smith: noncom|2: this is in reagent, correct?

17:33 Balveda: I'm having an error trying to extend a protocol, telling me immutant.web.internal.ring.LazyMap does not exist when I do a lein run

17:35 Any ideas? I'm requiring it in the ns declarations

17:36 tcrawley: Balveda: try a `lein clean`

17:36 Balveda: Alright

17:36 tcrawley: are you trying to extend LazyMap itself?

17:37 Balveda: nope

17:37 Didn't work either

17:37 this is the code

17:37 http://pastebin.com/5FQNk8zm

17:38 tcrawley: what does your ns declaration look like?

17:39 Balveda: http://pastebin.com/DkdpKP3J

17:40 tcrawley: hmm, you may need to (:import immutant.web.internal.ring.LazyMap)

17:41 Balveda: Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: LazyMap in this context, compiling:

17:41 tcrawley: I'm curious why you need to extend the protocol to LazyMap specifically though, you should be able to extend to java.util.Map

17:41 Balveda: er

17:42 made a mistake

17:42 oh, there's an idea

17:42 I'll try it out

17:42 tcrawley: which would be more general

17:44 Balveda: that did it

17:44 thanks

17:45 tcrawley: my pleasure!

17:45 amalloy: tcrawley: extending a protocol you don't own to a type you don't own is dubious

17:46 * tcrawley owns nothing here

17:47 Balveda: (inc tcrawley)

18:09 lodin_: amalloy: I'd say it's OK at an application level, but not in a library (since you can end up with conflicts and render other libraries unusable).

18:11 Balveda: is there any middleware in the luminus defaults that could be interfering with a ring response redirect?

18:12 As in, I'm doing a response/redirect but it's just printing the html in the console rather than redirecting

18:21 sdegutis: justin_smith: Do you use jetty-ring-adapter? If so, how do you integrate that with start/stop, seeing as the create-server is private and only run-server is public?

18:31 domokato: is record access supposed to be faster than map access?

18:33 sdegutis: justin_smith: I guess I can do (.stop server) and GC it, and create another one when the time comes...

18:34 domokato: nevermind. i thought my timings were coming out the same, but my code was just wrong

18:44 sdegutis: nm found https://github.com/weavejester/ring-jetty-component/blob/master/src/ring/component/jetty.clj

18:44 Looks like I really ought to start using real-life Components, not just records.

19:04 TEttinger: ,(defmacro pi [] `(float 3.141592))

19:04 clojurebot: #'sandbox/pi

19:04 TEttinger: ,(pi)

19:04 clojurebot: 3.141592

19:06 TEttinger: I'm curious if anyone knows if that method of declaring a "primitive constant" has some flaw I haven't seen. AFAIK, defining a value boxes it and I don't know how you typically get around that

19:20 neoncontrails: TEttinger: Would you expect otherwise? I'm not being snarky, just curious. In my mind, functions are always preceded by parens, and macros are a kind of function (even when they have 0-arity)

19:42 TEttinger: neoncontrails: yeah, I'm just unsure of any other way to propagate (float 3.141592) into the code without storing it as a capital-F Float and suffering boxed math issues

19:43 neoncontrails: Oh, I see. Math/PI is out of the question?

19:44 jeremylite: TEttinger: if it's a double, you can type hint function arguments to not box it

19:45 neoncontrails: ,(defmacro pi [] '(float 3.1415926535897))

19:45 clojurebot: #'sandbox/pi

19:45 neoncontrails: ,(def pie (pi))

19:45 clojurebot: #'sandbox/pie

19:45 neoncontrails: ,pie

19:45 clojurebot: 3.1415927

19:45 neoncontrails: That work?

19:45 jeremylite: neoncontrails: he's talking about java's boxed primitives

19:45 float vs java.lang.Float

19:46 justin_smith: with the macro, clojure shouldn't need to box

19:46 neoncontrails: Ohh, right. The autoboxing behavior

19:53 TEttinger: justin_smith: can you elaborate?

19:53 ,(defmacro piii [] 3.1415926535897)

19:53 clojurebot: #'sandbox/piii

19:53 TEttinger: ,(piii)

19:53 clojurebot: 3.1415926535897

19:54 TEttinger: would that box it?

19:54 jeremylite: i'm finding this difficult to debug in a repl

19:54 TEttinger: no kidding. try: (set! *unchecked-math* :warn-on-boxed)

19:54 ,(set! *unchecked-math* :warn-on-boxed)

19:54 clojurebot: #error {\n :cause "Can't change/establish root binding of: *unchecked-math* with set"\n :via\n [{:type java.lang.IllegalStateException\n :message "Can't change/establish root binding of: *unchecked-math* with set"\n :at [clojure.lang.Var set "Var.java" 221]}]\n :trace\n [[clojure.lang.Var set "Var.java" 221]\n [sandbox$eval145 invokeStatic "NO_SOURCE_FILE" -1]\n [sandbox$eval145 invoke "NO_S...

19:55 justin_smith: well, that works locally

19:55 TEttinger: ,(with-bindings [*unchecked-math* :warn-on-boxed] (* 2 (piii)))

19:55 amalloy: why not just (def ^:const pi 3)

19:55 clojurebot: #error {\n :cause "Unable to resolve symbol: piii in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: piii in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: piii in this co...

19:55 TEttinger: ,(defmacro piii [] 3.1415926535897)

19:55 clojurebot: #'sandbox/piii

19:55 TEttinger: ,(with-bindings [*unchecked-math* :warn-on-boxed] (* 2 (piii)))

19:55 clojurebot: #error {\n :cause "java.lang.Boolean cannot be cast to clojure.lang.IMapEntry"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.Boolean cannot be cast to clojure.lang.IMapEntry"\n :at [clojure.lang.Var pushThreadBindings "Var.java" 317]}]\n :trace\n [[clojure.lang.Var pushThreadBindings "Var.java" 317]\n [clojure.core$push_thread_bindings invokeStatic "core.clj" 1818]\n [c...

19:55 justin_smith: TEttinger: at compilation time, the macro is expanded, so it should not need to box a value coming directly from a macro

19:56 TEttinger: amalloy: I wasn't aware of ^:const

19:56 amalloy: i don't think clojure will do any math on float primitives anyway

19:56 so all you could really do with such a const is pass it to a java method

19:56 TEttinger: ,(doc with-bindings)

19:57 clojurebot: "([binding-map & body]); Takes a map of Var/value pairs. Installs for the given Vars the associated values as thread-local bindings. The executes body. Pops the installed bindings after body was evaluated. Returns the value of body."

19:57 TEttinger: ,(defmacro piii [] 3.1415926535897)

19:57 clojurebot: #'sandbox/piii

19:57 TEttinger: ,(with-bindings {*unchecked-math* :warn-on-boxed} (* 2 (piii)))

19:57 clojurebot: #error {\n :cause "java.lang.Boolean cannot be cast to clojure.lang.Var"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.Boolean cannot be cast to clojure.lang.Var"\n :at [clojure.lang.Var pushThreadBindings "Var.java" 318]}]\n :trace\n [[clojure.lang.Var pushThreadBindings "Var.java" 318]\n [clojure.core$push_thread_bindings invokeStatic "core.clj" 1818]\n [clojure.core$...

19:57 TEttinger: the heck...

19:57 ,*unchecked-math*

19:57 clojurebot: false

19:58 amalloy: TEttinger: (a) you want binding, not with-bindings; (b) using binding to set a compiler option doesn't work

19:58 TEttinger: ,(binding [*unchecked-math* :warn-on-boxed] (* 2 (piii)))

19:58 clojurebot: 6.2831853071794

19:58 TEttinger: it's not a compiler option is it?

19:58 you can set it at runtime

19:58 justin_smith: TEttinger: the reflection warnings happen on compilation

19:59 TEttinger: try eval inside the binding block

19:59 TEttinger: ,(binding [*unchecked-math* :warn-on-boxed] (eval '(* 2 (piii))))

19:59 clojurebot: 6.2831853071794

19:59 TEttinger: ,(let [p (piii)](binding [*unchecked-math* :warn-on-boxed] (eval '(* 2 p))))

19:59 clojurebot: #error {\n :cause "Unable to resolve symbol: p in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: p in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: p in this context"\n ...

20:00 TEttinger: ,(binding [*unchecked-math* :warn-on-boxed] (eval '(let [p (piii)](* 2 p))))

20:00 clojurebot: 6.2831853071794

20:00 TEttinger: so let bindings preserve primitive-ness?

20:00 amalloy: ,(binding [*unchecked-math* :warn-on-boxed] (eval '((fn [n] (+ 1 n)) 1)))

20:00 clojurebot: #error {\n :cause "denied"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6891]}\n {:type java.lang.SecurityException\n :message "denied"\n :at [clojurebot.sandbox$enable_security_manager$fn__835 invoke "sandbox.clj" 69]}]\n :trace\n [[clojureb...

20:00 TEttinger: ,(def p-uh 3.14)

20:00 clojurebot: #'sandbox/p-uh

20:01 TEttinger: ,(binding [*unchecked-math* :warn-on-boxed] (eval '(* 2 p-uh)))

20:01 clojurebot: #error {\n :cause "denied"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6891]}\n {:type java.lang.SecurityException\n :message "denied"\n :at [clojurebot.sandbox$enable_security_manager$fn__835 invoke "sandbox.clj" 69]}]\n :trace\n [[clojureb...

20:01 TEttinger: ah, we can't get compilr warnings

20:01 amalloy: why did it let TEttinger eval once?

20:01 TEttinger: because I didn't throw an unchecked warning

20:01 ,(binding [*unchecked-math* :warn-on-boxed] (eval '(* 2 3)))

20:01 clojurebot: 6

20:02 TEttinger: ,(binding [*unchecked-math* :warn-on-boxed] (eval '(* 2 p-uh)))

20:02 clojurebot: #error {\n :cause "denied"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6891]}\n {:type java.lang.SecurityException\n :message "denied"\n :at [clojurebot.sandbox$enable_security_manager$fn__835 invoke "sandbox.clj" 69]}]\n :trace\n [[clojureb...

20:02 TEttinger: when it throws the warning, something gets blocked by the sandbox

20:02 ed-g: (inc tcrayford)

20:02 (inc amalloy)

20:07 justin_smith: TEttinger: OK, so like I said a macro returning the float avoids reflection, right?

20:12 TEttinger: yep, it makes sense now, thanks justin_smith

20:16 irctc: quit

22:31 Guest___: What's the preferred lib for making http calls from ClojureScript?

22:36 justin_smith: Guest___: I think people usually use js/Ajax via interop

23:12 dnolen: Guest___: goog.net.XhrIo works fine, there are a few core.async based wrappers too

23:12 Guest___: Thanks. Taking a go at https://github.com/JulianBirch/cljs-ajax for now

Logging service provided by n01se.net