#clojure log - Feb 21 2016

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

9:59 justin_smith: python476: you can use jstack to get the stack traces of all the running threads while its in that state (if you can find the pid that's using 100% pid, then 'jstack <PID>'), if you share that in a paste we can probably figure out what's going on

10:06 python476: hi justi

10:06 n_smith

10:06 thanks (as usual), didn't know about jstack, gonna test

10:11 here it is http://lpaste.net/152994

10:12 justin_smith: python476: I wonder what rewrite-clj is doing...

10:13 python476: as far as I can see from that stack trace, rewrite-clj is in the process of parsing / analyzing your code

10:13 python476: lots of 'waiting' threads

10:14 justin_smith: and I guess maybe it's stuck in a loop, or doing some kind of intense calculation?

10:14 python476: right, you can pretty much disregard the ones that say "parking"

10:14 but notice the one starting at line 159

10:14 python476: note that I launched the lein repl and didn't do anything

10:14 justin_smith: I bet that is the one consuming your CPU

10:15 python476: yeah, cider invokes a bunch of stuff, including apperently the rewrite-clj process

10:15 python476: yes that's the only busy stack

10:15 justin_smith: well you can be busy without being deep, but the two often go together :)

10:16 python476: indeed, I expected the thin stacks beind idle-busy

10:16 not stacking-mad-busy

10:16 justin_smith: for example there's another runnable at refactornrepl220SNAPSHOT.org.httpkit.client.HttpClient.run(HttpClient.java:365)

10:16 (like 122)

10:17 short stack trace but could be consuming CPU

10:17 python476: I thought FUTEX_WAIT indicated a socket issue for some reason

10:18 justin_smith: whre do you see futex? (other than the title of the paste)

10:19 python476: htop / strace

10:19 the only 100% cpu java thread strace shows one line with FUTEX_WAIT

10:22 justin_smith: ahh OK it's an OS thing not a JVM thing http://man7.org/linux/man-pages/man2/futex.2.html

10:23 python476: oh you thought it was a pure code + infinite loop ?

10:23 justin_smith: python476: is this in a vm?

10:23 python476: yes

10:23 justin_smith: python476: https://nofluffjuststuff.com/blog/pratik_patel/2010/01/solution_futex_wait_hangs_java_on_linux__ubuntu_in_vmware_or_virtual_box

10:24 python476: ah no, not VM, I meant JVM

10:24 justin_smith: known futex issue in vms?

10:24 oh, OK

10:24 python476: unfortunate abbreviation

10:24 justin_smith: so yeah this probably has nothing to do with the futex thing, that's just a jvm implementation detail and the bug is not likely there

10:25 python476: standalone `lein repl` doesn't exhibit the problem

10:25 so it's between emacs cider nrepl lein

10:25 and PEBCAK

10:25 probably PEBCAK

10:25 justin_smith: there's likely something pathological about refactor-nrepl with your specific project / codebase

10:26 refactor-nrepl is likely where the issue is, based on those stacks

10:26 python476: ah, refactor is just above rewrite-clj

10:26 justin_smith: python476: this is a total shot in the dark but you could try running lein eastwood and changing things it warns about

10:27 - things that eastwood warns about are likely to be things that would trip up a project that auto-parses code like that

10:27 or maybe more like things that would trip up refactor nrepl are also things eastwood would warn about

10:29 python476: but there's no trace of refactor-nrepl in that project

10:30 justin_smith: python476: cider pulls in refactor-nrepl

10:31 python476: oh ok

10:31 cider is drunk

10:32 justin_smith: python476: cider is something people like because the devs prioritize features. It's also something people dislike because the devs prioritize features.

10:33 python476: by using cider you are (by default at least) pulling in all the features unless you opt out, and you're using a tool with a less than stellar stability history

10:33 python476: you don't use it ?

10:33 justin_smith: python476: I got tired of all the things breaking, stopped using it.

10:33 python476: I tried using inf-clojure-mode to avoid big dependencies

10:34 but I have to admit cider makes the UX very nice

10:34 justin_smith: python476: I think I have an unusual philosophy of UX, in that I prefer "things not breaking" as a higher priority than "having nifty features"

10:34 python476: that was my goal too

10:34 justin_smith: but that's OK, we can each make those decisions for ourselves as users

10:34 python476: but so far I need a middle ground

10:35 let's see what eastwood say

10:35 justin_smith: python476: as an interim there's also disabling the refactor-nrepl plugin, I bet there's a way to do that either globally or just for that project

10:36 python476: surely, it seems cider often leaves control to the user

10:38 TimMc: justin_smith: That's why I'm on Debian stable. :-P

10:38 actually, oldstable at the moment, need to do the upgrade

10:38 justin_smith: TimMc: kudos, that's a typical choice of mine as well, but my current box came with ubuntu pre-installed, so I am on an ubuntu LTS

10:53 python476: btw, what's the meaning of WARNING!!! version ranges found for: [tikkba "0.5.0"] -> [org.clojure/clojure "[1.2.0,]"]

10:54 TimMc: python476: tikkba of that version declares a dependency on any version of clojure from 1.2.0 on up.

10:54 That's a version range, and they're generally terrible.

10:54 python476: oh so the warning is on the lib, not project.clj

10:54 TimMc: yeah

10:55 If you depend on a version range, or against something else that does, it means your build can break randomly at some future point. THey're very annoying to debug, as well. That's why lein recommends excluding the transitive dependency and putting in your own explicit dependency if necessary, to pin it down.

10:57 python476: aight

10:57 I'm trying cider-jack-in with an empty src folder..

10:58 it does burn cpu but for one minute only

11:18 justin_smith: python476: if it does that even for an empty directory, that might be worth a bug report

11:19 python476: maybe that's just ... slow machine leading to long init times

11:19 also maybe I didn't realize it was burning cpu for a minute because one minute doesnt make a laptop hot

11:20 but before coming here today it was running for 10+ minutes

11:20 I'll keep bisecting my project to avoid disturbing others more

11:20 where do you drop a bug report ? github issues ? a ML?

11:21 justin_smith: for most clojure projects a github issue would probably be best, I'd imagine refactor-nrepl would be one of those

11:24 python476: aight, thanks

11:39 it's getting weirder and weirder. made a new lein project, copying just the deps, local repo and a fake main, now no more repl

11:39 unless ran twice

11:40 enough bug hunt, time to read some fogus book

11:52 * TimMc shrugs, mutters "cider..."

11:53 python476: cider, cider, cider

11:53 * python476 vanishes, abducted by an unbalanced alien sexp

12:30 TimMc: Oh no, they said "cider" three times in a mirro!

12:30 *mirror

12:52 justin_smith: one of the unknown hazards of using the codemirror editor

13:33 CStorm: what is the best way/lib to use when i want to fire a function every, say, hour?

13:34 luma: there's Quartzite http://clojurequartz.info/

13:35 justin_smith: CStorm: it's not super hard to just use a java.util.concurrent.ScheduledThreadPoolExecutor directly, but there's also at-at as a nice wrapper

13:36 https://github.com/overtone/at-at

13:37 if you don't need a huge thing like quartzite that is

13:46 banana`: Hey guys, I have a quick question. I am trying to do an element wise or between two list. So if I have a L1 : '(false true) and L2 : '(true false) I want to do L1 or L2 and get '(true true) back since that would be element one from both L1 and L2 ored together and then element two from both ored together. Any ideas?

13:46 justin_smith: banana`: bitwise-or?

13:46 oh no, boolean or

13:47 banana`: Yes a boolean or

13:47 justin_smith: ,(map #(or % %2) [false true false] [true false false]) ; banana`

13:47 clojurebot: (true true false)

13:47 justin_smith: sadly you can't just map or, since it's a macro

13:47 banana`: Ya I tried that

13:48 I think mine didn't work since I did the same thing you did but used #(or %1 %2)

13:48 Any reason why you used % instead of %1?

13:48 justin_smith: ,(map #(or %1 %2) [false true false] [true false false]) ; banana`

13:48 clojurebot: (true true false)

13:48 justin_smith: banana`: no reason at all

13:48 CStorm: thank you justin_smith

13:48 justin_smith: I don't actually use %1 very often, maybe it's a bad habit

13:48 TMA: banana`: it is one character shorte

13:48 justin_smith: haha

13:49 TimMc: by that logic you could replace identity with #(do %)

13:49 err

13:49 TMA: ^ - sorry of the misstag

13:49 banana`: Okay thanks! Turns out I was using apply or reduce when I tried using a macro for or

13:50 justin_smith: banana`: oh yeah, you don't need that, map handles multiple args just fine

13:50 banana`: but also there's for

13:50 TMA: ,do

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

13:50 justin_smith: ,(#(do %) 1)

13:50 clojurebot: 1

13:50 TMA: ,(do 1)

13:50 clojurebot: 1

13:50 ridcully: ,(source do)

13:50 clojurebot: Source not found\n

13:50 banana`: Okay cool thanks for the help justin_smith

13:51 TMA: ,(map do [foo 1 2 3 true])

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

13:51 TMA: ,(map #(do %) [foo 1 2 3 true])

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

13:51 TMA: ,(map #(do %) ['foo 1 2 3 true])

13:51 clojurebot: (foo 1 2 3 true)

13:51 justin_smith: TMA: please don't use #(do %) instead of identity, it is equivalent but it is terrible :P

13:51 just saying less chars isn't strictly always better

13:52 TMA: justin_smith: I won't.

13:53 too bad do is a macro too

13:53 justin_smith: haha

14:20 pilne: so, i'm just getting around to watching the 2013 keynote by paul phillips about just how much is wrong with the compiler side of scala LMAO

14:20 god that's scary

14:20 justin_smith: oh, that's a good talk, but it's about a sad thing

14:21 pilne: 4.2billion states for int testing???

14:21 yeah, it is sad, but lord, is that what building a language to run on the jvm entails?

14:24 CStorm: do you have a link?

14:24 pilne: https://www.youtube.com/watch?v=TS1lpKBMkgg

14:25 justin_smith: pilne: no, not at all. They had some design goals that were a poor fit for the vm.

14:25 pilne: so ambition lead to... dirty magiks that are having a ripple effect now?

14:28 justin_smith: pilne: that was my impression.

14:29 pilne: so TLDR: if you are using something else as a host, conform to it's limitations if you can't achieve what you want sanely?

14:40 justin_smith: pilne: right, but the hard part is truly understanding the limitations, I think

14:45 pilne: true... until you hit them, they aren't really waving their hands by a bonfire...

17:21 bitsynthesis: hello! when writing a plugin which supports multiple versions of clojure, how should the clojure dependency be defined? i gather that leiningen supports version ranges but recommends / warns against using them. is there an alternative?

17:22 rhg135: depend on the earliest you have tested against and document it is what I'd do

17:23 bitsynthesis: that will always pull in that specific version of clojure if the project uses a different one

17:24 so if you're going to specify a version you may as well specify the newest version of clojure it supports, right? since it's going to pull down what it wants regardless

17:24 rhg135: will it? I guess you can also do that

17:25 bitsynthesis: ideally i would like it to use whatever version the project already specifies, if supported

17:25 rhg135: you can always use exclusions

17:26 I always thought lein used any explicit deps over those required by dependencies

17:27 TimMc: If you depend on the earliest version that works for you, you give more flexibility to people who depend on your lib.

17:27 rhg135: oh, plugin you said

17:27 It'll use lein's version which is 1.8 right now iirc

17:27 TimMc: oops, didn't see that

17:29 bitsynthesis: if you specify clojure 1.6 it will use that, not lein's version or the project's version

17:29 rhg135: wouldn't that break lein though?

17:32 TimMc: "Plugins need not declare a dependency on Clojure itself; in fact all of Leiningen's own dependencies will be available."

17:32 https://github.com/technomancy/leiningen/blob/master/doc/PLUGINS.md

17:32 rhg135: that's what I was thinking

17:33 bitsynthesis: TimMc: aha. ok thanks guys. so maybe it is just downloading the version because it's specified, but not using it

17:33 rhg135: you can always check at runtime

17:33 ,*clojure-version*

17:33 clojurebot: {:major 1, :minor 8, :incremental 0, :qualifier nil}

17:57 rhg135: it's so quiet these days

17:57 ~slack

17:57 clojurebot: Cool story bro.

17:57 rhg135: hmm

18:10 ridcully: rhg135: younger generation is taking over the web

18:12 rhg135: ridcully: not sure if I'd say 'younger' but that is certainly possible

18:15 ridcully: or maybe its just sunday and this channel is most active on eu/us working hours

18:15 rhg135: that sounds very likely

18:16 ridcully: or the justin_smith wake hours?!

18:16 rhg135: I heard a rumor that he does not sleep lol

18:17 he only clojures

18:30 CStorm: i setup a profiles.clj with some env vars: {:dev {:env {:secret "secret"}}} – i can get them just fine in my code when i run lein ring server. but after a uberjar i guess its not in "dev" anymore. Where should i add them then?

18:32 rhg135: usually you run on a different environment so I think usually you set it in the environment

18:33 CStorm: but if i just want to use the same secret i use in dev?

18:34 rhg135: lein doesn't usually exist in production, I'm not sure how'd you do that

18:35 CStorm: i am running my project with java -jar file.jar

18:36 so im not using lein.

18:36 its just that im unsure where to put my prod enviroment variables :)

18:36 rhg135: exactly so it won't use anything from profiles.clj

18:37 you set them in the environment, but I'm unsure how to reuse the dev key

18:38 as in env SECRET="secret" java -jar file.jar

18:38 CStorm: Ok

18:38 Will look that up.

18:38 Ty.

18:38 rhg135: np

18:47 newclj: Hey, where do I put my java interface if I want to implement it in clojure? I have it in :gen-class :implements <interface>, but I'm assuming I have to put the .java file somewhere in my clojure proj?

18:51 rhg135: it has to be a .class on the classpath

18:52 in lein :jvm-opts is a vector of a java source tree which will be compiled before launching the repl

18:53 newclj: @rhg135 Thanks, I'll have a look into it

18:53 rhg135: clojure in general is great at interop

19:02 newclj: so I added a :java-source-paths [<path to .javas>] in my defproject and it seems to pick up the interface in IntelliJ, but I still get a class not found exception when running lein uberjar?

19:03 rhg135: yes, sorry :java-source-paths. my brain is jumbled today

19:04 what is the contents of that dir?

19:05 newclj: a java interface and 3 .java files the interface depends on

19:06 rhg135: in subfolders? remember java also requires a certain structure and corrent naming

19:07 newclj: hm no, just on all together in the one dir

19:09 rhg135: for instance: com/rhg135/Test.java containing package com.rhg135; interface Test { public Object doStuff(); }

19:09 newclj: all the files are within the same package in java

19:11 rhg135: but I'm not sure as I don't do java in my lein projects

19:11 or at all manually

19:15 newclj: rhg135: Fair enough, it's definitely picked up in IntelliJ now though :) so thanks for the progress

19:15 rhg135: np

19:25 newclj: rhg135: Just had to specifiy package name in my :implements, working perfectly now :D thanks agian

20:12 rhg135: ah ok. glad it worked

20:34 oich: is clojuresque the only clojure gradle plugin or clojure using gradle approach?

20:38 edannenbe: oich, unless gradle is a requirement, did you try boot yet? it's pretty much the gradle of clojure

20:39 bendavisnc: say hey guys, is there any way to have something similar to a javascript object in clojure, by that, i mean some hash map with an idea of "this"

20:40 justin_smith: bendavisnc: for "this" to be useful you need methods

20:40 bendavisnc: perhaps you want defrecord

20:41 bendavisnc: ok yeah probably

20:41 all i want is some namespace to define values and methods and maybe / probably abstract methods / values as well

20:41 justin_smith: defrecord can implement methods from interfaces or protocols, and each one gets a "this" arg

20:42 bendavisnc: wait, namespace?

20:42 bendavisnc: are things like that completely discouraged in lisp land?

20:42 yeah, like just a scope level of values

20:42 justin_smith: bendavisnc: I mean we have defrecord but we also have namespaces and their usages don't overlap

20:43 oich: edannenbe I have barely looked at boot so far. I've gotten further with leiningen. But, yes the project needs to be able to be used by people other than me and so, not boot or leinengen

20:43 bendavisnc: eh ok. i think i'm just using the word more liberally

20:43 justin_smith: namespaces are first class though, if that's what you actually want

20:44 sineer: Hi! I use core.async thread to fill up a channel and a go block to empty it. How do I wait for the thread to finish and channel to empty before main exit?

20:44 bendavisnc: ok. i think i need to rethink what i'm doing. maybe i don't need this

20:45 sineer: I've been trying to find good examples but did not find any, probably just not looking for the right thing

20:45 justin_smith: sineer: core.async/thread returns a channel, if you try to read that channel you won't get a value until the thread exits

20:45 sineer: justin_smith: ok, thanks!

20:45 justin_smith: so if your primary thread reads from that channel, that primary thread won't exit until the thread does (of course)

20:46 sineer: what about the go blocks? I doseq lots of them to empty the channel..

20:46 justin_smith: they also each return a channel

20:47 sineer: oh yeah and now I don't doseq lots of them anymore just one go block and doseq is in my thread.. neat, thanks again!

20:51 bendavisnc: would it be a bad idea / is it possible to have a hashmap as like a base template, and have a hashmap value be lazy but a throw exception if accessed without merging first?

20:52 does that make sense?

20:52 justin_smith: there are no lazy hashmaps

20:52 bendavisnc: ok but are there lazy hash map values?

20:52 justin_smith: the only thing that is lazy is a lazy-seq

20:53 bendavisnc: like a key has an expression that's not evaluated until accessed?

20:53 rhg135: justin_smith: does not datomic do it for entities?

20:53 justin_smith: no, that does not exist

20:53 bendavisnc: value*

20:53 justin_smith: rhg135: OK, there are no lazy hash-maps in clojure.core

20:53 * rhg135 nods

20:54 bendavisnc: i think i may be able to use delay for what i'm thinking

20:54 rhg135: delay is a good compromise

20:55 I once thought of writing a facade over maps with delayed keys

20:55 justin_smith: bendavisnc: what does "hash map as like a base template" mean?

20:56 bendavisnc: like i'm basically trying to make an abstract class

20:56 which maybe just isn't clojureish at all

20:56 justin_smith: bendavisnc: just use a hash map. They are immutable, so your function can just assoc something to it.

20:56 bendavisnc: but i want something with base values that gets extended

20:57 justin_smith: bendavisnc: that's what assoc does

20:57 bendavisnc: the map is immutable, assoc returns a new one with your associations performed

20:57 so you don't need a special template, you just need a hash map, and assoc

20:57 bendavisnc: ok but how do i say, like, this value will be in this map. or an extension of this map?

20:58 justin_smith: what is an extension?

20:58 bendavisnc: a merge call i think

20:58 rhg135: schema, yo

20:58 bendavisnc: yeah probably

20:58 base template = schema = abstract class

20:58 justin_smith: yeah, sounds like you want prismaticschema, this is not a thing in the language itself

20:58 bendavisnc: no he is talking about a specific library called schema

20:59 bendavisnc: ah ok thanks for the heads up

20:59 justin_smith: bendavisnc: abstract classes are abstract classes, this is the jvm so we have them too but they are not useful

20:59 rhg135: well, asserts exist

20:59 ,(assert (string? (:x {})))

20:59 clojurebot: #error {\n :cause "Assert failed: (string? (:x {}))"\n :via\n [{:type java.lang.AssertionError\n :message "Assert failed: (string? (:x {}))"\n :at [sandbox$eval25 invokeStatic "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval25 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox$eval25 invoke "NO_SOURCE_FILE" -1]\n [clojure.lang.Compiler eval "Compiler.java" 6927]\n [clojure.lang.Compiler eval "Compi...

20:59 bendavisnc: right ok

20:59 justin_smith: rhg135: asserts are a supertype of type asserts

20:59 bendavisnc: i'm super new to thinking in functional terms

20:59 justin_smith: *superset

20:59 bendavisnc: let me ask this though:

21:00 rhg135: ah right!

21:00 bendavisnc: say i have a situation, where basically i'm calling / mapping all of these functions

21:00 and in all of these functions, i'm always passing the same variable as like an extra parameter that basically represents a context of information

21:01 like the program is always the same, but these are our global variables

21:01 rhg135: partial, yo

21:01 * rhg135 needs to stop using that word

21:01 bendavisnc: hmmmm

21:01 justin_smith: bendavisnc: again with the wording, vars (the things created with def) are all globally accessible but in namespace scope

21:02 but yes, if you want to provide some extra data in function calls partial is very helpful

21:02 if it's like a boilerplate everything gets this arg thing in particular

21:02 rhg135: (def contextify (partial partial))

21:03 justin_smith: bendavisnc: and yes, an argument passed to every function you call is equal in power computationally to a global

21:03 rhg135: lol

21:03 bendavisnc: justin_smith: i get that, but what i was wondering was a. is it frowned upon? b. is there a pretty straight forward default approach to an alternative?

21:04 rhg135: ,(((partial partial) + 1) 2 3)

21:04 clojurebot: 6

21:04 justin_smith: bendavisnc: haskell has monads for this :)

21:04 you can get monads from a lib but they are weird and don't perform well and are not part of the core language

21:04 bendavisnc: justin_smith: omg, i've been trying so hard to learn that word in scala land

21:05 rhg135: monads are great just not when you need them

21:05 bendavisnc: what i'm doing is, i basically have this program that renders an image, and i have render parameters

21:05 stuff like width height etc

21:06 i have files that could be like json files

21:06 render parameter files

21:06 and i'm just trying to figure out what to do with these files / how to incorporate the data

21:07 so basically i have these hashmaps

21:07 that should be an interface in java / scala land

21:07 justin_smith: interfaces do not contain data though

21:07 they describe methods you can call

21:07 bendavisnc: but the data fits a common interface

21:07 there's always a width, etc

21:08 justin_smith: interfaces are for executable methods not data

21:08 bendavisnc: dude that's just wrong

21:08 rhg135: a protocol can be backed by a map

21:08 bendavisnc: an interface of course can define a value

21:08 justin_smith: bendavisnc: this is the jvm, "interfaces" are a specific thing that describe methods not fields

21:08 bendavisnc: in java i guess it's a little weird, and it's actually a hard coded getter

21:08 but in scala it's straight forward with traits

21:09 so i guess yeah java would have to be an abstract class

21:09 sorry i shouldn't say interface

21:10 rhg135: ,(do (defprotocol A (get-a [me])) (extend-protocol A clojure.lang.PersistentMap (get-a [me] (:a me))) (get-a {:a 1}))

21:10 clojurebot: #error {\n :cause "clojure.lang.PersistentMap"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: clojure.lang.PersistentMap, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.ClassNotFoundException\n :message "clojure.lang.PersistentMap"\n :at [java.net.URLClassLoader$1 run "U...

21:10 justin_smith: bendavisnc: anyway, in clojure world the best thing that does the things you describe is prismatic/schema

21:11 bendavisnc: ok so yeah actually maybe this helps pin point what i wanna do?

21:11 in java, this would be an interface

21:11 could be*

21:11 rhg135: that's a lot of wrapping around a map

21:11 justin_smith: prismatic/schema describes layout of immutable data

21:11 bendavisnc: and the method promise would be like public int getWidth()

21:11 justin_smith: an interface or protocol in clojure describes methods you can execute

21:12 what is a method promise?

21:12 bendavisnc: a signature declaration

21:13 justin_smith: bendavisnc: when you have immutable data, getters are just annoying boilerplate

21:13 if you need data use data, if you need methods use methods, and if you really really want to be mutable yeah use deftype or something and use getters and private things and yadda yadda

21:14 but the premise in clojure is we almost never need mutation, and when we do we just use a simple mutable box that only holds one value

21:14 (unless we need to do otherwise for compatibility reasons)

21:14 bendavisnc: justin_smith: i'm not talking mutation

21:15 justin_smith: bendavisnc: why the hell do you want getters then?

21:15 my point is forget about getters and interfaces, make a data declaration with prismatic/schema and just use that data

21:16 rhg135: in java they usually used to hide the actual structure of the data, justin_smith

21:16 justin_smith: and most of the time you only need prismatic schema at system boundaries where very different systems try to interact within one program

21:16 bendavisnc: so i want to define methods that works on data

21:16 immutable data

21:16 justin_smith: rhg135: I know this is usual, it's also not how we do things in clojure

21:16 bendavisnc: OK, define methods in a protocol

21:16 or just make functions instead or use methods later when you realize you actually need that (usually you do not)

21:17 rhg135: I mean, mutability and encapsulation are complected into getters

21:17 bendavisnc: rhg135: sorry, are what into getters?

21:17 justin_smith: bendavisnc: complected means "made complicated" by joining

21:17 rhg135: in to rather

21:18 justin_smith: bendavisnc: complecting is the opposite of that thing where you separate things that have nothing to do with each other and suddenly everything is simpler (aka simplification)

21:18 rhg135: but yes the idea to use a function is the approach I'd take

21:19 justin_smith: rhg135: I'd assert that mutation makes getters neccessary though, so it's not neccessarily a complex

21:19 bendavisnc: thanks a ton guys for bearing with me

21:19 rhg135: that way you only have to change it if you change the structure

21:19 bendavisnc: idk, scala made me think differently about the division between function and value

21:19 justin_smith: np, hope I don't seem impatient or overly vehement here, I get absurdly excited about these issues :)

21:20 scala does lots and lots of complecting

21:20 rhg135: justin_smith: only in some cases. Most getters I've seen just do `return this.x`

21:20 bendavisnc: it made me want to program more in a way where i'm talking about values that don't exist yet

21:21 justin_smith: lazy-seqs, promises, and delays make some of this possible, but not in the haskell "everything is lazy" way of course

21:21 bendavisnc: i sorta wish i knew how to write this code in clojure

21:22 def getWidth(): Int = {throw new Exception(getWidth not overriden)}

21:22 i thought a delay does that but now i don't

21:22 mgaare: bendavisnc: you can't just "flatmap that shit"

21:22 rhg135: ,(do (def data {:a (delay 1)}) (defn get-a [m] @(:a m)) (get-a data))

21:22 clojurebot: 1

21:22 mgaare: bendavisnc: Clojure takes a stand against concrete derivation, which it sounds like you're trying to do

21:23 bendavisnc: mgaare: i don't know what you mean by can't flatmap, but i wish i did

21:24 mgaare: bendavisnc: sorry, just little scala joke.

21:24 bendavisnc: mgaare: ah ok

21:24 man i like so much about both languages

21:24 mgaare: I briefly worked at a Scala place, and some coworkers suggested that should be the official motto of the language

21:24 bendavisnc: i was sorta hoping i could treat clojure like a dynamic clojure where i could type class only when i wanted

21:25 maybe that's dumb

21:25 justin_smith: clojure is a dynamic clojure, so that's a start

21:25 but we don't mess with types much (for better and also for worse)

21:25 bendavisnc: haha sorry, treat clojure like a dynamic scala

21:26 rhg135: I take the python approach were a class is just a bunch of obfuscated data

21:26 justin_smith: if you want strong typing and compile time proofs as your top priority, you probably want scala not clojure

21:26 mgaare: bendavisnc: there are a few tricks you can do here. so you have your `width` function, and you're saying you don't want that to work unless some specific type is implementing it, right?

21:26 rhg135: and on the jvm classes are mostly immutable

21:26 objects though...

21:26 bendavisnc: mgaare: you understand my sould

21:26 soul*

21:27 mgaare: bendavisnc: so you could define a protocol, say, like this: (defprotocol Dimensions (width [this]) (height [this]))

21:28 so if you try to call that width function on something that doesn't implement it, you'll get an exception already.

21:28 But perhaps you want a more specific exception? Or what?

21:29 bendavisnc: mgaare: ok yeah that is what i want

21:29 thanks for getting that, i don't need a compile time exception really

21:29 i basically just don't want to define a value

21:29 rhg135: mgaare: technically, if you used straight maps you'd still get an exception anyway, but it'd probably be a NPE then

21:29 bendavisnc: at a time a define it

21:29 say

21:29 (def width 0)

21:30 and worry that my width is ever zero

21:30 i should say that's not my only intention

21:30 i also just want to express that there's a scope of execution with a width value

21:30 mgaare: where you're kind of going off the rails of idiomatic Clojure a bit is thinking about it in terms of some kind of abstract class that you'll subclass for implementations of this.

21:31 bendavisnc: ok yeah

21:31 thanks

21:31 rhg135: {:pre [(not (zero? n))]}

21:31 justin_smith: bendavisnc: def only creates vars, which are global mutable values inside a namespaced global scope, and our data is immutable, you can't have invalid partial state in an immutable data structure

21:32 bendavisnc: ok

21:32 yeah

21:32 i'm sorta a scala guy

21:32 justin_smith: bendavisnc: immutability is our cure for partial state (you might want runtime checks for other sources of invalid state of course)

21:32 bendavisnc: but i'm also just sorta a javascript guy

21:33 i want something that in jquery land i would merge

21:33 and then i could call a function inside it, which would have access to everything inside the called object

21:33 justin_smith: bendavisnc: "inside it"

21:33 bendavisnc: and theoretically, you could call this existing method on a template that hasn't been extended or provided values, so the method should tell you it failed

21:34 mgaare: bendavisnc: good old javascript emulated modules

21:34 bendavisnc: and that method can be getWidth for example

21:34 and i guess that's just bad clojure code?

21:34 mgaare: So this way of thinking about Javascript's object model is a good fit for Clojure in some ways and a bad fit in others.

21:35 bendavisnc: i wanna write something close to

21:35 myCrazyArtThing.withWidth(100).render()

21:35 justin_smith: bendavisnc: I think you will find that compared to what you are used to, clojure is not a flexible language for programming styles. But the "one true way" clojure strongly encourages with its design does actually work out pretty well.

21:35 bendavisnc: (render (assoc crazy-ar-thing :width 100))

21:36 rhg135: ,(do (defn call [m k & args] (apply (get m k) m args)) (call {}))

21:36 clojurebot: #error {\n :cause "Wrong number of args (1) passed to: sandbox/call"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (1) passed to: sandbox/call"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.RestFn invoke "RestFn.java" 412]\n [sandbox$eval26 invokeStatic "NO_SOURCE_FILE" 0]\n [sand...

21:36 rhg135: eh, something like that would work

21:36 mgaare: Clojure's object model is really nothing like this, so thinking about templates and prototypes isn't helpful. However, Clojure records give you a lot of what you want, in that when you implement a protocol in a record, all the fields of the record are available in the scope of the function

21:37 rhg135: the point is the passing in of the this is explicit

21:37 bendavisnc: justin_smith: that's a really interesting thing to say

21:37 amalloy: defining a protocol and a record just for scoping reasons should make you pretty sad

21:37 bendavisnc: so when ppl say clojure is flexible, they sorta need to be careful what they mean

21:37 it sounds like anyways

21:38 justin_smith: bendavisnc: for example at every turn clojure makes concrete extension (inheritence) arbitrarily difficult to do. Because the language designers think it's a bad idea to use it.

21:38 bendavisnc: yeah, I would never call clojure flexible

21:38 rhg135: clojure is very flexible, but flexibility has a cost

21:38 justin_smith: hmm...

21:38 rhg135: usually it's a lot of buggy code to write

21:39 mgaare: bendavisnc: it's not flexible in the sense that javascript is flexible, which is where you can write in almost any kind of style you want but then someone writes a book called "Javascript: The Good Parts" and it's 50 pages long

21:39 bendavisnc: hahaha yeah i see what you guys are saying sorta

21:39 is it a similar style philosophy to python?

21:40 mgaare: I think so, yes

21:40 bendavisnc: like i sorta feel like clojure / python are the right wingers of the programming language world

21:40 rhg135: actually python's methods are implemented by essentially partialling the instance when you access them via an instance

21:40 justin_smith: there's a few languages I would count as opinionated, including python yeah and also ml and C even

21:41 mgaare: rhg135: I think he meant python and clojure are similar in the sense that both of them have strong opinions about the correct way to write code in the language

21:41 justin_smith: bendavisnc: if you are looking for a flexible, relatively unopinionated lang, once again scala's probably your guy (but I'm here because I agree with clojure's opinions generally)

21:41 rhg135: yeah, I'm just pointing out objects are essentially a map with partial functions

21:42 amalloy: "partial functions" means something specific and quite different from partially-applied functions

21:42 bendavisnc: yeah

21:42 i've been thinking a lot about this lately

21:42 rhg135: yeah I meant partially applied

21:43 bendavisnc: i love lisps "data is code" mantra

21:43 rhg135: lexicon failure

21:43 bendavisnc: and i was thinking about what type of language would be if you could extend json

21:43 and im thinking that's basically, lisp, right?

21:43 justin_smith: lisp with some extra data types sure

21:44 clojure is that plus default immutability in many ways

21:44 bendavisnc: but yeah, i'm just saying it's a 1000 x closer that lisp's schema than to scalas

21:44 rhg135: isn't that what xml was plus a bunch of cruft?

21:44 bendavisnc: and then another few magnitudes of lines, i guess we get to java

21:45 i mean an executable json

21:45 a self referential json

21:45 justin_smith: java doesn't have the data literals though

21:45 and doesn't do self reference nicely at all

21:45 (in my experience)

21:45 bendavisnc: like if i could write this code:

21:46 {crazyArtProject: {width: 0, height: 0, size: this.width * this.height}}

21:46 which yeah... i guess that's literally javascript

21:47 rhg135: {"function": "add", "args": [1 2 3]}

21:47 indeed, json requires string keys too

21:47 bendavisnc: idk. javascript doesn't seem data first but i hoenstly don't know how to articulate that

21:48 maybe i'm looking for an eager evaluation javascript

21:48 rhg135: js is eager...

21:50 bendavisnc: shit sorry

21:50 i was thinking how in js

21:50 [1, 2, 3] is sorta equal to '(1 2 3)

21:51 justin_smith: ,(= [1 2 3] '(1 2 3))

21:51 clojurebot: true

21:51 bendavisnc: that's weird

21:51 or not

21:51 justin_smith: bendavisnc: structural equality

21:51 bendavisnc: sorry i'm use to java

21:51 rhg135: not really

21:52 justin_smith: bendavisnc: if two values are immutable, and have the same effective shape, clojure typically considers them equal

21:52 rhg135: if you use the seq interface '(1) is as good as [1]

21:52 bendavisnc: gotcha. yeah i like that

21:52 so you literally never have situations of something like toList?

21:53 rhg135: list* is sometimes used

21:53 amalloy: list* is not like toList at all

21:53 seq kinda is

21:54 rhg135: well I don't know scala so I only guess

21:54 into maybe

22:03 bendavisnc: thanks again guys for your time and insights

22:03 night

22:38 solatis: ok, so, in clojure idiomatic code, what does one do when someone calls a 'find' operator which has no result? return nil?

22:39 amalloy: ,(find {} {})

22:39 clojurebot: nil

22:39 amalloy: good thing to take inspiration from

22:39 solatis: ah that's great

22:42 TEttinger: hm, any Cursive experts around? I'm having an odd issue where at the command line lein can see deps just fine, but in IntelliJ with Cursive, none of the deps seem to be on the classpath and aren't even visible.

22:43 so no suggestions for deps, errors on anything defined in a def...

22:43 *dep

22:43 howdy cfleming :)

22:46 I've tried re-synchronizing the project.clj, I don't see any analogue to `lein deps`

22:47 on intellij 15.0.2 if it matters

22:49 appears to be cursive 1.1.0-15

22:49 amalloy: TEttinger: try invalidating caches and restarting

22:49 TEttinger: will do

22:49 amalloy: that's often fixed intellij issues for me

22:52 TEttinger: nope, initially it opened up and there was no context on -main , like it was plain text. I closed core.clj with that in it, reopened, and highlighting came back saying dep can't be found, etc.

22:52 solatis: is there any way to force lein to re-download a specific directory when i know for sure that, even though the version is the same, the .jar has been modified?

22:52 this is about a 'internal-lib-0.1.0-SNAPSHOT'-style library

22:52 it's hosted in a private s3 repo

22:52 TEttinger: there's some flag to pass to lein deps, I think it miiiight be -U

22:52 I'd check the lein docs

22:53 solatis: yeah but that doesn't seem to work :/

22:53 TEttinger: there's also the deleting-the-directory-in-.m2 approach

22:54 solatis: yeah, that second one is the one i didn't want to use

22:54 well, sucks, guess i have to do the delete-.m2 approach anyway

22:55 TEttinger: not the whole thing though

22:55 solatis: yeah i know

22:55 TEttinger: you can just delete the directory that's old oh ok

22:55 solatis: the thing is, i want to set up an agile environment where every dev always has the most up-to-date checkout of this private library

22:55 TEttinger: ha, that's exactly what I'm trying to do using jitpack.io

22:56 but that's more for public libs

22:56 solatis: so i am now using our continuous deploy strategy to continuously deploy to S3

22:56 and have our devs use that as a dependency

22:56 which works great, until you update it with the same version number...

22:56 so guess we should stop doing that

22:57 TEttinger: hm, I know maven treats SNAPSHOT versions differently

22:57 solatis: hmm

22:57 thats interesting

22:58 i know in other language environments, you're able to 'symlink' to a local dependency

22:58 so do a git checkout, and then tell the build tool to use that local checkout for a certain dependency, rather than a public repo

22:58 TEttinger: yeah, you can in lein, I think. `lein install`

22:58 solatis: aha

22:58 aha!

22:58 that would solve all my problems

22:58 TEttinger: though that installs whatever the project.clj has for a version

22:58 solatis: yeah sure

22:59 TEttinger: also I am super rusty

22:59 solatis: but it's more of a situation where dev A fixed a bug in internal library, and dev B needs to be able to use that fix

23:00 TEttinger: https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md#snapshot-versions

23:00 solatis: \o/

23:01 thanks

23:01 didn't know there was that kind of logic

23:01 TEttinger: also checkout deps

23:01 that's a feature I haven't seen before in lein

23:03 solatis: it looks like checkout deps may solve more features than I thought

23:04 since if everyone can just get an updated copy of the source, then they'll automatically see the source changes when the code changes

23:04 it looks like repls will pick up on the change without restarting too

23:04 clojurebot: Cool story bro.

23:05 TEttinger: classic

23:05 solatis: nice, nice

23:05 now, where do i find a good clojure dev to hire...

23:06 i think there was a slack channel for that

23:07 TEttinger: is it a local thing? I think that may affect your hiring choices significantly

23:07 clojure devs in topeka kansas vs. the bay area... uh...

23:09 hiredman: if you are hiring, I am looking

23:09 mgaare: solatis: me also

23:09 TEttinger: but your name says "hired"

23:10 solatis: lol

23:11 TEttinger: mgaare: do you have any open source projects out there? one of hiredman's open source contributions just said "Cool story bro."

23:11 solatis: yeah, being around the office is required, sadly

23:11 but, I'm introducing Clojure big time on our organization

23:11 TEttinger: great!

23:11 solatis: (it's in Amsterdam)

23:12 TEttinger: that is not a bad place to live at all.

23:12 solatis: exactly, we sponsor visas

23:12 TEttinger: what's the english-speaker ratio like? if someone didn't speak dutch

23:12 solatis: we speak english exclusively at the office

23:12 TEttinger: then again dutch is about as close to english as it gets

23:13 solatis: we have several international team members already

23:13 and well, dutch people are insanely good at speaking English, on average

23:13 TEttinger: I'd expect it, the vocabulary is so close

23:14 even word order is similar, and english doesn't often share that

23:14 solatis: well it's rather because we're a small country, which depends a lot on other countries for trade, doing business, etc

23:14 hiredman: https://twitter.com/justincampbell/status/575447532865609728

23:14 solatis: and we don't dub our movies, we subtitle them

23:14 etc

23:14 hiredman: hehe i know

23:15 hiredman: it's a difficult decision

23:15 i'm CTO, so i *can* make the call

23:15 but i do want people to be around the office 1 or 2 days a week _at least_

23:15 but yeah, you're severely limiting your choices

23:15 TEttinger: I have a bunch of random generators that imitate an existing language, and if you don't stick in way more english-only markers (-ought, -augh) than should probably be there, fake english looks more like fake dutch

23:16 hiredman: there was some microsoft studies just making the rounds

23:16 solatis: TEttinger haha

23:16 hiredman: http://research.microsoft.com/apps/mobile/news.aspx?post=/en-us/news/features/nagappan-100609.aspx

23:16 solatis: hiredman: well, i worked from a low-cost country as a freelancer for 2 years, and it's definitely very much possible

23:16 hiredman: "Geographical Distance Doesn’t Matter— Much."

23:17 solatis: the problem with remote work is that it only works with really good, and independent developers

23:17 hiredman: everyone claims to hire the best

23:17 so, everyone should have no problem with it

23:17 solatis: haha

23:17 if only that were true! sometimes you just need to expand the team and hire developers that are 'good enough'

23:18 but in general i agree with you

23:18 i can get a lot more done when i'm not at the office

23:20 TEttinger: seeing as I don't have an office, my productivity often depends on whether my cat has decided my chair is now his chair

23:20 so I don't have an office but I do have a boss

23:20 solatis: yes, cats can be quite dominant bosses

23:20 especially when it concerns food

23:24 TEttinger: heh, satchmo (younger cat) isn't demanding about much at all. my other cat (eddie) is very demanding about some very specific things, like his tent. we have turned a guest bed into a full-time tent for eddie, pulling the covers up over the headboard so he has a place to stay. when my brother actually needed that bed... eddie would pester him until the bed became a tent again

23:25 these cats are the bosses

23:26 solatis: lol

23:26 so, you actually have given your whole cat a bed

23:27 never cave to a cat's demands!

23:27 justin_smith: as opposed to people who give part of their cat a bed

23:27 solatis: you give him a pillow, and he takes the whole bed!

23:27 lol justin_smith ... it's early in the morning here, give me a break

23:27 TEttinger: yeah, eddie is pretty darn happy with that tent

23:28 he purrs in there constantly

23:28 solatis: my cats have to sleep outside

23:28 fuck them

23:28 my house

23:28 TEttinger: you don't have coyotes or coywolves in amsterdam

23:28 solatis: well i'm in cambodia now actually

23:28 justin_smith: TEttinger: kitty purr indicator is one of the few KPIs that aren't complet bs

23:28 solatis: you have things like snakes

23:28 TEttinger: mm

23:29 solatis: but my cats are vicious

23:29 they eat poisonous snakes for breakfast

23:30 justin_smith: "between the tuna plan, and the tent, and the blind flightless bird program, our KPI numbers look excellent this quarter"

23:30 TEttinger: coywolves are terrifying though. coyotes don't have any fear of humans. wolves can bring down larger animals than people and do so regularly. mix the two and you end up with the property of all wolf hybrids where they don't have the behavioral cues of either parent

23:31 solatis: sounds like something out of a zombie movie

23:31 TEttinger: apparently because wolf numbers have dwindled so much in the northeast US and nearby canada, wolves breed with the newly introduced coyotes out of necessity, and produce much more effective offspring

23:31 we just have plain coyotes here in so cal

23:31 but they are loud

23:32 all night, yipping furiously

23:33 they think coywolves are so effective because the whitetail deer hasn't had any common predators since people nearly wiped out wolves, so you have inexperienced deer and suddenly a predator that's just big enough to bring one down and works in groups

23:33 and coyotes can't bring down deer normally

23:38 also, if you want zombie movie, there are fish that I believe are common in cambodia and are now invasive in parts of the US. https://en.wikipedia.org/wiki/Snakehead_(fish)

23:38 yep, They are one of the most common staple food fish in Thailand, Cambodia, Vietnam, and other South East Asian countries, where they are extensively cultured.

23:58 solatis: TEttinger3: haha yes i am fully aware of that. fucking monkeys can be lethal over here

Logging service provided by n01se.net