#clojure log - Sep 19 2015

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

4:34 Empperi: 01:54 [rajaniemi] DCC SEND from crowgoose [ port 43352]: virus.exe [13kB bytes] requested in channel #clojure

4:34 01:59 [rajaniemi] DCC aborted receiving file virus.exe from crowgoose

4:34 okey dokey

4:35 got to say one has to be pretty desparate to try that on such a channel

4:55 ahoegh_: Empperi: crowgoose tried the same one me.

5:24 m1dnight_: Does anyone know how I can create .edn config files that can change after I created an uberjar? As it currently stands I have to recreate the uberjar each time I change the config.

5:31 mavbozo: m1dnight_, what's this config.edn file contains? can't you put the config.edn file somewhere outside the uberjar?

5:33 m1dnight_: Well, the thing I don't know exactly is, can I just put a relative path in the codebase then? So that, say, the foo.edn file is always in the root directory of the jar file?

5:34 Maybe I can just play around with it. (edn/read-string (slurp (io/resource "servers.edn"))) This is how I read the config file at the moment.

5:36 mavbozo: you can run your uberjar with java -jar -Dconfig.location="/etc/my-app-config.edn"

5:36 and in your code, you can get the config.location with (System/getProperty "config.location")

5:37 TEttinger: m1dnight_: if it's a resource it's inside the jar. you can modify the jar to replace the resource I think

5:37 m1dnight_: oh that might be something Im interested in, mavbozo

5:37 TEttinger: but the thing is that modifying/recompiling the jar takes some time and I would just like to stop and start it to re-read the config

5:37 It doesnt have to be inside the jar.

5:37 I will have a look at it right away!

5:37 TEttinger: or you can change it from a resource to just (edn/read-string (slurp "servers.edn"))

5:38 hm

5:38 if you had a resource called servers.edn and you tried to get a local file with the same name, it would prefer the resource I think?

5:38 not sure

5:39 m1dnight_: To the experimentation-mobile!

6:12 justin_smith: you need io/resource to get the resource inside the jar

6:12 then it finds the first one in the classpath

6:25 m1dnight_: I stranded on setting the system property and then reading in the files like this: (edn/read-string (slurp (io/file config-path file)))

6:25 where config-path is the System/getProperty and file is the filename.

6:26 justin_smith: if you don't need to read anything inside the jar, that would work

6:27 m1dnight_: Exactly! If I want to change the path to a temporary database or w/e I dont have to recompile. Which is nice.

7:03 triss: there's not a function like swap! that returns the value before the function provided is applied is there?

7:11 m1dnight_: Afaik there is not, no.

7:12 Bronsa: triss: no, http://dev.clojure.org/jira/browse/CLJ-1454

7:13 m1dnight_: Does anyone know if its possible to fold with an index? I want to iterate over a list of integers and return the index (1-based) of the higherst value.

7:14 triss: okeydoke. keep a ref to previous value isn't too much hassle for now.... surprised how many times its been implemented tho

7:15 m1dnight_: Are refs not an option for the value as well?

7:15 You could use (dosync (ensure x) (let [old-value @x] (ref-set! x new-value)))

7:15 or somethiong

7:16 You could use (dosync (let [old-value (ensure x)] (ref-set! x new-value))) even!

7:17 Bronsa: m1dnight_: using the STM for simple CAS semantics seems an overkill

7:17 m1dnight_: Well you can then store {:curr :old} in the atom and update the old in swap! function and read that out afterwards

7:17 Bronsa: m1dnight_: wrt your question, just use a tuple as acc value to your reducing function and keep track of the ids

7:18 and incur a map lookup everytime you need to access the value?

7:18 m1dnight_: and that would work in a concurrency setting as well as you get the new value returned and can read the "old" value from the result of swap

7:19 a map lookup is about O(1).

7:19 *about*

7:20 Bronsa: m1dnight_: that's irrelevant, it's always a c more than no lookup & forces you to (comp :new-value deref) rather than simply deref every-time you need to get the value

7:21 m1dnight_: Thats true. But the point is that you have to work with swap! and that it can not do what triss wants so you have to work around that.

7:21 How would you do it?

7:22 Bronsa: m1dnight_: sure but there are better workarounds than the one you proposed, see http://dev.clojure.org/jira/browse/CLJ-1454

7:22 https://github.com/flatland/useful/blob/develop/src/flatland/useful/state.clj#L43 this one solution I like the most

7:22 m1dnight_: oh I see. yes the compare and swap one is much better idd

7:23 Allright Bronsa, I stand corrected! :)

7:23 triss: cheers Bronsa

7:23 and m1dnight_ !

8:12 gko: If I want to create a parser library with a default "main", should I use lein new app (that can be 'require'd to be used as any other library) or lein new default (and add "main" stuff myself) ?

8:52 triss: is it possible to make fireplace put evaluations output in to a vim buffer so I can refer back to it?

8:52 i'd love to have a pane open with the output of the last few commands in.

9:02 oh it seems :Last is doing the job

10:54 monsta: What is the differenct from using (vec (1 2 3)) and (into [] (1 2 3))

10:57 lodin_: monsta: I don't know, but I always use vec if what I want to do is to "cast" a sequence to a vector.

11:27 kavkaz: What is the most preferrable SQL library for Clojure? Is there one that most people use for backend stuff?

11:35 justin_smith: kavkaz: clojure.java.jdbc is probably the most used

12:21 xtrntr: can i interrupt a doseq?

12:22 tcrayford____: xtrntr: you can throw an exception to interrupt I guess :/

12:23 there's no `break` keyword or anything else like that in clojure though

12:23 xtrntr: alright

12:23 thanks

12:24 tcrayford____: generally you'd just use `filter` to remove the elems you don't want to iterate over though

12:24 * tcrayford____ hasn't wished for a break in ~6 years of doing clojure

12:26 xtrntr: no, there's some kind of animation loop.. i suppose if i wanted to kill the animation halfway, i should put some kind of flag in the function?

12:26 or is that bad clojure?

12:29 noncom: xtrntr: user (loop) with (recur) then

12:29 tcrayford____: yeah, I'd vote for loop/recur

12:30 xtrntr: oh, there's a company named such

12:30 :)

12:37 justin_smith: xtrntr: if your processing of a sequence needs to stop arbitrarily, use reduce and reduced

12:37 use loop if you are doing something more complex than just walking along a sequence

12:38 ,(reduce (fn [acc el] (if (> el 10) (reduced acc) (conj acc el))) [] (range))

12:38 clojurebot: [0 1 2 3 4 ...]

12:38 justin_smith: anyway, range is infinite, that's our proof the reduce stopped

12:38 *indefinite

12:39 ,(reduce (fn [acc el] (if (> (rand) 0.5) (reduced acc) (conj acc el))) [] (range))

12:39 clojurebot: [0 1 2]

12:39 justin_smith: ,(reduce (fn [acc el] (if (> (rand) 0.5) (reduced acc) (conj acc el))) [] (range))

12:39 clojurebot: [0]

12:39 justin_smith: ,(reduce (fn [acc el] (if (> (rand) 0.5) (reduced acc) (conj acc el))) [] (range))

12:39 clojurebot: []

12:39 justin_smith: ,(reduce (fn [acc el] (if (> (rand) 0.5) (reduced acc) (conj acc el))) [] (range))

12:39 clojurebot: []

12:39 xtrntr: i'm going to need time to get used to this..

13:01 noncom: how do i convert between js Date and cljs-time date ?

14:00 tolstoy: Something like: (cljs-time.coerce/from-long (.getTime (js/Date.))) ?

14:00 m1dnight_: Cljtime uses a lot of different formats

14:00 justin_smith: ,(frequencies (repeatedly 1000 #(reduce (fn [acc el] (if (> (rand) 0.5) (reduced acc) (+ acc el))) 0 (range))))

14:01 clojurebot: {0 754, 1 129, 15 8, 21 4, 36 3, ...}

14:01 tolstoy: Oh, from-date. ;)

14:02 justin_smith: ,(str (frequencies (repeatedly 1000000 #(reduce (fn [acc el] (if (> (rand) 0.5) (reduced acc) (+ acc el))) 0 (range)))))

14:02 clojurebot: "{0 749935, 153 2, 1 125070, 55 219, 15 7802, ...}"

14:03 m1dnight_: justin_smith: i was just looking for the frequencies today. Damn.

14:03 justin_smith: ,(apply str (frequencies (repeatedly 1000000 #(reduce (fn [acc el] (if (> (rand) 0.5) (reduced acc) (+ acc el))) 0 (range)))))

14:03 clojurebot: "[0 750190][153 2][1 124774][55 247][15 7791][21 3912][136 3][91 28][36 995][6 31478][28 1906][3 62449][66 120][45 496][78 73][120 7][10 15513][105 15][190 1]"

14:04 justin_smith: ,(apply str (sort-by second (frequencies (repeatedly 1000000 #(reduce (fn [acc el] (if (> (rand) 0.5) (reduced acc) (+ acc el))) 0 (range))))))

14:04 clojurebot: "[171 1][190 1][153 2][136 5][120 10][105 10][91 32][78 64][66 112][55 238][45 492][36 976][28 1965][21 3914][15 7745][10 15816][6 31466][3 62785][1 124896][0 749470]"

14:05 * justin_smith is off to see if that follows ziph's law.

14:20 csd_: what's the simplest way to replicate common lisp's progv in clojure? http://clhs.lisp.se/Body/s_progv.htm -- i.e. where you pass it a map and it sets up let bindings for all the k-v pairs in the map

14:21 justin_smith: csd_: flatland/useful has a macro that does that

14:23 csd_: any idea what it might be named?

14:24 justin_smith: one moment

14:27 csd_: I either lost it or misremembered

14:27 csd_: it would require calling eval unless the hash-map is a compile time literal

14:29 csd_: nah the bindings need to be made dynamically

14:29 justin_smith: csd_: the problem is you don't even know what keys (therefore what symbols) might be bound

14:29 that requires eval

14:29 unless you have a list of possible symbols somewhere...

14:31 csd_: i'm trying to port this over from CL http://norvig.com/paip/patmatch.lisp

14:32 i think i'd know the all the key-side symbols of the let, but not the value-side

14:32 justin_smith: I guess you could implement your own ad-hoc binding / resolution mechanism that does not use clojure eval

14:32 but it won't be proper local bindings either

14:33 csd_: this sounds outside my depths

14:33 justin_smith: oh, wait, if you know all the possible left-hand-sides this might be a case for with-local-vars

14:33 (doc with-local-vars)

14:33 clojurebot: "([name-vals-vec & body]); varbinding=> symbol init-expr Executes the exprs in a context in which the symbols are bound to vars with per-thread bindings to the init-exprs. The symbols refer to the var objects themselves, and must be accessed with var-get and var-set"

14:34 justin_smith: oh no, never mind

14:34 csd_: couldn't you convert that code to use a hash map and do explicit hash-map lookups to get the values?

14:36 csd_: i guess, although not sure how off hand

14:39 seems doable i suppose

15:12 amalloy: justin_smith: that's certainly not in useful. the closest thing to that i've done is write an answer on stackoverflow saying it's a bad idea

15:34 justin_smith: amalloy: on the surface level, I was factually wrong, on a more real level, I was correct that you had the right answer

15:34 amalloy: haha

15:34 very deep indeed

15:36 gfredericks: ~this is not a case for with-local-vars

15:36 clojurebot: Ack. Ack.

15:37 mungojelly: i don't really understand how these leiningen dependencies work i guess i need to read something about it, does it actually look at these urls to find the dependency or what is it looking in

15:37 how do i say a dependency on flatland/useful, like how do i know which version to say? :/

15:37 justin_smith: mungojelly: it searches your repositories

15:37 it starts with like maven central and clojars and maybe sonatype

15:38 mungojelly: oh ok it just seemed to magically know everything in the universe

15:38 justin_smith: haha

15:39 mungojelly: so is what i should do search on maven/clojars myself to find what versions i might want to tell it to depend on?

15:39 justin_smith: there's a default config that sets up the first repositories for you (but it is possible to replace it)

15:39 mungojelly: if you are not sure what version to get, sure. Sometimes I just look at the version tag / readme on github too.

15:40 mungojelly: there is also "lein search" which takes a long time to build the index though...

15:40 mungojelly: another interesting thing to check is http://crossclj.info which shows who is using what version of what library (in open source at least)

15:41 mungojelly: that's what i had been doing was entering the lein dependencies line it tells you to on github readmes but when things didn't tell me what to say i discovered i didn't know how that magic worked

15:43 someone linked to crossclj.info and it was too interesting for me to have the bandwidth to understand it, that's so much information

16:03 noncom: what's the best way to get the 2 dates representing the beginning and the end of the current month?

16:05 gfredericks: with clj-time?

16:06 justin_smith: gfredericks: is there a reason not to use Calendar?

16:07 gfredericks: I don't know, I was just trying to figure out the background for the question

16:08 justin_smith: I mean I've only used the API a little, but I never see people recommending using it, and wonder why

16:10 Intey: jsutin_smith: Calendar is native and correspond to clojure.instant ?

16:11 justin_smith: Intey: the instant reader in clojure is java.util.Date, but things like "date for first and last days of a month" would be done with the Calendar api and not the Date api

16:11 and maybe that unintuitive split is part of why nobody likes those apis...

16:12 Intey: In clj-time, i see 3 funcs, for noncom question: now, start, end. I don't know, but with those can be done.

16:13 noncom: ah, sorry, yes, in clj-time (cljs-time to be precise, but there is not much difference)

16:13 in the emantime, i found the way - i take (now), make a new date with year and month - that's the start and then make the end with +1 month

16:14 justin_smith: ,java.util.Calendar/UNDECEMBER ; 13th month of the year

16:14 clojurebot: #error {\n :cause "Unable to find static field: UNDECEMBER in class java.util.Calendar"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to find static field: UNDECEMBER in class java.util.Calendar, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message ...

16:14 noncom: ahhaha :D

16:14 13th monh

16:14 java can do this

16:14 justin_smith: ,java.util.Calendar/UNDECIMBER ; 13th month of the year

16:14 clojurebot: 12

16:14 justin_smith: haha, spelled it wrong the first time

16:14 noncom: is it an easter egg?

16:14 justin_smith: no, it's a documented part of the api

16:15 noncom: :/

16:15 :D

16:15 justin_smith: ,java.util.Calendar/WEDNESDAY

16:15 clojurebot: 4

16:16 justin_smith: ,java.util.Calendar/HOUR

16:16 clojurebot: 10

16:16 justin_smith: OK, this is a weird API

16:16 noncom: really :)

16:18 justin_smith: noncom: OK, undecimber is there because localized calendars are supported, and the Hebrew calendar, among others, there is sometimes a 13th month

16:18 noncom: this makes sence

16:19 but the name is funny nevertheless :)

16:19 justin_smith: it is a weird name

16:19 https://en.wikipedia.org/wiki/Undecimber

16:19 but it's real

16:20 noncom: huh, so all this is serious..

16:20 good to know

16:21 justin_smith: it's justin_smith 's rule of locales: anything localized will support things you find hilarious

16:22 (see also unicode snowman)

17:46 rary: Okay, I've switched to idea+cursive. It is really nice, I like it!

17:46 justin_smith: thank you for your advice again.

17:47 rainbow parentheses are beautiful :)

17:51 I am reading the Joy of Clojure now and authors write that if there would be a strong request to publisher, they will write a separate book about Clojure compiler implementation details

17:52 Lets create a strong request, ha? :-) it will be definitely interesting reading.

18:47 obliviasimplex: hey, I seem to be having some trouble with Cider. M-x cider-jack-in gives me these errors and stack traces: https://bpaste.net/show/fcd37a267ba5

18:48 Anyone know what the trouble is here, and how to fix it?

18:57 domokato: is it possible to get the value of a var of a symbol passed into a macro? or does the value not exist yet?

19:00 this is in a namespace file to be compiled, not the repl

19:01 amalloy: domokato: you can do it, but it's more often a bad idea than a good one. what is the big picture?

19:05 domokato: maybe i'm trying to do something dumb, but I'm trying to write a macro that allows me to inherit fields between records. I don't intend to ever use the base record, so I've just defined it as a vector of symbols of fields and I'm trying to pass it into the macro, which would expand it into a call to defrecord

19:08 along with the additional fields

19:09 amalloy: inheriting fields between multiple records sounds like a bad way to get composite data. if you have N records which all need fields x,y,z, why not (defrecord Q [x y z]) and then just give those N records a single q field?

19:13 domokato: in my model, it just seems like a is-a relationship rather than a has-a

19:13 justin_smith: domokato: clojure really doesn't do is-a (at least not concretely)

19:13 domokato: alright, i'll just go with the has-a then :)

19:13 thx

19:14 justin_smith: it does is-a for interfaces (is-a thing that you can run this function on) but not data (no is-a thing that has these fields)

19:15 domokato: yeah, that's why i was trying to implement it, but seems to not be worth the effort

19:16 i guess it's a little bit annoying to do it the has-a way because I have to instantiate the inner record manually in every case

19:16 maybe it's okay...

19:17 justin_smith: domokato: using prismatic/schema you can do "has these fields" as an insertion, and using clojure.core/merge you can "inherit" it

19:17 s/insertion/assertion

19:21 domokato: i can't find any insertion

19:24 justin_smith: domokato: see my correction - I meant assertion

19:25 also, off topic but wow, I found a URL that can't be resolved, but if you paste it into chrome's browser bar it crashes the entire browser (not just one tab, the whole browser)

19:27 domokato: hm...don't see assertion either :(

19:27 https://github.com/Prismatic/schema ?

19:27 or do you just mean...do an assert?

19:27 justin_smith: yes, you can use s/defn for example to make a defn which asserts certain keys are present in some arg

19:28 domokato: sorry, I am talking about s/validate (and the other things which use that)

19:29 domokato: sorry, i'm unfamiliar with this library

19:31 yeah, i'm trying to use merge but i still have the issue of getting the value of a var from its symbol

19:32 justin_smith: in a macro?

19:32 domokato: yeah

19:32 justin_smith: in a macro, getting the symbol means too many layers of quoting

19:32 so if you are using ` you need ~ somewhere

19:33 domokato: i have a var like (def body-state ['sprite 'sprite-info]) and i'm passing body-state into the macro call, but when i unquote the the value passed in i get a var, i believe, not the actual vector

19:36 justin_smith: ,(= ['sprite 'sprite-info] '[sprite sprite-info]) ; btw

19:36 clojurebot: true

19:36 domokato: ah

19:37 yeah, i noticed that

19:37 anyway, here's my macro right now: (defmacro pseudo-extend [name parent fields & remainder] `(defrecord ~name ~(apply merge parent fields) ~@remainder))

19:37 it works when passing in a vector literal, but not when passing in a vector var

19:38 justin_smith: ,(apply merge [:a :b :c] [:d :e :f])

19:38 clojurebot: [:a :b :c :d :e ...]

19:38 justin_smith: weird

19:38 ,(into [:a :b :c] [:d :e :f]) ; this is the normal way to do that

19:38 clojurebot: [:a :b :c :d :e ...]

19:40 domokato: oh okay nice

19:41 justin_smith: ,(let [name 'n parent '[a b c] fields '[d e f]] `(defrecord ~name ~(into parent fields)))

19:41 clojurebot: (clojure.core/defrecord n [a b c d e ...])

19:41 justin_smith: that looks legit (if your args are of the types you think...)

19:42 but what I meant by using merge was not defining a record that has the merged field vectors, but using a map (or record) and using merge to get the default field key / values for things that you don't explicitly override in the hash-map

19:43 since defrecord is already using a hash-map like thing instead of an object, why not use hash-map merge to get default key / value pairs

19:44 domokato: i think your implementation that worked above isn't quite analogous to using defmacro

19:45 i just got it to work using: (defmacro pseudo-extend [name parent fields & remainder] `(defrecord ~name ~(into @(resolve parent) fields) ~@remainder))

19:47 justin_smith: domokato: that's a fair bit of work to do something records allowed already (you can merge an instance of a defrecord class with a normal hash-map)

19:49 domokato: right but i'm trying to inherit fields from another record. Not their values, just their declarations. I will use merge with normal hash-maps later to instantiate those fields

19:50 justin_smith: what good does inheriting declared fields do when defrecord allows associating any field you want to a record instance?

19:50 ,(defrecord Foo [bar baz])

19:50 clojurebot: sandbox.Foo

19:50 justin_smith: ,(assoc (->Foo 1 2) :quux 42)

19:50 clojurebot: #sandbox.Foo{:bar 1, :baz 2, :quux 42}

19:50 rhg135: performance if there's many instances with the extended fields

19:51 domokato: yeah, performance

19:51 rhg135: you did profile this right?

19:51 domokato: yeah

19:51 it's slowing down my draw loop considerably

19:51 keyword lookups in hash maps

19:52 that's why i'm changing everything over to use records instead of maps

19:53 rhg135: something about this feels wrong, but I can't think of anything better

19:53 domokato: tell me about it

19:53 :)

19:53 justin_smith: domokato: why not make those fields the render loop needs be the record fields, and associate other records into it (not just their fields)

19:57 domokato: if I have a bunch of records with BodyState as a field, every time I instantiate one of those I need to do (map->Thingy {:body-state (map->BodyState ...) ...}) rather than just (map->Thingy ...)

20:00 in my case i generally do (map->Thingy nil) first then merge in the data later

20:00 justin_smith: domokato: when you do that, you don't get any of the perf benefit

20:01 ,(type (assoc (->Foo nil) :a 1 :b 2))

20:01 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" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: ->Foo in this...

20:01 justin_smith: ,(defrecord Foo [bar baz])

20:01 clojurebot: sandbox.Foo

20:01 justin_smith: ,(type (assoc (->Foo nil) :bar 1 :baz 2))

20:01 clojurebot: #error {\n :cause "Wrong number of args (1) passed to: sandbox/eval49/->Foo--64"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (1) passed to: sandbox/eval49/->Foo--64"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.AFn invoke "AFn.java" 32]\n [sandbox$eval91 invokeStatic "NO_SOURCE_...

20:01 justin_smith: oops

20:01 ,(type (assoc (map->Foo nil) :bar 1 :baz 2))

20:01 clojurebot: sandbox.Foo

20:01 justin_smith: oh, wait...

20:02 never mind, that only happens with dissoc

20:02 domokato: what does?

20:02 amalloy: well, it's still true you don't get much benefit if you're building records out of maps

20:02 justin_smith: ,(type (assoc (dissoc (map->Foo nil) :bar) :bar 1 :baz 2))

20:02 clojurebot: clojure.lang.PersistentArrayMap

20:02 justin_smith: the dissoc makes it not be a record instance, even if you attach the field later

20:03 domokato: ah, good to know

20:03 amalloy: if you are using records for performance, which is rare but not unheard of, you should probably call the constructor yourself, or at least the ->Foo constructor rather than map->Foo

20:03 domokato: it's the access i'm worried about, not so much the instantation

20:06 the field accesses happen in the draw loop every frame. the instantiation happens at the beginning of the game or just once every few frames

20:07 justin_smith: domokato: another option to consider is ECS where instead of iterating over objects and accessing fields, you can directly iterate the fields

20:11 domokato: or a protocol, where you provide the data / functionality via protocol functions rather than via direct field access

20:12 phaseNi: is (swap! blah (fn [x] nil)) the same as (reset! blah nil)?

20:12 rhg135: how is polymorphic method dispatch faster than field access?

20:12 in theory, yes, phaseNi

20:13 semantically, rather

20:13 justin_smith: phaseNi: not quite, swap! retries if there is concurrent modification, reset! does not

20:14 rhg135: now I wonder, maybe it's not faster than hash lookup, that's a good point

20:15 phaseNi: justin_smith: Out of curiosity, in this case, would it really matter?

20:15 domokato: justin_smith: thanks, and everyone else too :)

20:15 phaseNi: justin_smith: it just changes the timing a bit

20:15 rhg135: you can't now if it'll matter

20:15 justin_smith: phaseNi: not just timing, also the resulting value if there is concurrent modification

20:15 rhg135: not without the rest of the things touching it

20:16 mungojelly: cache what the painter needs and make updates to that only as there are changes in the model

20:16 phaseNi: justin_smith: i mean if the other thread happened slightly slower the value would still be changed

20:16 s/slower/later/

20:16 justin_smith: phaseNi: if the other thread did a reset! this is not true

20:17 rhg135: ~mutable state

20:17 clojurebot: mutable state is bad

20:17 phaseNi: heh

20:17 rhg135: it becomes dependant on the order of thiings

20:18 amalloy: justin_smith: i don't think you can ever tell (reset! a x) and (swap! a (constantly x)) apart, if no concurrent swap! function has side effects (other than the swap of course)

20:18 phaseNi: yes, what amalloy said is what i was thinking

20:20 justin_smith: hmm

20:27 rhg135: in my criterium test, polymorphic method access is much faster than defrecord field access, trying the tests again with type hints (tried unhinted first) and will paste the results

20:28 and hinted field access is pretty much identical to unhinted polymorphic method via defprotocol

20:29 rhg135: that is strange

20:29 way to go jit

20:30 amalloy: hinting doesn't matter to protocols at all

20:30 justin_smith: and when hinted, the protocol method call is unchanged (uploading to refpheap now)

20:30 amalloy: haha, so I discovered

20:31 https://www.refheap.com/109749

20:32 rhg135: domokato: so, turns out where JIT applies, a protocol method is as good as field access on a record, and you can do composition of protocols much more cleanly than composition / "inheritance" of base record fields

20:33 rhg135: that is very strange

20:33 I love the jvm

20:33 amalloy: justin_smith: fwiw the jit isn't the only thing optimizing those protocol method calls. if you had the same line of code dispatching to two different implementations in alternation, the inline cache would never hit

20:34 justin_smith: hmm, OK

20:34 amalloy: oh, and it makes a big difference whether the record implements the protocol inilne or was extended to it

20:34 justin_smith: oh yes, that is definitely true, I knew that one

20:35 rhg135: is the cache that big a factor?

20:37 amalloy: probably. avoids map lookup and hierarchy dispatch i would think

20:45 rhg135: it seems not to for me

20:49 justin_smith: rhg135: seems not to?

20:50 rhg135: https://www.refheap.com/109750

20:51 not a huge difference per 100 iterations where one is a cycle of two types and the other is of one type

20:55 domokato: my records store changing state and are kept in atoms, so i don't think protocols would work here?

Logging service provided by n01se.net