#clojure log - Jun 28 2017

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

0:41 mgaare: Why don't specs implement IFn

0:43 It would be so nice to have something like, (s/spec a-bunch-of-predicate-logic-here :gen useful-generator) and have the result be callable as a normal pred

1:01 amalloy: aren't specs able to do a bunch of things? conform a thing, act like a predicate, produce an error report...which of those things should it do when called as a function?

1:03 mgaare: I think they should act like a predicate

1:04 as it stands now, maybe I'ved missed it but I don't see a way to get the same functionality that, say, int? has. Where it can be used as a spec, can be called as a predicate function, and has a generator

1:04 amalloy: my point is, what if someone else disagrees? why should a predicate be the most interesting thing?

1:04 suppose i think it would be far better if it produced an error report instead

1:05 isn't it great that when i read your code, i can tell what you're using a spec for by what function you call on the spec?

1:06 mgaare: another solution would be if spec supported adding generators to functions

1:07 or I wonder if you could do that with fdef

1:07 hmm

1:07 doesn't seem that way

1:09 amalloy: and to your question, right now we both lose because they do nothing at all ;)

1:09 amalloy: no, i win because i actually think it's great to have named functions for doing things

1:11 mgaare: So do I, but it seems like our predicates are destined to be second class citizens to the built-in clojure ones, as they get generator support and we have no apparent way to add it to ours

1:13 amalloy: what's this about generator support for core functions? i haven't really kept up with development

1:17 mgaare: a whole slew of predicates in core have generators. So you can call s/gen on a variety of things like nat-int?, inst?, string? and so forth and it returns a generator. But the mechanism for this is a hard-coded list in clojure.spec.gen.alpha

1:23 amalloy: is it? i agree that that sounds pretty silly. i can't find the source for that, though

1:23 i could easily be missing it, of course. as i said, i'm not current

1:34 mgaare: it's a little tricky to trace. `s/gen` calls down to `gensub` which calls `specize` on the predicate, which calls `spec-impl` for objects, that reifies a thing that will call spec.gen.alpha/gen-for-pred to get a generator, which is this here https://github.com/clojure/spec.alpha/blob/master/src/main/clojure/clojure/spec/gen/alpha.clj#L187 that gets the generator out of this map https://github.com/clojure/spec.alpha/blob/master/src/main/clojure/clojure/spec/

1:34 gen/alpha.clj#L128

1:38 amalloy: huh. confirmed, that seems lame

1:53 dysfun: spec is a bit crack

1:54 TEttinger: a spec for crack though, now that woul be something

2:04 hm. thinking about https://github.com/rschmitt/dynamic-object and (de)serialization of hand-written values as opposed to machine-written ones

2:05 I love clojure's approach to writing data for prototyping, and I don't know if I have seen or used something better at that use

2:07 I don't know if there's any kind of way that homogeneous, no-types-declared collections will easily translate to Java, which is of course pretty strict on types if you want to get your IDE to do any work

2:22 dysfun: TEttinger: sure, List<String> is just List<Object> at runtime

2:23 well, it's more like List at runtime, really, but you get my point

2:24 TEttinger: yes, but the IDE won't be too helpful if you constantly cast each Object you get from a List to String in Java code

2:24 dysfun: oh well

2:24 shouldn't rely on an IDE then

2:25 TEttinger: you shouldn't rely on coffee then

2:25 dysfun: i shouldn't, you're right.

2:25 TEttinger: heh

2:25 unneeded performance boost!

2:25 * dysfun sips his coffee

2:26 dysfun: meanwhile, i've given up trying to be polite in an email and left it at "call me"

2:26 TEttinger: , maybe

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

2:26 TEttinger: ,:maybe

2:26 clojurebot: :maybe

2:26 TEttinger: there.

2:27 dysfun: hello, maybe

2:27 TEttinger: this is your cousin, maybee

3:35 Wxckol: Hey

3:36 TEttinger: hello

3:36 dysfun: wotcha

3:39 Wxckol: What does Clojure is for?

3:39 dysfun: it's a general purpose programming language

3:39 Wxckol: general purpose like what?

3:39 im a general ignorant :D

3:39 dysfun: well, in short, you can do most things with it

3:40 Wxckol: What do you do with it?

3:40 dysfun: build websites mostly

3:40 Wxckol: Can you show me something you built with it?

3:41 dysfun: https://github.com/irresponsible/anarchy is a simple business logic engine i built in clojure

3:42 Para_: "business logic engine" sounds horribly engineered solution looking for a problem

3:42 Wxckol: Mh, ok (thank you), but it's beyond my knowledge for now. What about a website, can you show me a website?

3:42 Para_: YMMV of course, rule engines have never appealed to me

3:42 dysfun: it's not a traditional rule engine

3:43 i can show you a website, but that it's written in clojure will make no difference to your experience of it

3:43 Wxckol: Just wanted to take a look you know

3:43 dysfun: that's the thing about general purpose programming languages - they can all do much the same things, they just do them differently

3:43 well, https://bleeckerburger.co.uk/ is written in clojure, but what i said above

3:44 Wxckol: So you write all this with code? No gui at all

3:44 ?

3:47 dysfun: yup

3:47 i mean the html can be trivially edited in a gui if you want, but i choose not to

3:48 well, actually the template engine probably knackers gui editability

3:48 but it started as html and then i just edited the template in

3:49 https://github.com/tonsky/datascript-chat # here is an example of a more dynamic app written in clojurescript

3:49 the burger site actually has a very shiny admin panel written in clojurescript too, but i can't show you that

4:25 Hanonim: Yop

4:25 dysfun: hiya

4:25 Hanonim: good ?

4:26 dysfun: okay i guess, tired

4:29 osfabibisi: apparently Kafka think they have solved Exactly Once

4:30 dysfun: well, they're presumably trying to compete with flink

4:30 (flink claims exactly-once, so it's nice to know we've made such progress with the provably hard german tank commander problem

4:35 Hanonim: osfabibisi: only in special occasions

4:35 osfabibisi: so what's the flink-definition-of-exactly-once?

4:36 dysfun: i suspect "exactly once except when something goes wrong"

4:36 osfabibisi: ah

4:36 so "not exactly once"

4:37 dysfun: well, we have a mathematical proof of the hardness of this problem, so...

4:38 anyway, exactly once except in case of error is basically as good as you can get, it's what you do in the case of error that matters

4:39 osfabibisi: ah ok

4:39 and does that work out being better than at-least-once in practice?

4:39 dysfun: it depends what you're doing

4:40 there is also the other category - at most once

4:41 at most once is what linkedin use for emails, because noone complains if they don't receive yet another fucking email

4:44 TEttinger: linkedin can show restraint on emails???

4:44 how surprising

4:44 I think they're just a spam council

4:45 dysfun: no, the outage of linkedin services can show restraint on emails

4:46 Carr0t: I wonder if they've done it by decoupling message sending from message sent checking. e.g. message is sent with UUID. Instead of resending on no ack you just keep asking "Have you got the message with UUID X" until you get either a yes or no. ON yes, mark as sent. On no, resend message with new UUID and start asking about *that* one

4:47 dysfun: ah, but what happens if the machine receives it but then goes offline before it's done processing?

4:47 osfabibisi: ah yes, I understood that better written down ;-)

4:49 ah yes, this is the thing that Paxos is meant to solve? (still not entirely sure what that is, I keep confusing it with the stock cube)

4:51 dysfun: paxos and raft attempt to solve this problem, yes

4:52 TEttinger: they just need to verify that they have received the message before the message was sent. a clear violation of causality, just like uber is a clear violation of taxi regulations

4:53 torrent-of-ions: Is "Joy of Clojure" worth buying considering a) I'm a Common Lisper, and b) it's only v1.4 of Clojure?

4:53 osfabibisi: I liked JoC

4:54 dysfun: it depends on whether it's the sort of book you like to read

4:54 TEttinger: clojure's different enough from CL, so having a good book helps

4:54 torrent-of-ions: Oh, it's 1.6 actually

4:54 TEttinger: not very old huh

4:54 1.7 was transducers? or was that 1.6?

4:54 torrent-of-ions: 1.7

4:54 dysfun: 1.7

4:55 TEttinger: I still haven't used a transducer knowingly

4:55 torrent-of-ions: I suppose those additions don't change the fundamentals

4:56 I'm still a bit unclear about fundamentals like names and symbols

4:56 dysfun: no, not at all

4:57 i use transducers quite a lot, but i don't write new ones

4:58 torrent-of-ions: Also I hate buying technical books just before a new version comes out, but I can't find any news about a 3rd edition

4:58 I'll order it then

4:58 dysfun: i can't see a new edition this year

4:58 or in the near future, generally

4:59 not with significant changes anyway, maybe a reprint

5:20 osfabibisi: dysfun: are you back on Clojure, or just visiting? ;-)

5:21 Hanonim: it's weird, after quite a while with clojure, i start missing imperative langs

5:21 dysfun: i am writing clojure, but not contributing to it

5:21 osfabibisi: aha

5:22 contributing to core? or to your irresponsible modules?

5:22 dysfun: core. i am still doing irresponsible because i use them too

5:22 osfabibisi: good good

5:25 dysfun: i've stopped bothering with the site though

5:25 deadghost: hmm did dysfun jump langs?

5:25 dysfun: it will eventually turn into the irresponsible software guild and include stuff written in kotlin, or if i ever build the damn thing, kotlisp

5:26 Hanonim: so you've chosen kotlin for your lisp ?

5:26 dysfun: it's seeming likely, but it's not definite

5:27 Hanonim: because of the type system ?

5:28 dysfun: i use a lot of java libraries. using them is often a pain in clojure because it tries to have its two worlds thing, whereas kotlin just does java++

5:28 osfabibisi: oh? we've found Java interop in clojure quite painless

5:28 dysfun: kotlin is not going to win any awards for outstanding revolutionary design, it's just java++, done quite wel

5:28 well*

5:29 it is often painless, but equally often painful

5:50 osfabibisi: ah, hehe

5:51 dysfun: :D i just talked a potential client into making an improved offer

5:51 osfabibisi: woohoo

5:55 audriusm: how will you improve the offer? :)

5:55 dysfun: well i improved it by asking them to improve it

5:55 and mentioned what their competition were offering

6:00 osfabibisi: is it a fun gig?

6:01 dysfun: no, but it's less un-fun that commuting 2 hours a day

6:01 than*

6:10 osfabibisi: this is true

6:13 dysfun: gosh, there are engineers up the pylon i see out of my window. it's the most interesting thing i've seen this week

8:05 Makis: Is there a trick to using Himera and tryclj because I keep getting errors even when I use some existing examples?

8:28 osfabibisi: so the Clojure example in http://www.bradcypert.com/5-programming-languages-you-could-learn-from/

8:28 why doesn't that blow it's stack? does lazy-cat do some magic there, even though it's not tail recursive?

8:43 raek: osfabibisi: yes. lazy-cat is a macro. the body of the lazy-cat form is wrapped up in a thunk and that thunk is returned immediately.

8:43 dysfun: i just looked at the source, it uses concat

8:43 so if it's a very big list, and you realise it all at once, it likely *will* blow its stack

8:45 raek: oh, you're right. it calls concat immediately. but the arguments to concat are wrapped in lazy-seq which is the thing that delays the computation

8:46 dysfun: also that quicksort assumes uniquity in the source collection

8:46 raek: so (lazy-cat e1 e2 ... e1000) becomes (concat (lazy-seq e1) (lazy-seq e2) ... (lazy-seq e1000))

8:46 dysfun: it will actually malfunction if an item goes twice by the looks of it

8:46 raek: dysfun: why would a big list blow the stack?

8:47 dysfun: raek: because each call to realise a new element adds a stack frame

8:48 haskell only gets away with pervasive laziness because the VM is built around it

8:48 raek: hmm right.

8:49 if the partition is perfectly balanced the lazy sequences becomes nested at a depth of log2 n

8:49 dysfun: yes. in general we assume the stack size is log(heapsize)

8:50 much garbage collection theory is based on that

8:51 raek: but I suppose you could design a pathological input that makes all the partitions maximally unbalanced, so that the stack depth needed would indeed be proportional to n!

8:51 dysfun: even with a perfect balance, it's vulnerable to large inputs

8:52 periodically someone turns up asking about a very strange stack overflow bug that appeared in production and it usually turns out it's concat's fault

9:33 osfabibisi: raek, dysfun: sorry, got called away after asking that question

9:33 so essentially that function *will* blow its stack on large inputs?

9:34 dysfun: pretty much

9:34 osfabibisi: cool. that was my guess, but I thought I'd ask in case I'd misunderstood ;-)

10:31 dysfun: so i spent an hour today tracking down a bug that would have been pointed out by even a half-arsed type system

10:31 TMA: would it help if (lazy-cat e1 e2 ... e1000) were (concat (lazy-seq e1) (lazy-cat e2 ... e1000))?

10:32 dysfun: it might be less awful than the original in a large collection, but it still suffers the same basic flaw

10:32 but making it lazy seems rather pointless

10:36 osfabibisi: is there an existing function for (defn check [message predicate] (when (predicate message) message)) ?

10:36 e.g. you can (some-> thing (check some-predicate?) (...))

10:36 * osfabibisi misses hoogle...

10:38 dysfun: er, isn't that... some-> ?

10:40 osfabibisi: hmm, not exactly, some-> would just path the truthy value of the predicate

10:40 it's a converter from truthy predicate into threading macro guard

10:40 dysfun: cond-> ?

10:41 but i think from your description not quite

10:43 osfabibisi: I can't figure out cond-> at all tbh ;-)

10:44 I think the `check` definition should do for now, ta for suggestions

10:44 dysfun: ,(for [i (range 10)] (cond-> i odd? #(* 2 %)))

10:45 clojurebot: (#object[sandbox$eval40$iter__36__41$fn__42$fn__43$G__44__45 0x23881a68 "sandbox$eval40$iter__36__41$fn__42$fn__43$G__44__45@23881a68"] #object[sandbox$eval40$iter__36__41$fn__42$fn__43$G__44__45 0x3c7db411 "sandbox$eval40$iter__36__41$fn__42$fn__43$G__44__45@3c7db411"] #object[sandbox$eval40$iter__36__41$fn__42$fn__43$G__44__45 0x60b8e71d "sandbox$eval40$iter__36__41$fn__42$fn__43$G__44__45@60b8e...

10:45 dysfun: ,(for [i (range 10)] (cond-> i odd? (#(* 2 %))))

10:45 clojurebot: (0 2 4 6 8 ...)

10:46 osfabibisi: ,(map #(* 2 %) (range 10))

10:46 clojurebot: (0 2 4 6 8 ...)

10:46 osfabibisi: I still don't understand your example

10:46 if it's odd, it multiplies by 2? wouldn't that be (2, 6, 10, ...) ?

10:46 dysfun: well, it's like -> except i inserted the predicate odd? in the middle

10:48 to be fair, *i* was expecting to see something different as well

10:48 osfabibisi: yeah, I have no idea what it's doing though

10:48 ah, heh

13:05 TimMc: Thing I'm really tired of in Clojure: Not being certain I can find all the places my code looks at a really generically named key in a datastructure.

13:05 Like if I have something under :data in a map, there's no good way to grep for all references to that.

13:07 osfameron: hmm. that's a weakly typed issue in general isn't it?

13:07 or possibly a hint that you should rename your map keys to something less generic

13:07 dysfun: namespaced keywords (which rich has been banging on about a lot recently) *almost* solve that one

13:08 (as in you need to substitute something that reads namespaces for grep in order to solve the typical case)

13:09 osfameron: it's interesting that Haskell just avoids having arbitrary maps of data and makes you model your structures up front

13:09 I sometimes wonder if that trade-off would be worth it

13:09 dysfun: michael snoyman said he'd quite like to remove tuples

13:09 osfameron: I mean, on larger-scale projects than I've worked on

13:10 technomancy: osfameron: you don't need haskell for that; racket encourages that too

13:10 osfameron: at least tuples are typed-ish, but yeah

13:10 right, I should have said "e.g. Haskell" ;-)

13:10 the generic maps thing is Oh So Convenient for as long as you can actually remember and reason about what you're doing

13:10 (which for me isn't very long, as I am a simple squirrel)

13:10 dysfun: it's really good for prototyping

13:11 and it's very good for eliminating boilerplate

13:11 but as your code grows up, i don't think it scales

13:11 osfameron: right, I've not done sufficiently complex things in Haskell to worry about boilerplate tbh

13:11 I should fix that...

13:11 dysfun: i got lost down the GHC.Generics hole a couple of months back

13:12 the other thing maps are good for is interop with json

13:12 justin_smith: the compromise that works best for me is arbitrary hash-maps locally (eg. within one set of tightly coupled namespaces in one project) and schemas / defrecords between subsystems, enforcing specific keys or even using types instead of mappy things

13:13 kind of like how shorter names are OK in small scopes but as scope gets larger you want more and more description in a name

13:13 TimMc: osfameron: Yeah, weakly typed and some related stuff. If I had schemas on all this code, I could find references to the schemas...

13:13 justin_smith: plain-old-arbitrary-data is great in small scopes, more reification and validation of structures is good for things that crosses boundaries

13:14 * TimMc brushes off old IRC discussions of using UUIDs for all names

13:14 justin_smith: haha

13:14 osfameron: justin_smith: interesthing - though again, at odds with dysfun's comment that it's the *weakly* typed stuff that is trivial to serialize and pass as JSON ;-)

13:14 technomancy: also we need letrec

13:14 osfameron: the French painter? ;-P

13:15 dysfun: no, we don't need letrec, we need letnonrec

13:15 justin_smith: osfameron: right, I think more structure at boundaries and less in the implementation is the path to sanity, not the opposite

13:15 TimMc: so we should use SOAP is what I'm hearing

13:15 technomancy: dysfun: reference to https://news.ycombinator.com/item?id=8226934

13:15 justin_smith: oh man...

13:16 osfameron: TimMc: eeeeek!

13:16 * osfameron hides behind the sofa from SOAP, and to catch up on Doctor Who... &

13:18 dysfun: shouldn't you sit *on* the sofa to watch doctor who?

13:18 justin_smith: TimMc: SOAP is terrible, but I'd still want the type checking at the edges to be strictest - because that's where you get the real cascading problems, is stuff that comes from furthest away, because you need to read unrelated code to understand it, and the odds that no one dev read both parts of the codebase increase...

13:18 technomancy: dysfun: you start out on the sofa and you end up behind the sofa once the daleks show up

13:18 it's traditional

13:18 justin_smith: also it's attention span friendly / uses human working memory nicely

13:19 technomancy: justin_smith: starting to sound like grpc

13:19 TimMc: also aparently everyone watches movies on their smartwatches or whatever these days so it's not like you need to be in any one place

13:19 dysfun: yeah, there's no better experience than watching a movie on a tiny tiny screen

13:20 TimMc: I pipe all YouTube videos to my NumLock light.

13:20 justin_smith: dysfun: I assume you've seen the classic David Lynch rant https://www.youtube.com/watch?v=wKiIroiCvZ0

13:20 * dysfun has never even heard of david lynch

13:20 justin_smith: technomancy: I'm unfamiliar... is it any good?

13:20 technomancy: justin_smith: well... no? maybe? I don't know.

13:21 it has some neat features, but protobufs are annoying.

13:21 grpc alone is pretty nice; it gives you distributed tracing, cancellation of requests, automated backoff, etc

13:22 but it's usually paired with protobufs which are efficient but extremely awkward to use from clojure

13:22 I think grpc with edn or transit would be pretty nice

13:22 dysfun: s/to use from clojure// # FTFY

13:22 technomancy: with specs at the service boundaries, of course

13:22 justin_smith: of course

13:23 technomancy: the problem is if you use protobufs then people think that means you don't need spec, but protobufs are lame

13:23 dysfun: nah, you need to generate protocolbuffers from specs

13:23 technomancy: hm... now there's an idea

13:23 dysfun: because specs are better than types

13:24 justin_smith: the system I have in development now uses transit event sourcing on kafka topics to build a state deterministically from a log, and all the job logic is driven by the state in a model derived from petri nets (pool of available workers, pool of jobs, join the two to represent an "in progress" object, etc.)

13:24 technomancy: is it common to keep specs for a service in a separate dependency artifact from any implementation?

13:24 justin_smith: where the jobs and workers and in progress tasks are all reified in a hash map that is guaranteed identical in every process

13:25 dysfun: technomancy: i haven't seen anyone do that yet

13:25 justin_smith: technomancy: I do this for things that talk to two separate codebases, I have app a, app b, and then schemas c which is referenced by a and b

13:25 this was designed before spec though

13:26 * dysfun shares specs between clojure and cljs

13:26 justin_smith: that seems likea pretty natural choice

13:26 I think spec is a bit too new for there to be real systems with N>1 apps in communication and specs in between

13:27 hiredman: itym the tooling for protobufs is lame

13:27 technomancy: surely N=2 isn't that rare?

13:27 justin_smith: oh yeah, some people put their cljs in separate apps right

13:28 technomancy: hiredman: well sure, but what motivation to improve the tooling is there? even if it were decent it still isn't very compelling vs transit or msgpack

13:35 hiredman: yeah, I am not sure for message passing kind of things, I am thinking more about storing data, I've had bad experiences processing lots of edn

13:36 technomancy: interesting; yeah that's different

13:40 gpk: Is Clojure any good for small command line programs? I'm thinking that the jvm overhead would be too high

13:40 justin_smith: the jvm overhead is fine! it's the clojure compiler that's too heavy for that

13:41 though cljs + node for command line can work (see for example lumo which is a self hosting clojurescript you can install via npm)

13:41 technomancy: I would recommend racket or ocaml for small programs instead

13:41 justin_smith: yeah, ocaml is great for small things that have to start up quickly

13:41 gpk: I currently use python

13:41 hiredman: it depends on what you find acceptable

13:41 gpk: Or C

13:42 hiredman: I write a lot of command line stuff in clojure, but most of it is sort of fire in forget or it is a long running task anyway

13:44 gpk: justin_smith: can one not compile clojure ahead of time?

13:45 justin_smith: you can, but there's still a certain amount of bootstrapping of clojure itself

13:46 gpk: What's it like compared to SBCL binaries?

13:46 Those are actually fast enough even though they are huge

13:47 justin_smith: it's not the size, it's the amount of work done on startup, and there's nothing outside of experimental unofficial forks that eliminate that startup work

13:47 gpk: I'm wondering what project I'm going to rewrite to teach me clojure, by the way

13:50 technomancy: sbcl just dumps its whole memory image, right?

13:50 I don't think you can come close to that on the jvm

13:50 gpk: Yeah

13:50 As far as I understand

13:51 technomancy: gpk: do you have a use case in mind or is this more of just a general question?

13:53 gpk: Just a general question... It would be nice to use Lisp instead of Python

13:53 But I write a lot of tiny things

13:53 technomancy: IMO racket is a much better python replacement

13:54 or hylang of course

13:54 gpk: Unfortunately racket is not cool...

13:54 Sounds stupid, I know

13:55 technomancy: racket is h*ckin' cool; you take that back

13:55 gpk: *I* know it's cool

13:55 technomancy: but if it's not cool enough you could always try...

13:55 rackjure!

13:55 * justin_smith is through being cool.

13:55 gpk: Unfortunately nobody will pay me to write Racket

13:56 technomancy: http://docs.racket-lang.org/rackjure/index.html <- racket with sunglasses on

13:56 gpk: *won't

13:58 So I think Clojure sits more where CL is

13:59 Which is good because it does some things better than CL I think

13:59 I always thought it would be cool to get paid to write Lisp as well

14:05 osfameron: <dysfun> because specs are better than types <-- oh?

14:07 dysfun: osfameron: (not serious)

14:07 it's one of my current pet peeves that people keep saying this when it blatantly isn't true

14:08 osfameron: ah

14:09 technomancy: huh; refactor-nrepl claims to be able to do slamhound-type things

14:09 this looks pretty nice; does it work well?

14:11 apparently not?

14:11 dysfun: you may be overestimating how many people have tried it

14:12 technomancy: no, I mean I tried it and it doesn't work

14:12 dysfun: oh, heh

14:12 technomancy: why the heck would a query for find-usages require a namespace/name *and* a filename, line number, and column number?

14:13 Frozenlock: technomancy: slamhound?

14:13 oh https://github.com/technomancy/slamhound

14:14 osfameron: "Slamhound rips your ns form apart and reconstructs it. No Dutch surgeon required." (I have no idea what that means, which makes the description a little bit less useful than something, er, descriptive, but it sounds cool, I guess)

14:14 dysfun: osfameron: essentially it will rewrite your imports

14:15 technomancy: the "usage" section has a demo

14:17 osfameron: I think the first time I looked at the docs I gave up by then as I didn't know what problem it was trying to solve

14:23 ah I see, it's the "tidy up imports" function that some IDEs have

14:23 I've occasionally wanted that, will try vim-slamhound

14:24 (still don't think the project description sells it well though ;-)

14:26 technomancy: it's not quite like Java's "tidy up imports" because the implementation is a brute-force recompile-all-the-things, so I felt a metaphor of violence was appropriate

14:26 Frozenlock: technomancy: refactor-nrepl did pretty well when I left it 'guess' namespaces. Granted it was always with the canned solutions (str -> clojure.string) or with namespaces I was already using elsewhere in the project.

14:26 TEttinger: dysfun: depends on what types you mean. I'm sure specs are better than some type systems. JS' for instance...

14:27 technomancy: Frozenlock: I'm more interested in the find-usages

14:29 so yeah... this just doesn't work as documented

14:29 too bad

14:42 lxsameer: which protocol is related to a derefable value ?

14:50 justin_smith: lxsameer: the easiest way to check is with supers

14:51 eg. (supers (class (future))) and (supers (class (atom nil)))

14:51 technomancy: boom; had lein refuse to download a transitive dependency that used a non-TLS repo which wasn't directly visible in project.clj

14:51 woot

14:51 justin_smith: nice

14:52 technomancy: coincidentally nice that the first time this occurred I happened to be on coffee shop wifi

14:52 lxsameer: justin_smith: thanks a lot man

14:54 Frozenlock: technomancy: living dangerously

14:55 technomancy: Frozenlock: it would be dangerous, if I weren't using this new version of lein that refuses to do idiotic things for me =)

14:55 idiotic things which every actually-released version of lein will happily go ahead and do =(

14:58 lxsameer: is a custom type which defined with deftype

14:58 mutable ?

14:58 justin_smith: types aren't mutable, but deftype fields can be

14:59 optionally

14:59 lxsameer: justin_smith: ow, thanks

15:39 ridcully_: osfameron: it also tries to do :refer etc. e.g. write >! somewhere, slamhound adds async with a refer. or use str/join and it will require clojure.string as str etc

15:49 osfameron: ah, it has a catalogue of common functions?

15:49 ridcully_: dunno. i'd guess it just looks around

15:50 not sure, if it does the same thing for imports too

16:10 octarinemole: hello everyone! i have this strange question: why is (<= 0.1 1/10) true but all of (< 0.1 1/10), (= 0.1 1/10) and (> 0.1 1/10) are false?

16:11 Para_: Clojure has fractional type support.

16:11 Or rather, rational.

16:11 ,(type (/ 1 3))

16:11 clojurebot: clojure.lang.Ratio

16:12 octarinemole: ,(<= 0.1 1/10)

16:12 clojurebot: true

16:12 octarinemole: if that's true, shouldn't also one of the following be true?

16:12 Para_: "is equal" of that part matches

16:12 octarinemole: ,(< 0.1 1/10)

16:12 clojurebot: false

16:12 octarinemole: ,(= 0.1 1/10)

16:12 clojurebot: false

16:12 Para_: No.

16:12 That's not how that works in any language :)

16:13 octarinemole: why is that? (sorry, it just looks mathematically pleasing...)

16:13 Para_: It reads out loud "is equal OR smaller than"

16:13 so it's (or (< 0.1 1/10) (= 0.1 1/10))

16:13 ,(or (< 0.1 1/10) (= 0.1 1/10))

16:13 clojurebot: false

16:13 octarinemole: yes, so either (= 0.1 1/10) or (< 0.1 1/10) should be true as well, shouldn't it?

16:14 Para_: ...well probably the other way around but anyhow

16:14 octarinemole: there you go, you get

16:14 ridcully_: ,(== 0.1 1/10)

16:14 clojurebot: true

16:14 octarinemole: ,(= (<= 0.1 1/10) (or (< 0.1 1/10) (= 0.1 1/10)))

16:14 clojurebot: false

16:14 Para_: ,(or (= 0.1 1/10) (< 0.1 1/10))

16:14 clojurebot: false

16:14 Para_: Hum.

16:14 Well anyway. The <= is not decomposable.

16:15 < and = are not the same as <= in a sense; it goes into land of type coersions

16:15 octarinemole: i see...

16:15 Para_: Just read it out loud and don't think everything can be split into parts.

16:15 You're not Aristotle, atoms have already been discovered :)

16:15 octarinemole: ok, well, thanks

16:16 TEttinger: ridcully_ had it

16:16 ridcully_: ,(BigDecimal. 0.1)

16:16 clojurebot: 0.1000000000000000055511151231257827021181583404541015625M

16:16 Para_: Yeah there's that.

16:16 octarinemole: that is why i chose 0.1 in the first place...

16:16 TEttinger: octarinemole: there's 0.1M for higher precision easily

16:16 octarinemole: i just expected some properties of the comparison operators which are apparently not there

16:16 TEttinger: but yeah == is mathematical equality

16:17 Para_: Well it applies to all languages as well, if you care about fractions/ratios, make sure you work with compatible types at all points.

16:17 TEttinger: I believe <= is the or of < and ==

16:17 technomancy: Para_: most languages don't have ratios

16:17 Para_: ,(or (== 0.1 1/10) (< 0.1 1/10))

16:17 clojurebot: true

16:17 Para_: technomancy: That's their downfall :)

16:17 octarinemole: @TEttinger ok, thanks, i think that helps me a lot!

16:17 TEttinger: since <= is mathematical, not as general as =

16:17 technomancy: Para_: I would say that having decimal literals default to floats is the downfall

16:18 it's much better to default to accuracy and opt-in to speed

16:18 Frozenlock: indeed

16:19 Most people that first come to a computer won't have the reflex of saying "hmm, I wonder if the computer will lie to me and NOT register the number as I entered it."

16:19 octarinemole: :)

16:19 Para_: technomancy: That's why Groovy defaults to BigDecimals with actual accurate precision, as well.

16:19 technomancy: Para_: huh; that's the first sensible thing I've heard about it =)

16:19 Para_: Frozenlock: Well most people are really technically inept as well.


16:20 Frozenlock: Para_: right, so we shouldn't make it harder.

16:20 Para_: They won't understand the difference or what it entails.

16:20 So don't waste your tiime.

16:34 IamDrowsy: I just had a look at the Clojure source and actually (= 0.1 1/10) resulting to false has nothing todo with 0.1 not being exact

16:34 ,(= 1/2 0.5)

16:34 clojurebot: false

16:35 IamDrowsy: equal (=) check for the category of a number (Integer, Floating, Ratio, Decimal) and will always give false when it doesn't match

16:36 technomancy: IamDrowsy: depends how you define your terms; "inexact" is commonly used to describe types rather than values

16:36 ridcully_: ,(= 1M 1)

16:36 clojurebot: false

16:37 justin_smith: (= 1N 1)

16:37 ,(= 1N 1)

16:37 clojurebot: true

16:39 octarinemole: ,(== 0 (- 0.1 1/10))

16:39 clojurebot: true

16:39 octarinemole: ,(== 0 (- 0.1 (BigDecimal. 0.1)))

16:39 clojurebot: true

16:39 justin_smith: there's also zero?

16:39 ridcully_: ,(= (BigInteger. "1") 1N)

16:39 clojurebot: true

16:39 octarinemole: these look a bit funny to me... it is like 0.1 can act as exactly one tenth, but also as "roughly" one tenth

16:40 justin_smith: ,(zero? (- 0.1 1/10))

16:40 clojurebot: true

16:40 justin_smith: octarinemole: before you use a double in a calculation it's other because it's less precise, after you use it it is contagious, you get a double back

16:41 technomancy: justin_smith: oh man that last one

16:41 justin_smith: yup

16:42 octarinemole: so... in (- 0.1 1/10) I should get a non-zero double, shouldn't I?

16:43 ridcully_: ,(+ 0.1 2/10)

16:43 clojurebot: 0.30000000000000004

16:44 octarinemole: it casts the fraction to a double and then does the operation?

16:46 funny that

16:46 ,(class (- 0.1 (BigDecimal. 0.1))

16:46 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

16:47 octarinemole: (class (- 0.1 (BigDecimal. 0.1)))

16:47 ,(class (- 0.1 (BigDecimal. 0.1)))

16:47 clojurebot: java.lang.Double

16:47 octarinemole: so it also downgrades the bigdecimal to a double when possible

16:47 dysfun: when it doesn't make sense to keep it as a rational, it will convert it to a double

16:47 octarinemole: ,(class (- 0.1M (BigDecimal. 0.1)))

16:47 clojurebot: java.math.BigDecimal

16:48 dysfun: and in this case, you gave it a double first

16:48 octarinemole: ok, i think i'm starting to understand it enough

16:48 ,(class (- (BigDecimal. 0.1) 0.1))

16:48 clojurebot: java.lang.Double

16:48 ridcully_: i think order has nothing to do?

16:48 dysfun: ah so it is

16:49 octarinemole: thanks everyone!

16:49 ridcully_: it will use double once one of those is there, since it gives the most wrong result

16:49 octarinemole: :-D

16:49 dysfun: "most wrong" really depends on how much of it's being used

16:49 i would have said the logical approach would be to do the opposite

16:50 technomancy: using a not-double would give the mistaken appearance of precision

16:50 ridcully_: is there even a way to get a Ratio from a double?

16:51 dysfun: i think "mistaken" depends heavily on what you're doing

16:52 i can envision several useful scenarious for the behaviour i descirbe

16:52 technomancy: without knowing about the context, using the less-exact representation is the only safe choice

16:56 dysfun: i don't know, it kind of offends me slightly because i've used so many languages that auto-upgrade to bignums

17:00 octarinemole: ridcully_: you can write a function that extracts the nominator and denominator from BigDecimal, then pass that to the Ratio constructor... maybe this should be built in?

17:01 dysfun: that doesn't do a rario from a double

17:01 technomancy: (->> (for [...] (future ...)) (map deref) doall) ; <- is that even ... I mean

17:01 you're derefing every single future as it's constructed

17:02 so... you're completely defeating the purpose of futures?

17:02 justin_smith: yeah, the doall should come first

17:02 dysfun: there are infinite solutions for fractions, so the best you can do is multiply it until you've eliminated the point to get the numerator and denominator

17:02 justin_smith: unless you only want to work with (chunk size) futures at a time?

17:02 technomancy: I always try to come up with an explanation that isn't "whoever wrote this was very confused" but ...

17:02 hiredman: it would make sense if the doall was before the map

17:03 justin_smith: technomancy: "I want either 1 or 32 futures to run at a time"

17:03 hiredman: lazy creating futures -> forcing the lazily created futures -> waiting for them all to compute

17:04 that is almost certainly what they meant to do

17:04 technomancy: yeah... and chunking accidentally makes it work sorta the way they meant?

17:04 octarinemole: dysfun: well, the double has finite precision, so you can definitely represent it as a fraction that way, and the methods on BigDecimal can help a lot

17:04 * osfameron giggles at https://twitter.com/WeRateTypes/status/880165429263556609

17:06 justin_smith: oh man, that's their only tweet

17:06 and they just made another one...

17:07 technomancy: it's like being around for a birth. such a magical moment.

17:07 Frozenlock: with blood and shit everywhere

17:07 magical

17:09 osfameron: what's the big hex string on their first tweet?

17:20 octarinemole: ridcully_: found it:

17:20 justin_smith: they're well typed Bröwer.

17:20 octarinemole: ,(clojure.lang.Numbers/toRatio (BigDecimal. 0.1))

17:21 clojurebot: 1000000000000000055511151231257827021181583404541015625/10000000000000000000000000000000000000000000000000000000

17:21 justin_smith: lol

17:22 octarinemole: and somewhat embarassingly...

17:22 ,(clojure.lang.Numbers/toRatio 0.1)

17:22 clojurebot: 0/1

17:22 justin_smith: well, it's a ratio

17:23 octarinemole: true :)

17:28 justin_smith: ,(clojure.lang.Ratio. (biginteger 666) (biginteger 420))

17:28 clojurebot: 666/420

17:29 postpunkjustin: sick ratio

17:30 octarinemole: yeah, and then the equals method is a bit odd...

17:32 i don't think the constructor is meant to be invoked directly as it doesn't normalize the fraction...

17:32 justin_smith: yeah, I inferred the constructor wouldn't normalize when I saw the output for 0.1

17:33 octarinemole: and then the equals method assumes they're normalized

17:33 ,(== 12/14 (clojure.lang.Ratio. (biginteger 6) (biginteger 7)))

17:33 clojurebot: true

17:33 octarinemole: ,(== 12/14 (clojure.lang.Ratio. (biginteger 12) (biginteger 14)))

17:33 clojurebot: false

17:33 octarinemole: so it's a no-no :)

17:35 lxsameer: how can I get a function by name with out requiring the namespace ? in runtime

17:35 justin_smith: resolve finds it, if any other code caused the code to be loaded at least

17:36 ,(resolve 'clojure.java.io/file)

17:36 clojurebot: #'clojure.java.io/file

17:36 justin_smith: that finds the var

17:36 you can call a var, or deref to get the actual thing out of it

17:39 lxsameer: justin_smith: but what if there were no file requiring that ns ?

17:39 technomancy: lxsameer: leiningen has a resolve-require function

17:40 (defn resolve-require [x] (require (symbol (namespace x))) (resolve x))

17:40 amalloy: lxsameer: why are you trying to do this? this is a weird thing to do

17:40 lxsameer: technomancy: hmmm is that going to work on production ? i mean in a jar

17:40 technomancy: lxsameer: yes, but it's better to have the call path known at compile-time if possible

17:40 lxsameer: amalloy: indeed it is.

17:42 amalloy: i'm trying to point to a function from an edn data

17:42 Frozenlock: lxsameer: is this to make plugins?

17:42 amalloy: how much do you trust the source of this edn data? if you let them call arbitrary functions, they can do pretty much anything

17:43 lxsameer: Frozenlock: not a plugin but maybe concepts would be the same

17:43 amalloy: it's a trusted source

17:44 justin_smith: so this is effectively DI via edn?

17:45 what if a consumer passed you a function instead?

17:45 lxsameer: justin_smith: some how yes

17:45 justin_smith: over wire ?

17:45 justin_smith: basically this happens on wire

17:46 justin_smith: OK - so they ask for some namespace, you might not have loaded it yet for whatever reason, but they trust you can find it if they ask for it?

17:46 lxsameer: justin_smith: both side has several functions but i want to conditionally specify the callback

17:46 justin_smith: yeah exactly

17:47 justin_smith: so it's a weird ad-hoc RPC thing

17:47 lxsameer: justin_smith: yes

18:08 technomancy: ad-hoc rpc isn't that weird

19:12 assoc-in: Has anyone called a jar from clojure? I have a jar for an external resource and it looks like I could clojure.java.shell to call it, but I am not sure how I would close it.

19:24 justin_smith: assoc-in: you could either invoke the jar's main from within your own vm, allowing you to access its api that hopefully has some way to shut it down or cancel it, or launch a shell script via shell/sh that runs it async and returns the pid (that you can later reference to kil it via shell )

19:24 or, you can also use ProcessBuilder to create a Process, which has a method to shut it down (and has a lot of useful options that shell/sh doesn't)

19:25 there's a library called conch that wraps ProcessBuilder but I think using the real API is much less error prone

19:54 assoc-in: Okay I was able to get it to work with this. It looks like you need to call sh again. (shell/sh "sh" "-c" "java -jar ......")

19:54 justin_smith: shell/sh doesn't us sh (despite the name)

21:08 llsouder: https://pastebin.com/M8CAHhEG

21:08 what is this argument? https://pastebin.com/M8CAHhEG

21:08 doh!

21:08 [{{username "username" password "password" next "next"} :params

21:08 session :session :as req}]

21:08 this is a vector with a map

21:09 and the first key of the map is a map????

21:09 why cant my evil brain parse this?!?!?

21:10 (defn do-login

21:30 so while I was waiting I found the :as which told me it is destructuring

21:31 so not the session :session makes sense to me. the name session is bound to the value of the :session key

21:32 so now*

21:32 that username stuff is still hurting my brains

21:38 ok, that took a while but I got it. "username" is a key and binds to username etc

21:39 yeah, thanks for letting me work that out LOL! Clojure documentation test.... passed!

22:04 assoc-in: justin_smith:Yes quite odd behavior. I think the documentation could be more clear about that

Logging service provided by n01se.net