2015-09-19
| 04:34 | Empperi | 01:54 [rajaniemi] DCC SEND from crowgoose [37.187.79.138 port 43352]: virus.exe [13kB bytes] requested in channel #clojure |
| 04:34 | Empperi | 01:59 [rajaniemi] DCC aborted receiving file virus.exe from crowgoose |
| 04:34 | Empperi | okey dokey |
| 04:35 | Empperi | got to say one has to be pretty desparate to try that on such a channel |
| 04:55 | ahoegh_ | Empperi: crowgoose tried the same one me. |
| 05: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. |
| 05:31 | mavbozo | m1dnight_, what's this config.edn file contains? can't you put the config.edn file somewhere outside the uberjar? |
| 05: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? |
| 05:34 | m1dnight_ | 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. |
| 05:36 | mavbozo | you can run your uberjar with java -jar -Dconfig.location="/etc/my-app-config.edn" |
| 05:36 | mavbozo | and in your code, you can get the config.location with (System/getProperty "config.location") |
| 05:37 | TEttinger | m1dnight_: if it's a resource it's inside the jar. you can modify the jar to replace the resource I think |
| 05:37 | m1dnight_ | oh that might be something Im interested in, mavbozo |
| 05:37 | m1dnight_ | 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 |
| 05:37 | m1dnight_ | It doesnt have to be inside the jar. |
| 05:37 | m1dnight_ | I will have a look at it right away! |
| 05:37 | TEttinger | or you can change it from a resource to just (edn/read-string (slurp "servers.edn")) |
| 05:38 | TEttinger | hm |
| 05:38 | TEttinger | 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? |
| 05:38 | TEttinger | not sure |
| 05:39 | m1dnight_ | To the experimentation-mobile! |
| 06:12 | justin_smith | you need io/resource to get the resource inside the jar |
| 06:12 | justin_smith | then it finds the first one in the classpath |
| 06: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))) |
| 06:25 | m1dnight_ | where config-path is the System/getProperty and file is the filename. |
| 06:26 | justin_smith | if you don't need to read anything inside the jar, that would work |
| 06: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. |
| 07:03 | triss | there's not a function like swap! that returns the value before the function provided is applied is there? |
| 07:11 | m1dnight_ | Afaik there is not, no. |
| 07:12 | Bronsa | triss: no, http://dev.clojure.org/jira/browse/CLJ-1454 |
| 07: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. |
| 07:14 | triss | okeydoke. keep a ref to previous value isn't too much hassle for now.... surprised how many times its been implemented tho |
| 07:15 | m1dnight_ | Are refs not an option for the value as well? |
| 07:15 | m1dnight_ | You could use (dosync (ensure x) (let [old-value @x] (ref-set! x new-value))) |
| 07:15 | m1dnight_ | or somethiong |
| 07:16 | m1dnight_ | You could use (dosync (let [old-value (ensure x)] (ref-set! x new-value))) even! |
| 07:17 | Bronsa | m1dnight_: using the STM for simple CAS semantics seems an overkill |
| 07:17 | m1dnight_ | Well you can then store {:curr :old} in the atom and update the old in swap! function and read that out afterwards |
| 07:17 | Bronsa | m1dnight_: wrt your question, just use a tuple as acc value to your reducing function and keep track of the ids |
| 07:18 | Bronsa | and incur a map lookup everytime you need to access the value? |
| 07: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 |
| 07:19 | m1dnight_ | a map lookup is about O(1). |
| 07:19 | m1dnight_ | *about* |
| 07: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 |
| 07: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. |
| 07:21 | m1dnight_ | How would you do it? |
| 07:22 | Bronsa | m1dnight_: sure but there are better workarounds than the one you proposed, see http://dev.clojure.org/jira/browse/CLJ-1454 |
| 07:22 | Bronsa | https://github.com/flatland/useful/blob/develop/src/flatland/useful/state.clj#L43 this one solution I like the most |
| 07:22 | m1dnight_ | oh I see. yes the compare and swap one is much better idd |
| 07:23 | m1dnight_ | Allright Bronsa, I stand corrected! :) |
| 07:23 | triss | cheers Bronsa |
| 07:23 | triss | and m1dnight_ ! |
| 08: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) ? |
| 08:52 | triss | is it possible to make fireplace put evaluations output in to a vim buffer so I can refer back to it? |
| 08:52 | triss | i'd love to have a pane open with the output of the last few commands in. |
| 09:02 | triss | 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 | tcrayford____ | there's no `break` keyword or anything else like that in clojure though |
| 12:23 | xtrntr | alright |
| 12:23 | xtrntr | thanks |
| 12:24 | tcrayford____ | generally you'd just use `filter` to remove the elems you don't want to iterate over though |
| 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 | xtrntr | 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 | xtrntr | :) |
| 12:37 | justin_smith | xtrntr: if your processing of a sequence needs to stop arbitrarily, use reduce and reduced |
| 12:37 | justin_smith | use loop if you are doing something more complex than just walking along a sequence |
| 12:38 | justin_smith | ,(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 | justin_smith | *indefinite |
| 12:39 | justin_smith | ,(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: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 | justin_smith | csd_: I either lost it or misremembered |
| 14:27 | justin_smith | 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 | justin_smith | that requires eval |
| 14:29 | justin_smith | 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 | csd_ | 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 | justin_smith | 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 | justin_smith | (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 | justin_smith | 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 | csd_ | 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 | amalloy | 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 | mungojelly | 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 | justin_smith | 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 | justin_smith | 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 | justin_smith | mungojelly: there is also "lein search" which takes a long time to build the index though... |
| 15:40 | justin_smith | 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 | mungojelly | 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 | justin_smith | 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 | noncom | 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 | noncom | 13th monh |
| 16:14 | noncom | 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 | noncom | :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 | noncom | but the name is funny nevertheless :) |
| 16:19 | justin_smith | it is a weird name |
| 16:19 | justin_smith | https://en.wikipedia.org/wiki/Undecimber |
| 16:19 | justin_smith | but it's real |
| 16:20 | noncom | huh, so all this is serious.. |
| 16:20 | noncom | 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 | justin_smith | (see also unicode snowman) |
| 17:46 | rary | Okay, I've switched to idea+cursive. It is really nice, I like it! |
| 17:46 | rary | justin_smith: thank you for your advice again. |
| 17:47 | rary | rainbow parentheses are beautiful :) |
| 17:51 | rary | 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 | rary | 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 | obliviasimplex | 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 | domokato | 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 | domokato | 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 | domokato | 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 | domokato | 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 | domokato | 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 | justin_smith | 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 | justin_smith | 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 | domokato | https://github.com/Prismatic/schema ? |
| 19:27 | domokato | 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 | justin_smith | 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 | domokato | 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 | justin_smith | 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 | domokato | yeah, i noticed that |
| 19:37 | domokato | anyway, here's my macro right now: (defmacro pseudo-extend [name parent fields & remainder] `(defrecord ~name ~(apply merge parent fields) ~@remainder)) |
| 19:37 | domokato | 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 | justin_smith | ,(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 | justin_smith | 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 | justin_smith | 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 | domokato | 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 | justin_smith | ,(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 | domokato | it's slowing down my draw loop considerably |
| 19:51 | domokato | keyword lookups in hash maps |
| 19:52 | domokato | 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 | domokato | :) |
| 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 | domokato | 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 | justin_smith | ,(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 | justin_smith | ,(type (assoc (map->Foo nil) :bar 1 :baz 2)) |
| 20:01 | clojurebot | sandbox.Foo |
| 20:01 | justin_smith | oh, wait... |
| 20:02 | justin_smith | 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 | domokato | 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 | justin_smith | 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 | rhg135 | in theory, yes, phaseNi |
| 20:13 | rhg135 | semantically, rather |
| 20:13 | justin_smith | phaseNi: not quite, swap! retries if there is concurrent modification, reset! does not |
| 20:14 | justin_smith | 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 | phaseNi | 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 | justin_smith | 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 | justin_smith | and hinted field access is pretty much identical to unhinted polymorphic method via defprotocol |
| 20:29 | rhg135 | that is strange |
| 20:29 | rhg135 | 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 | justin_smith | amalloy: haha, so I discovered |
| 20:31 | justin_smith | https://www.refheap.com/109749 |
| 20:32 | justin_smith | 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 | rhg135 | 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 | rhg135 | 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? |