#clojure log - May 31 2015

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

0:00 dumptruckman: but that would only do one of the players right?

0:00 (that would work for now)

0:01 definitely a lot more readable that way

0:01 justin_smith: dumptruckman: what I am saying is that if (-> entities :players first :segments) works, then (mapcat :segments (:players entities)) and (apply concat (for [player (:players entities)] (:segments player))) would too

0:01 dumptruckman: ah

0:02 NPE

0:02 :D

0:02 justin_smith: I still say the mapcat version is clearest (it does the same as the one using for)

0:02 dumptruckman: that's my first NPE in clojure

0:02 justin_smith: dumptruckman: what gave you an npe?

0:02 ,(-> nil first :key)

0:02 clojurebot: nil

0:03 dumptruckman: maybe one too many sets of parens

0:03 yep

0:03 justin_smith: ,(-> nil :players first :segments)

0:03 clojurebot: nil

0:03 dumptruckman: ,((-> nil :players first :segments))

0:03 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.NullPointerException\n :message nil\n :at [sandbox$eval73 invoke "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval73 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.Compiler eval "Compiler.java" 6792]\n [clojure.lang.Compiler eval "Compiler.java" 6755]\n [clojure.core$eval invoke "core.clj" 3079]\n [clojure.core$eval51$fn__52$fn__62 invoke "NO_SOUR...

0:03 justin_smith: yup, that would do it

0:05 dumptruckman: huh

0:05 (-> entities :players first :segments) produces nil

0:05 justin_smith: so your data doesn't have the shape you expect

0:05 I would bisect it

0:06 dumptruckman: right

0:06 bisect?

0:06 justin_smith: (-> entities :players)

0:06 dumptruckman: seeing if entities even has anything

0:06 justin_smith: move left if you don't see what you expect, move right if you do

0:06 right

0:06 dumptruckman: okay, entities has what is expected

0:06 ooh

0:07 it's not a map...

0:07 justin_smith: dumptruckman: the idea being if you have -> and the end isn't what you expect, you can split it in the middle, then remove or add until you see the anomoly

0:07 dumptruckman: it's a vector with single element which is my map

0:07 this library must be wrapping that

0:07 justin_smith: yeah, that would explain your error

0:07 I tend to jump to the (-> foo :bar :baz ...) form in the repl, because it makes finding out the real shape of the data very easy

0:08 dumptruckman: i am seeing that

0:08 (i'm very new to clojure)

0:08 been wanting to play with it for quite some time... finally jumping into a project

0:08 only really done koans before

0:09 justin_smith: cool

0:09 how are you finding it so far?

0:09 dumptruckman: hmm

0:09 (-> entities first :players first :segments)

0:09 wouldn't that get the first element of entities?

0:09 justin_smith: well it would give you the :segments from the first of :players if it was a nested thing

0:10 dumptruckman: i meant

0:10 (-> entities first)

0:10 is the same as (first entities)

0:10 right?

0:10 justin_smith: right

0:10 dumptruckman: i am enjoying it

0:10 except

0:10 for a lack of refactoring

0:11 i love how elegant many of my solutions end up being

0:11 compared to what they'd have looked like in java

0:12 woah

0:12 the first thing in entities is not what i expected O.o

0:13 somehow

0:13 the first thing in entites is EXACTLY the thing i'm looking for

0:13 justin_smith: dumptruckman: it might help you to look up how component entity systems work (I assume this is what you are using here)

0:14 dumptruckman: nah

0:14 this is play-clj

0:14 the weirder thing is

0:14 justin_smith: I think play-clj is a CES

0:14 dumptruckman: it's not

0:15 it uses a kind of odd "entity system"

0:15 in that

0:15 all the main functions pass around this entity array

0:15 but i'm basically trying to force my entire game state into that array

0:15 justin_smith: that's the functional programming version of CES isn't it/

0:15 dumptruckman: no

0:15 i'm familiar with CES

0:15 and this isn't that

0:15 justin_smith: OK

0:16 dumptruckman: there's another lib called Ripple that merges play-clj and brute (an ECS)

0:16 play-clj just has a kind of restrictive way of doing things

0:17 so you kind of have to do some weird workarounds like i'm doing.... i'm just trying to hammer down that workaround

0:19 justin_smith: dumptruckman: so what specifically does play-clj do that disqualifies it from being an ECS?

0:20 dumptruckman: http://pastie.org/10215828

0:20 well

0:20 it doesn't have components or systems

0:20 i guess it kind of has components

0:20 but really doesn't have systems

0:20 actually no

0:20 doesn't have components

0:21 so yeah

0:21 justin_smith: wait, why is it that when you print the first of the entities, it shows the :segments from the first of the :players in entities

0:21 dumptruckman: that's what i want to know

0:21 it doesn't make sense

0:22 it's like it's skipping the top layer

0:23 ok weird

0:23 something changes between those outputs

0:23 but i don't know what..

0:24 justin_smith: dumptruckman: you said array before, if you actually meant that, arrays are mutable.

0:24 if you meant vector then yeah, something else is going on

0:24 dumptruckman: vector, sorry

0:25 well, i got those outputs from different runs

0:25 justin_smith: your results would likely make much more sense in a single run

0:25 dumptruckman: using both printlns in the same run explains why (first entities) shows what it does

0:25 well... it doesn't explain it entirely because

0:26 oh wait

0:26 the (println entities) i pasted came from another part of the code.... so play-clj appears to be extracting what i'm trying to get at

0:27 i don't know how or why it'd do that

0:28 or not

0:29 ohh...

0:29 i was returning the modified entities vector that i was trying to get in the render function

0:30 and i think play-clj was passing that modified one back to the render function

0:30 so the very first run would've looked different

0:30 justin_smith: right, the general pattern in functional code is that instead of mutating something, you return the updated version

0:31 dumptruckman: right but my render function shouldn't be be returning a modified version

0:33 okay so

0:33 (-> entities first :players first :segments) gives me what i'm looking for

0:33 justin_smith: so in that case your initial for/concat would work

0:33 as would my proposed mapcat alternative

0:34 dumptruckman: or

0:34 (mapcat :segments (:players (first entities)))

0:34 that would be what i want

0:34 justin_smith: ahh there is that difference yeah

0:34 forgot entities was a vector with the map inside

0:34 dumptruckman: the only problem is it's not rendering my shapes ;)

0:35 i think it's probably because it's not a vector of shapes

0:35 and is instead a vector of maps

0:35 so i need to extract the shape from each of those maps

0:35 justin_smith: ahh - for has a feature for this

0:36 dumptruckman: wouldn't it just be

0:36 (mapcat :shape (mapcat :segments (:players (first entities))))

0:37 justin_smith: ,(for [p (:e {:e [{:s [1 2]} {:s [3 4]} s (:s p)] s)

0:37 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: )>

0:37 justin_smith: ,(for [p (:e {:e [{:s [1 2]} {:s [3 4]}]} s (:s p)] s)

0:37 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: ]>

0:38 justin_smith: ,(for [p (:e {:e [{:s [1 2]} {:s [3 4]}]}) s (:s p)] s)

0:38 clojurebot: (1 2 3 4)

0:38 justin_smith: no need for concats!

0:38 dumptruckman: hmm

0:38 justin_smith: it's actually readable if you put each binding in the for on it's own line, as you would in a let

0:40 dumptruckman: i can't parse that

0:40 so

0:40 justin_smith: dumptruckman: the idea is that for accepts nested bindings

0:40 I'll give the easer to read version

0:40 dumptruckman: the value for :shape in my :segment is #play_clj.entities.ShapeEntity{:object #<ShapeRenderer com.badlogic.gdx.graphics.glutils.ShapeRenderer@7471a313>, :draw! #<core$create_segment$fn__212 snake_clj.core$create_segment$fn__212@173fcf2e>, :type #<ShapeType Filled>}

0:41 justin_smith: ,(def ent {:e [{:s [1 2]} {:s [3 4]})

0:41 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: )>

0:41 dumptruckman: but when i do

0:41 (mapcat :shape (mapcat :segments (:players (first entities))))

0:41 justin_smith: ,(def ent {:e [{:s [1 2]} {:s [3 4]}]})

0:41 clojurebot: #'sandbox/ent

0:41 dumptruckman: it merges everything inside that map

0:42 and doesn't include the map

0:42 justin_smith: ,(for [p (:e ent) s (:s p)] s)

0:42 clojurebot: (1 2 3 4)

0:43 dumptruckman: so

0:43 the binding in for

0:44 allows referencing previous bindings

0:44 justin_smith: right

0:44 and each one is recursively expanded

0:44 in a way that can effectively be a concat at each level

0:44 dumptruckman: and the return value of the for loop

0:44 is a concat

0:44 justin_smith: not a loop, comprehension

0:44 dumptruckman: ?

0:44 justin_smith: but effectively, yes

0:45 but it can do more than that, this is just a subset of what it can do

0:48 dumptruckman: ha

0:48 yes, i think that might have worked

0:49 (let [snakes (for [player (:players (first entities)) segment (:segments player)] (:shape segment))] (render! screen snakes))

0:49 it works

0:49 :D

0:50 i don't really understand why mapcat made it all screwy

0:54 justin_smith: yeah, if that for comprehension works, the nested mapcat should too, but I think the for is better (as long as it isn't a one liner)

0:58 dumptruckman: well

0:58 the different was

0:58 with for i get (#Thing{shape-stuff} #Thing{shape-stuff})

0:58 with the map cat i got

0:59 (shape-stuff shape-stuff)

1:17 dealing with collections in clojure takes some getting use to

1:31 how can i check a map's values for a particular value and return the key associated with that value?

1:32 basically i want to use a map backwards >.>

1:35 TEttinger: dumptruckman, this actually is surprisingly common

1:35 but map values aren't guaranteed to be unique

1:35 dumptruckman: of course

1:36 i know they will be in this case

1:37 TEttinger: ,(let [m {:a 1 :b 3 :c 2}] (into {} (interleave (vals m) (keys m))))

1:37 clojurebot: #error {\n :cause "Don't know how to create ISeq from: java.lang.Long"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "Don't know how to create ISeq from: java.lang.Long"\n :at [clojure.lang.RT seqFrom "RT.java" 528]}]\n :trace\n [[clojure.lang.RT seqFrom "RT.java" 528]\n [clojure.lang.RT seq "RT.java" 509]\n [clojure.lang.ATransientMap conj "ATransientMap.java" 42]\n [cloju...

1:37 TEttinger: eh?

1:37 ,(let [m {:a 1 :b 3 :c 2}] (apply hash-map (interleave (vals m) (keys m))))

1:37 clojurebot: {1 :a, 3 :b, 2 :c}

1:37 TEttinger: that gets a reverse map

1:38 there's a lot of ways to do this

1:38 gws: ,(clojure.set/map-invert {:a 1 :b 2 :c 3})

1:38 clojurebot: #error {\n :cause "clojure.set"\n :via\n [{:type java.lang.ClassNotFoundException\n :message "clojure.set"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run "URLClassLoader.java" 366]\n [java.net.URLClassLoader$1 run "URLClassLoader.java" 355]\n [java.security.AccessController doPrivileged "AccessController.java" -2]\n [java.net.URL...

1:38 TEttinger: ,(let [m {:a 1 :b 3 :c 2} target 3] (filter #(= (val %) target) m))

1:38 clojurebot: ([:b 3])

1:39 TEttinger: which also works for duplicates

1:39 ,(let [m {:a 3 :b 3 :c 2} target 3] (filter #(= (val %) target) m))

1:39 clojurebot: ([:a 3] [:b 3])

1:39 TEttinger: ,(require 'clojure.set)

1:39 clojurebot: nil

1:40 TEttinger: ,(clojure.set/map-invert {:a 1 :b 2 :c 3})

1:40 clojurebot: {1 :a, 2 :b, 3 :c}

1:40 TEttinger: nice, gws

1:40 (inc gws)

1:40 lazybot: ⇒ 7

1:40 TEttinger: ,(clojure.set/map-invert {:a 3 :b 2 :c 3})

1:40 clojurebot: {3 :c, 2 :b}

1:40 TEttinger: very nice

1:41 gws: yeah even though it has nothing to do with sets so it's a little counterintuitive haha

1:42 mercwithamouth: pee

1:42 peep* geeze

1:43 brainproxy: well hash-map literals do throw when encountering dup keys

1:43 though (hash-map ...) doesn't

1:44 so i guess in a certain sense a literal hash-map represents a set of keys

1:45 TEttinger: although ##(keys {:a 1 :b 2}) will be a vector, oddly, because sets aren't ordered

1:45 lazybot: ⇒ (:b :a)

1:45 TEttinger: well, seq

1:47 brainproxy: there's flatland/ordered :-)

1:47 gws: makes sense

1:47 brainproxy: but yeah, stock sets aren't ordered

1:52 TEttinger: brainproxy, yeah, I do pretty strongly feel like not having the ordering data in maps and sets by default, even as metadata, is kinda a flaw

1:52 it might be a property of HAMTs that prevents it though

1:53 brainproxy: TEttinger: ah interesting, hadn't considered that

1:53 TEttinger: metadata or HAMTs?

1:53 brainproxy: HAMTs

1:53 justin_smith: ,(clojure.set/invert (hash-map Double/NaN Double/NaN Double/NaN Double/NaN))

1:53 clojurebot: #error {\n :cause "clojure.set"\n :via\n [{:type java.lang.ClassNotFoundException\n :message "clojure.set"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run "URLClassLoader.java" 366]\n [java.net.URLClassLoader$1 run "URLClassLoader.java" 355]\n [java.security.AccessController doPrivileged "AccessController.java" -2]\n [java.net.URL...

1:53 TEttinger: yeah they aren't by default ordered, since the whole hash thing

1:53 justin_smith: hmm

1:53 TEttinger: oh justin_smith

1:54 justin_smith: ,(require 'clojure.set)

1:54 clojurebot: nil

1:54 justin_smith: ,(clojure.set/invert (hash-map Double/NaN Double/NaN Double/NaN Double/NaN))

1:54 clojurebot: #error {\n :cause "No such var: clojure.set/invert"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: No such var: clojure.set/invert, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6543]}\n {:type java.lang.RuntimeException\n :message "No such var: clojure.set/invert"\n :at [clojure.lang.Util runtimeExce...

1:54 TEttinger: ,(clojure.set/map-invert (hash-map Double/NaN Double/NaN Double/NaN Double/NaN))

1:54 clojurebot: {NaN NaN, NaN NaN}

1:54 TEttinger: haha

1:54 justin_smith: ahh

1:55 TEttinger: ,(get (clojure.set/map-invert (hash-map Double/NaN Double/NaN Double/NaN Double/NaN)) Double/NaN)

1:55 clojurebot: nil

1:55 TEttinger: heh

1:56 brainproxy: I've only encountered a few situations that actually depend on ordered sets, per se

1:58 TEttinger: the main thing I'm going to be doing is a bit odd, and it's partly why I'm making my own language instead of extending an existing one

1:58 brainproxy: do tell :-)

1:58 TEttinger: but it kinda depends on having consistent ways to go between sequences

1:59 the idea is to have, effectively, "first-class keysets" or in another way of looking at it, separating data from how it is accessed.

2:00 Chapel, an obscure language made by Cray recently, has this and calls it Domains

2:00 this means I can have one underlying seq type, like clojure seqs

2:01 but you can access that seq as a 1d array if you have a 1d array-like domain (enforcing a limit on the length, like an array, and optionally starting at a non-0 index)

2:02 you can access it as a hashmap, where the domain is a series of ordered unique keys, and it looks up the corresponding element by order

2:02 or a 2d array

2:02 (2 keys)

2:02 brainproxy: interesting

2:02 TEttinger: or weirder domains, like ones that have special behavior if a key is not found

2:03 (interpolating between nearby keys')

2:03 (interpolating between nearby keys' values, for instance)

2:03 brainproxy: sounds like it would conceptually apply some topology concepts to data structures, maybe?

2:03 TEttinger: it's a logical extension on the seq abstraction

2:03 yes

2:03 I know nothing about topology though

2:04 brainproxy: does it have anything to do with cobordisms?

2:04 TEttinger: kobolds?

2:04 brainproxy: http://en.wikipedia.org/wiki/Cobordism

2:05 search for a pdf paper titled "Physics, Topology, Logic and Computation: A Rosetta Stone"

2:07 TEttinger: that article makes no sense to me

2:07 I mean I could probably generate random word sequences that would make more sense to me

2:08 brainproxy: okay, nvm, was just curious, I'm not sure I really understand it either :-)

2:09 TEttinger: then again, wikipedia often is more complex than it needs to be

2:10 https://en.wikipedia.org/wiki/Low-discrepancy_sequence

2:10 this makes it sound outrageously complex

2:10 really it's just a deterministic sequence that has random-number-sequence-like properties

2:11 like this is a good one https://en.wikipedia.org/wiki/Low-discrepancy_sequence#/media/File:Halton_sequence_2D.svg

2:12 that looks close to random, right? if the points popped out one at a time, you wouldn't notice that they aren't near each other

2:12 brainproxy: right

2:12 TEttinger: but it's generated by a pretty simple thing involving decimals in a different base

2:13 https://en.wikipedia.org/wiki/Halton_sequence

2:13 or rather, fractions would also work

2:14 wasamasa: woah: http://devmag.org.za/2009/05/03/poisson-disk-sampling/

2:15 this also makes for nice results

2:15 found it in the citations of the low-discrepancy sequence article

2:15 TEttinger: so the 3,5 halton sequence is a 2d sequence, where the x axis is drawn from the sequence of (1/3, 2/3, 1/9, 4/9, 7/9, 2/9, 5/9...) and the y-axis is drawn from (1/5, 2/5, 3/5, 4/5, 1/25, 6/25, 11/25...)

2:16 and that's really it

2:16 it looks random but it totally isn't

2:17 it's interesting how most "classic" libraries on subrandom sequences don't touch poisson disk sampling, but they're used pretty heavily in some games, apparently

2:19 wasamasa: must be that it matches one mistake humans keep doing when asked to think up random numbers

2:19 assuming a minimum distance :P

2:20 and once that is introduced for all values, the result looks less disconcerting than an actually random distribution of points

2:21 TEttinger: yup

2:22 also, quasi-monte-carlo apparently has legitimate financial benefits https://en.wikipedia.org/wiki/Quasi-Monte_Carlo_method

2:23 https://en.wikipedia.org/wiki/Quasi-Monte_Carlo_methods_in_finance

2:31 one to three orders of magnitude over conventional monte carlo

3:55 oh geez... how do autogensyms work

3:55 if I have a macro that uses foo# , and it later uses foo# as a variable, they refer to the same thing, right?

3:55 but if I then later have another macro that uses foo#, it doesn't refer to the same gensym

3:57 so I'm guessing the gensym is "bound" (not sure if right term) to the scope in which it is created

3:57 but do macros even have scope?

3:57 is theirs the same as a function's scope?

5:15 tim__: I'm confused about :keywords that aren't in a map

5:15 I'm trying to pull access_code out of this

5:15 headers: {content-type: application/json, content-length: '289', connection: keep-alive, pragma: no-cache, expires: 'Sat, 01 Jan 2000 00:00:00 GMT', set-cookie: 'csrftoken=9c5bad8727db13908992e479d7f78c6b; expires=Sun, 29-May-2016 09:06:25 GMT; Max-Age=31449600; Path=/', date: 'Sun, 31 May 2015 09:06:25 GMT', vary: 'Cookie, Accept-Language, Accept-Encoding', cache-control: 'private, no-cache, no-store, must-revalidate'

5:16 sorry

5:16 body: access_token: xxxxx user: {username: tfdiddy, bio: '', website: '', profile_picture: 'https://igcdn-photos-e-a.akamaihd.net/hphotos-ak-xtp1/t51.2885-19/11055747_791331110950700_2073441790_a.jpg', full_name: Tim, id: '520163296'}

5:16 SagiCZ: whats the issue and what are you pasting?

5:17 tim__: Hi I'm trying to work with the instagram api via this code https://github.com/Rydgel/Clojure-Instagram-API

5:18 SagiCZ: and?

5:18 whats confusing about keywords?

5:18 tim__: sorry bear with me

5:18 SagiCZ: ,(:a {:a :value})

5:18 clojurebot: :value

5:19 SagiCZ: ,(:b {:a :value})

5:19 clojurebot: nil

5:19 tim__: we have this method (get-access-token *creds* "code-from-IG")

5:19 that returns

5:19 body: access_token: xxxxx user: {username: tfdiddy, bio: '', .......

5:19 body doesn't seem to be a map

5:19 SagiCZ: how can it return that?

5:19 whats the type of that return value?

5:19 ,(type {:a 0})

5:19 clojurebot: clojure.lang.PersistentArrayMap

5:20 SagiCZ: (type (get-access-token *creds* "code-from-IG"))

5:20 tim__: its calling an rest api

5:20 SagiCZ: can you do this?

5:20 tim__: so maybe that is just the body of the response!

5:20 SagiCZ: it could be a string

5:20 call the "type" function on it please

5:20 tim__: ok, trying now, standby :)

5:21 erle: How do I remove from a nested datastructure the objects whose (pr obj) representation doesn't comply to the EDN specification? Fx, {:a 1 :b (find-ns 'user)} → {:a 1}.

5:21 "comply with"

5:25 tim__: hmm I can't get type to work in this

5:25 (defn save-auth [{:keys [params]}] (let [code (:code params) access-token (get-access-token *creds* code)] {:status 200 :headers {"Content-Type" "text/plain"} :body (-> access-token :body )}))

5:25 but I'm pretty sure that all of :body is a string

5:25 SagiCZ: in that case you have to parse it

5:25 tim__: as I'm the object the I'm getting back is probably the http response from instagram

5:26 how do I convert this into a map so I can work with it ?

5:26 SagiCZ: do you use REPL?

5:27 anyways.. you can do this to read map from string

5:27 ,(read-string "{:a 0 :b 1}")

5:27 clojurebot: {:a 0, :b 1}

5:27 SagiCZ: ,(:a (read-string "{:a 0 :b 1}"))

5:27 clojurebot: 0

5:27 SagiCZ: but you should really find out what type is it..

5:28 tim__: Thanks

5:28 erle: Might be a good idea to use clojure.edn/read-string for such things.

5:28 SagiCZ: erle: whats that?

5:28 erle: Something that refuses to read evil things.

5:29 ,(doc read-string)

5:29 clojurebot: "([s] [opts s]); Reads one object from the string s. Optionally include reader options, as specified in read. Note that read-string can execute code (controlled by *read-eval*), and as such should be used only with trusted sources. For data structure interop use clojure.edn/read-string"

5:29 SagiCZ: so stupid

5:29 gosh thats dumb

5:29 why is in some random namespace

5:30 erle: I guess they had to put it somewhere… And since the only thing it reads is EDN, why not put it in clojure.edn?

5:31 SagiCZ: the namespace has just two functions

5:31 erle: ,(ns-publics (find-ns 'clojure.java.browse))

5:31 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.NullPointerException\n :message nil\n :at [java.util.concurrent.ConcurrentHashMap hash "ConcurrentHashMap.java" 333]}]\n :trace\n [[java.util.concurrent.ConcurrentHashMap hash "ConcurrentHashMap.java" 333]\n [java.util.concurrent.ConcurrentHashMap get "ConcurrentHashMap.java" 988]\n [clojure.lang.Namespace find "Namespace.java" 188]\n [clojur...

5:32 erle: Hmm:

5:33 Guess I should require it first. Anyway, that namespace has only one function, for example.

5:38 tim__: @SagiCZ me again, so read-string didn't work, so I tried type am getting class clojure.lang.PersistentArrayMap

5:38 SagiCZ: so its a map already

5:38 no reason for read-string

5:38 tim__: ,(str (type (:body access-token)))

5:38 clojurebot: #error {\n :cause "Unable to resolve symbol: access-token in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: access-token in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6543]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol:...

5:39 SagiCZ: now explain what exactly doesnt work?

5:39 tim__: gosh I'm sorry I haven't used IRC before

5:39 ok this (:access_code (:body access-token))

5:40 doesn't give me the value of :access_code

5:41 SagiCZ: evaluate this please

5:41 (keys (:body access-token))

5:42 tim__: [access_token, user]

5:42 :)

5:42 SagiCZ: well as you can see.. tha map has no key :acces_code

5:42 thus it cant return the value for it

5:42 tim__: right, now let me try access_token, what the hell

5:42 SagiCZ: (:access_token (:body access-token))

5:43 tim__: yeah good, I'm not quite that stupid, access_code as a typo before

5:43 *was

5:44 @SagiCZ is it ok If I paste the method in here

5:45 that I've got so far

5:45 SagiCZ: no

5:45 tim__: its only a few lines

5:45 SagiCZ: www.refheap.com

5:45 paste it there

5:45 tim__: ok

5:45 thank you https://www.refheap.com/101909

5:46 SagiCZ: whats wrong with that?

5:47 what does it return<

5:47 ?

5:47 tim__: nothing, blank

5:47 but what is interesting it that this ...

5:47 SagiCZ: umm

5:47 tim__: https://www.refheap.com/101910

5:47 works

5:47 that will put out test

5:48 but see :body in my test is a map, but in the response from get-access-token it isn't a map

5:48 SagiCZ: oh

5:48 but you called type on it_

5:48 ?

5:49 access-token is a map right_

5:49 ?

5:49 could you paste what is in the access-token variable? just do (let [...] access-token)

5:51 tim__: this is all happening via http - as instagram api posts back to a URL which makes it tricky for me

5:51 but just a sec

5:51 SagiCZ: yea

5:53 tim__: https://www.refheap.com/101911

5:54 SagiCZ: great.. give me a sec

5:55 kwladyka: I use ring + compojure + selmer. How can i put URL to routes in templates in HTML? I don't want use static HTML link in href and forms. I want use something like UrlTo(user.register).

5:56 tim__: one more example https://www.refheap.com/101912

5:57 I that one without using (str) which makes it look more like a map

5:58 SagiCZ: and (type access-token) returned PersistentArrayMap right?

6:00 i guess this should work ("access_token" (:body access_token))

6:00 tim__: @SagiCZ https://www.refheap.com/101913

6:00 I'll try that

6:00 SagiCZ: in clojure maps, keys dont have to be :keywords.. they can be strings or integers as well

6:01 ,("hey" {"hey" "value"})

6:01 clojurebot: #error {\n :cause "java.lang.String cannot be cast to clojure.lang.IFn"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.String cannot be cast to clojure.lang.IFn"\n :at [sandbox$eval25 invoke "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval25 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.Compiler eval "Compiler.java" 6792]\n [clojure.lang.Compiler eval "Compiler.java" 6755]\n...

6:01 SagiCZ: ,(get {"hey" "value"} "hey")

6:01 clojurebot: "value"

6:02 SagiCZ: (get (:body access_token) "access_token")

6:02 ok sorry tim.. it should be this ^

6:02 tim__: OMG

6:02 it worked!

6:03 (get (:body access-token) "access_token")

6:03 SagiCZ: sorry for not telling you earlier.. my clojure is a bit rusty

6:03 (doc get)

6:03 clojurebot: "([map key] [map key not-found]); Returns the value mapped to key, not-found or nil if key not present."

6:04 tim__: thank you for your help! Why do you think it showed as keyword here https://www.refheap.com/101912

6:05 SagiCZ: tim__: weird.. i guess the browser console just ate the quotes? who knows

6:06 tim__: SagiCZ: indeed, there is lots of mystery for me at the moment, early days :) thanks for helping anyway, this was killing me

6:06 SagiCZ: no problem!

6:45 kwladyka: Somebody use bidi routing library? How it looks vs pedestal?

6:51 i am trying answer myself which one should i use

6:51 because i see compojure is too simply for me

8:47 lxsameer: guys I'm writing a clojure lib, my ns name is xyz.core and I have a function called test1 , how can I call it from repl ?

8:49 jjttjj: (require xyx.core) (xyz.core/test1 args)

8:50 lxsameer: but i get this exception

8:50 CompilerException java.lang.ClassNotFoundException: mailgun.core, compiling:(/tmp/form-init4875882536837719255.clj:1:1)

8:51 while I'm requiring the namespace

8:51 jjttjj: ^

8:52 jjttjj: do you have it as a dependency in the project.clj?

8:52 lxsameer: jjttjj: i'm using lein and created a library project, and I'm in repl provided by lein repl in my lib project tree

8:53 jjttjj: hmmm

8:58 lxsameer: ohhh, if you're using lein repl you need to use load-file

8:58 lxsameer: with the file path as a param. instead of require

8:59 lxsameer: jjttjj: ah ok thanks

9:01 jjttjj: is there any shorter way to test my lib

9:01 ?

9:02 SagiCZ: lxsameer: use a good IDE that helps you with painful tasks like this?

9:02 lxsameer: SagiCZ: I'm using emacs with ceder, is that enough ?

9:03 SagiCZ: lxsameer: if it works for you then fine.. i personaly couldnt stand emacs and started using Cursive with IntelliJ IDEA

9:03 lxsameer: SagiCZ: thanks

9:04 jjttjj: lxsameer: do you mean CIDER?

9:04 you should do m-x cider-jack-in while in a file in your project tree

9:04 lxsameer: jjttjj: oops .

9:04 jjttjj: yeah

9:04 jjttjj: then you'll get a repl where require, etc will all work

9:05 SagiCZ: yeah just press a couple of magic buttons together and it might just work

10:21 justin_smith: jjttjj: require outside an ns form needs quoting (require 'xyx.core)

10:53 digiorgi: why you personally choose Clojure over Common Lisp?

10:56 justin_smith: at first, because company infrastructure was set up to make using the jvm a convenient choice. Now because of the large range of jvm libs and relatively frequent update of the vm, and because I prefer many of clojure's design decisions in comparison to cl.

11:04 dumptruckman: i'm wondering if there's a simpler and more efficient way to do this:

11:05 (let [new-entities [{:players (into [] (for [player (get-players entities)] (move player)))}]] new-entities)

11:07 justin_smith: I don't know about efficient, but you could have [{:players (mapv move (get-players entities))}] - I think that's clearer to read

11:09 dumptruckman: hmm yeah, that reads a lot better

11:12 i feel like it's hard for me to see where i should be using map

11:13 justin_smith: map is usually clearer when you are applying a single function, with no nested comprehension

11:14 for is usually clearer when you have nested functions to call, or nested comprehensions to do

11:19 dumptruckman: so i should just think map instead of for, typically

11:31 sw1nn: Can anyone give any guidance on when I should be using fn? vs ifn? to check whether something is function? In particular I think liberator here: https://github.com/clojure-liberator/liberator/blob/master/src/liberator/util.clj#L8 should be using ifn? 'cos (fn? a-multi-method) => false

11:32 justin_smith: yeah, ifn matches keyword too :)

11:32 the problem is that ifn also matches symbol

11:32 and most people supplying a symbol don't mean for it to be called (for example)

11:32 ,(ifn? 'a)

11:32 clojurebot: true

11:32 justin_smith: or vectors or maps

11:32 ,(ifn? [])

11:32 clojurebot: true

11:33 justin_smith: ,(ifn? {})

11:33 clojurebot: true

11:33 justin_smith: ,(ifn? #{})

11:33 clojurebot: true

11:33 sw1nn: well for vectors, that's fine right

11:33 ,([1 2 3] 3)

11:33 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.IndexOutOfBoundsException\n :message nil\n :at [clojure.lang.PersistentVector arrayFor "PersistentVector.java" 153]}]\n :trace\n [[clojure.lang.PersistentVector arrayFor "PersistentVector.java" 153]\n [clojure.lang.PersistentVector nth "PersistentVector.java" 157]\n [clojure.lang.APersistentVector invoke "APersistentVector.java" 283]\n [sandb...

11:33 sw1nn: ,([1 2 3] 2)

11:33 clojurebot: 3

11:33 justin_smith: sw1nn: well all those things are callable as functions, that's what ifn? tells you

11:34 sw1nn: when is symbol callable?

11:34 justin_smith: ,('a '{a 0})

11:34 clojurebot: 0

11:34 justin_smith: always

11:34 sw1nn: hmmm I see

11:34 justin_smith: ,('a '#{a b c})

11:34 clojurebot: a

11:35 sw1nn: so what is fn? telling me that ifn? isn't

11:35 justin_smith: sw1nn: the important thing in that context, is whether a user of liberator would expect to provide 'x and get (constantly 'x) back, or provide 'x and have it be used as a function

11:35 sw1nn: ifn? is callable, fn? is made by (fn [] ...)

11:36 another example:

11:36 ,(fn? #'+)

11:36 clojurebot: false

11:36 justin_smith: ,(ifn? #'+)

11:36 clojurebot: true

11:36 sw1nn: right, so i think it should be ifn? in that case, because you are passing something to be called to handle a decision.

11:36 justin_smith: for interactive development, sometimes people want to supply a var (that will be looked up each usage) rather than a function

11:37 sw1nn: OK, as long as people wouldn't be surprised / confused on what it does for symbols, vars, etc.

11:37 sw1nn: (ifn? a-var) => true

11:38 I'm confused when I pass the name of a function and it works, but I pass the name of a multimethod and it doesn't.

11:39 so have to #(a-multi-method %) or (partial a-multi-method)

11:40 justin_smith: sw1nn: multimethods are not fn? because they are not made using fn

11:42 sw1nn: yeah, I see the distinction now. ta

11:44 justin_smith: sw1nn: I came up against these same issues when someone posted a feature request on the polaris router for accepting multimethods

11:44 SagiCZ: justin_smith: do you think SICP is a good book to read when I need to learn how to design applications in a functional way? I already know a bit of clojure but struggle to transfer my OOP knowledge of Java to Clojure

11:45 justin_smith: SagiCZ: SICP is a great book. It also has online lectures from the original class, by the author, on youtube.

11:45 SagiCZ: is the last section about Register Machines relevant for clojure>

11:46 ?

11:46 J_Arcane: SagiCZ: I recommend How to Design Programs.

11:46 http://www.ccs.neu.edu/home/matthias/HtDP2e/

11:46 SagiCZ: J_Arcane: thanks.. why would you recommend this book?

11:48 J_Arcane: It's very much explicitly about what you asked about. It's good at teaching how to design and compose functional programs (I think it doesn't even teach mutation until something like 8 chapters in), and the lessons even the first few chapters will give are quite handy.

11:48 Made me a better programmer, though as is the way with youth, I don't think I recognized it at the time.

11:48 SagiCZ: J_Arcane: sounds great! will definitely check it out

11:55 chadhs: is there an option to configure auto intent when working in the `lein repl` which i believe is repl-y?

12:02 justin_smith: chadhs: lein repl uses nrepl

12:05 Jaood: justin_smith: how does that answers his question?

12:05 chadhs: justin_smith: this gets reported when you run `lein repl`

12:05 REPL-y 0.3.5, nREPL 0.2.7

12:05 justin_smith: Jaood: it doesn't answer the question, it's just addressing one part of what he said

12:05 chadhs: it's not biggy, just haven't seen anything in docs to configure behavior in the repl

12:07 there are some cool options to get colorized output which is nice. i chose venantius/ultra

12:07 justin_smith: chadhs: isn't that a grab bag of various tools / options thrown together?

12:08 chadhs: yes it is. it provides nice output, so rather than yak shaving tried it out and like the result thus far.

12:08 justin_smith: chadhs: yeah, if you look at the source of ultra it's got one namespace that consists of importing whidby, another that consists of importing puget etc.

12:09 good to hear it's a good combo though

12:09 chadhs: correct

12:09 easy for newbie like me at this point ;-)

12:09 justin_smith: chadhs: the reason I brought up nrepl is that nrepl accepts various middlewares for modifying its behaviors

12:10 chadhs: ill post something if i figure out auto indent, but for now i think i can handle hitting the space bar

12:10 justin_smith: I'm actually not sure if repl-y is pulled in as an nrepl middleware, or repl-y is invoking nrepl in that case though

12:10 chadhs: ah gotcha… (gotta run an errand bbl to check messages thnx justin!)

12:22 martinklepsch: weavejester: hey — is ns-tracker supposed to support reloading of .cljc namespaces as well or is there a difference?

12:31 weavejester: martinklepsch: It relies on tools.namespace for that.

12:31 martinklepsch: So if you have an older dependency overriding it, it won't load cljc

12:31 martinklepsch: And tools.namespace doesn't currently support cljc files with reader conditionals in the ns declaration

12:32 martinklepsch: weavejester: thanks, that's super helpful!

12:32 weavejester: martinklepsch: See http://dev.clojure.org/jira/browse/TNS-34

13:10 maio: can someone point me to some best practices regarding adding clojurescript to a project? how should I layout my repo for example?

13:10 src/clj + src/cljs? or is there some problem with src/proj/x.clj + src/proj/x.cljs?

13:15 tolstoy: maio: for what it's worth, I use the src/clj src/cljs src/cljc style, then add those paths to the appropriate builders as needed.

13:16 maio: As far as "best practices", I don't know. I always figure best practices are what you hope your competitors are using.

13:16 maio: :)

13:18 tolstoy: maio: One issue I've had with cljsbuild is that if you want to use macros in CLJS, a "util.clj" in src/clj will somehow break a "util.clj" in src/cljs. I think it's a lein classpath issue, but don't know for sure.

13:43 Jarvis2: CuteStat 2.0 Site Worth Script NULLED Share & Rate direct link http://bit.ly/1EL693G

13:43 CuteStat 2.0 Site Worth Script NULLED Share & Rate direct link http://bit.ly/1EL693G

13:43 CuteStat 2.0 Site Worth Script NULLED Share & Rate direct link http://bit.ly/1EL693G

13:48 justin_smith: tolstoy: is this because the macros for cljs must be on util.clj?

13:48 tolstoy: justin_smith: I think so.

13:49 I had `src/clj/app/util.clj` with some stuff in it.

13:49 And: `src/cljs/app/util.clj` (as well as a corresponding util.cljs) with a macro in it.

13:49 justin_smith: u

13:49 tolstoy: No matter what I did, the macro never showed up.

13:50 Once I changed the "cljs" namespaces to "utils" rather than "util", everything worked as expected.

13:50 justin_smith: yeah, that's gonna have path shadowing

13:50 see also cljs.core.async stylr

13:51 err that style of disambiguating by package

13:51 tolstoy: I just thought the :include-macros true thing had changed, so I never quite asked the right question on #clojurescript when I was asking about it.

13:51 tmtwd: hi when I do cider-jack-in it doesn't load the current namespace

13:52 and C-c M-n doesn't work either

13:52 tolstoy: justin_smith: Strange, though, because cljsbuild paths did not include "src/clj".

13:52 justin_smith: tmtwd: try running lein check

13:53 kwladyka: Somebody have experience with Pedestal, Hoplon and Bidi? I am trying figure out which one should i use :)

13:53 justin_smith: tolstoy: aren't there profile merges in play?

13:53 tolstoy: justin_smith: Perhaps, but it's invisible to me.

13:54 justin_smith: As an example, lein-garden merges lein's top level :source-paths in with the declaration in its own area. End result, change anything and the css gets regenerated.

13:55 justin_smith: kwladyka: bidi and pedastal are not replacements for one another

13:55 kwladyka: justin_smith, if you have time there is my question with more details http://stackoverflow.com/questions/30557724/when-use-pedestal-hoplon-bidi-and-route-one

13:56 tmtwd: yeah, I still can't load the current namespace

13:57 tolstoy: justin_smith: I submitted a patch for lein-garden (next release, whenever that is), but I didn't investigate lein-cljsbuild to figure out what I might have been misconstruing about namespace collisions.

13:59 justin_smith: kwladyka: bidi and compojure are routing libs, all they do is rpute requests to handlers

13:59 tmtwd: I get :reloading (funny.core funny.core-test)

13:59 justin_smith: hoplon os a templating lib

14:00 tmtwd: but I still get user> in the repl

14:00 justin_smith: xompojure is not intended to do templating

14:00 kwladyka: justin_smith, hmm so hoplon is something like selmer?

14:00 justin_smith: iirc - double checking

14:02 J_Arcane: kwladyka: Hoplon is a single-page-app framework in Clojurescript.

14:02 justin_smith: yeah, I wad wrpng

14:03 *I was wrong, that is

14:03 tolstoy: kwladyka: Maybe you're looking for a "full stack" framework? The usual pattern for Clojure web-devs is to mix and match libraries.

14:04 justin_smith: kwladyka: but beside that point you are comparing tools from different categories

14:04 kwladyka: justin_smith, maybe... did you look for my link?

14:04 justin_smith: yes

14:04 tolstoy: kwladyka: As justin_smith is saying, each of those libs solve different parts of the problem.

14:04 kwladyka: "Write everything in Clojure and ClojureScript, clientside and serverside." <- Hoplon

14:05 i undestand, but on http://stackoverflow.com/questions/30557724/when-use-pedestal-hoplon-bidi-and-route-one i explain my problem with details (i hope)

14:05 J_Arcane, so Hoplon is for frontend or for front and backend side?

14:06 J_Arcane: kwladyka: Pretty much front end only, I think, though I believe they have a sibling library for back-end.

14:06 I've only used it for a front-end only SPA.

14:07 justin_smith: bidi is a router. hoplon and pedastal are full stack

14:07 kwladyka: or Hoplon is similar to metor framework?

14:07 *meteaor

14:07 *meteor

14:08 J_Arcane: justin_smith: Ahh, right. I just never used the server side.

14:14 Bruce_Wayne: Anyone know the best place to see a reagent, re-frame example

14:14 ?

14:14 justin_smith: hoplon is more oriented to spa where you have a lot of (cl)js client logic, pedestal is ,ore focused on the backend loggic of building a resttful servvice

14:16 eyepatch: I'm pretty much a total newb to web development, and the tutorials I'm looking at assume more web dev experience than I have. I don't understand the deployment cycle of Clojure integrated with compojure. Where is the HTML file loaded by the browser?

14:16 J_Arcane: Bruce_Wayne: I did a simple weather app with reagent-template recently. Nothing special, but might be helpful for seeing the basics: https://github.com/jarcane/wunderprojectj

14:17 kwladyka: but hoplon has also backend support? Hoplon cl(js) doesnt work with REST on backend side?

14:17 eyepatch: Can a web app made with Compojure be as interactive as one with a technology stack including JS such as ASP.NET?

14:17 Bruce_Wayne: J_Arcane: Thank you!

14:17 eyepatch: Do people integrate JS into their web development with compojure somehow?

14:17 weavejester: eyepatch: Yes, any modern web stack has the same capabilities

14:18 eyepatch: At least in terms of serving files

14:18 kwladyka: eyepatch, compojure is for routing only

14:18 eyepatch, you can load files using RING

14:18 eyepatch: I'm referring to the stack that's used with compojure on top of ring iirc.

14:19 weavejester: eyepatch: A web server receives HTTP requests sent by a HTTP client, like a browser

14:19 kwladyka: eyepatch, but if you want use template use hiccup, selmer or enlive

14:19 weavejester: eyepatch: And sends back a HTTP response in return.

14:19 justin_smith: kwladyka: sure, but they have a different focus. pedestal will help more if your development is backend-heavy, hoplon likely more useful if the work is frontend heavy

14:19 kwladyka: justin_smith, like always you help a lot :)

14:20 justin_smith: kwladyka: though pedestal doesn't use ring, which is the more popular backend abstraction

14:20 J_Arcane: eyepatch: Have a look at reagent-template. Generally what you do is build a back-end that provides a route that serves the built front end.

14:20 weavejester: eyepatch: Each HTTP response will contain one of the files you see in your browser, be it a HTML page, an image, CSS styling, and so forth.

14:24 eyepatch: Most web servers allow files to be served from a directory. So a URL like http://example.com/foo/bar.txt, will be converted into a path like /var/www/foo/bar.txt, and the response will contain the content of that file.

14:33 sidharth1: in the clojure java realm, is the use of the value of (Object.) a common thing ? I have this working code that says "(let [eof (Object.)]"..., is that at all a common thing to say ?

14:34 justin_smith: sidharth1: it's the idiomatic way to make a unique token that you would test for equality later

14:34 sidharth1: it looks ... yes.. i was thinking that

14:35 justin_smith: see also gensym

14:35 which is a bit more clojurey, and is useful in macros

14:35 sidharth1: thanks for the consultation :)

14:35 justin_smith: ,(gensym)

14:35 clojurebot: G__27

14:35 justin_smith: (doc gensym)

14:35 clojurebot: "([] [prefix-string]); Returns a new symbol with a unique name. If a prefix string is supplied, the name is prefix# where # is some unique number. If prefix is not supplied, the prefix is 'G__'."

14:36 justin_smith: the key there being that within a single run of your program, it is guaranteed unique

15:21 toxmeister: anyone got any bright idea how can i force `lein test` to *not* ignore .cljc files?

15:22 justin_smith: toxmeister: I've found that I can require and test cljc files from clj test namespaces

15:22 but I have not tried putting tests in cljc

15:30 toxmeister: justin_smith: been thinking about that, but means i'd have to generate dummy ns wrappers for all my tests and that per clj & cljs... i think it might have to do with builtitude & this call: https://github.com/technomancy/leiningen/blob/master/src/leiningen/test.clj#L145

15:31 justin_smith: doing `lein test my.cljc.ns` works fine, it's just the auto-selection which seems to ignore these files

15:31 justin_smith: toxmeister: ahh, so you want to run the same tests from clj and cljs on a cljc file?

15:31 interesting

15:31 toxmeister: yeah, example here: https://github.com/thi-ng/ndarray/blob/master/test/core.org#complete-namespace-definition

15:32 it generally works, but as i said only if you specify the namespace as command arg

15:32 so for the above linked test, i can call `lein test thi.ng.ndarray.test.core` and it works fine

15:33 justin_smith: toxmeister: in that case, a workaround would be to explicitly add that file to your test-paths in project.clj maybe?

15:33 and the real fix would likely be what you linked above

15:33 toxmeister: but don't you just state directories in :test-paths?

15:34 justin_smith: toxmeister: I have noticed with other *-paths in lein that I can specify a directory or a specific file

15:34 but I haven't tried with a test file tbh, you could try though

15:36 toxmeister: justin_smith: just tried, full file path in :test-paths doesn't make any difference :(

15:36 justin_smith: will file an issue

15:36 justin_smith: Sorry to hear that. I guess we need a bultitude update?

15:36 toxmeister: justin_smith: thx though! :)

15:37 justin_smith: you any experience w/ lein hacking? always find it a bit daunting...

15:38 justin_smith: toxmeister: there are straightforward instructions on getting the source repo running locally

15:38 after that it's just a bigger than usual clojure project

15:39 toxmeister: justin_smith: interestingly: https://github.com/Raynes/bultitude/blob/master/src/bultitude/core.clj#L15

15:39 justin_smith: last edit "a day ago"

15:39 justin_smith: heh :

15:39 )

15:54 toxmeister: yeah, a new library is born: https://github.com/thi-ng/ndarray/blob/master/src/index.org :)

15:55 TEttinger: is this an n-dimensional array lib?

15:56 toxmeister: TEttinger: yes, currently up to 4D, but changeable

15:56 TEttinger: does it return primitive arrays when run in clojure?

15:57 toxmeister: TEttinger: ...and everything type hinted and most transformations ops almost free (ie. no copying of data needed)

15:57 TEttinger: yes

15:57 TEttinger: great!

15:57 (inc ToxicFrog)

15:57 lazybot: ⇒ 4

15:57 TEttinger: (inc toxmeister)

15:57 lazybot: ⇒ 1

15:57 TEttinger: heh

15:57 toxmeister: TEttinger: you can get at the primitive array (via `(nd/data my-ndarray)`)

15:58 TEttinger: under CLJS it uses typed arrays

16:01 Bruce_Wayne: what’s the difference be (register-sub …) and (register-handler …) in reframe?

16:18 sveri: register-sub is triggered when something changed in the application state, register-handler is triggered by program code to change the application state

16:18 Bruce_Wayne: ^^

16:19 Bruce_Wayne: so when someone clicks a button then register-sub is called?

16:19 I’m working through this example: https://github.com/Day8/re-frame/tree/master/examples/simple

16:20 sveri: no, the other way around, you click a button and register an event with (dispatch [:button-event]), then register-handler with the id :button-event is called

16:20 There you can change the app-state

16:22 Bruce_Wayne: oh ok then once the handler is called, the app state changes, and then the sub is called because the app state changed?

16:23 sveri: exactly

16:23 Of course you have to define in register-sub what specific part of that app-state should change so that it's called

16:24 And finally you use re-frame/subscribe for that sub to actually be notified of that change

16:27 Bruce_Wayne: and can you register subs or handlers to multiple states?

17:32 anti-freeze: Hi everyone. So, I'm trying to create a macro to make repetitive database operation definitions simple. Firstly, I can't get this to work, secondly, can anyone advise a better way of maybe going about this? Here's the sauce: https://www.refheap.com/be527722eea4862e4f2e347fc

17:33 SagiCZ: if you can do it with a function, dont do it with macro

17:34 anti-freeze: SagiCZ: I constantly have to redefine the same functions again and again with only minor differences, I thought a macro would be a perfect fit

17:36 SagiCZ: probably a good idea then

17:38 TMA: anti-freeze: it might be possible to have one master function that takes one more parameter -- the difference

17:38 anti-freeze: SagiCZ: Its a simple enough macro. I define a function that returns a map with quoted forms containing a %name% placeholder. The macros job is to replace %name% with the model name. So for example {:create '(def %name% (partial create-* coll)} would become (def create-user (partial create-* coll))

17:38 chouser: I suspect you still don't actually need a macro and might in the long run prefer functions that take arguments rather than functions with special names (if I understand your goal correctly)

17:39 anti-freeze: So then I can just go (generate-operations :user :users default-operations)

17:39 SagiCZ: the good thing about functions is that they are objects and can be used as input into function-manipulating functions whereas macros can not

17:39 anti-freeze: And it'll generate the standard stuff

17:39 TMA: anti-freeze: instead of (defn foo-N [...] (... (___ ...) ...)) where only the ___ changes, you could have (defn foo-generic [f ...] (... (f ...) ...))

17:39 anti-freeze: SagiCZ: Right, what I had before was something like (def create-user (partial create-* "users"))

17:39 chouser: that said, I'm sure we'd be happy to help you write some ill-advised macros. :-)

17:39 anti-freeze: But it would be the same in every file

17:40 change the method and collection name

17:40 chouser: why not have replace usages like (create-user ...) with (create :user ...) ?

17:40 s/have//

17:41 anti-freeze: doesn't seem very DRY is all

17:41 chouser: both syntaxes use the word "create" once and the word "user" once. No added repetition either way.

17:42 But again, if you want to learn to write macros, happy to help.

17:42 anti-freeze: chouser: I could do, but I want to abstract collections away from the other accessors. Besides, If I want to overwrite behaviour for that single instance, I assume it would be difficult to do

17:42 SagiCZ: i never got around learning about macro beacuse I just never run into a problem that couldnt be solved with a function

17:42 chouser: could use multimethods if you expect to tweak behavior.

17:43 TMA: in common lisp you can have eql-specialized method that would do the trick

17:43 is something similar possible in clojure?

17:43 anti-freeze: chouser: I could do actually. Good idea. I hear multi-method performance is terrible though and considering its an integral part of the application

17:44 chouser: anti-freeze: if you're dispatching on a single parameter, you could use protocols, which have stellar performance.

17:44 kristof: TMA: dispatch on =

17:44 chouser: Anyway, if you want to write a macro, the standard recommendation is to start with a concrete specific example input to the macro, and write out what that example would expand to.

17:45 only then try to write the macro, and if you get stuck it's then much easier for others to help.

17:45 SagiCZ: chouser: um.. so if i have a multimethod dispatching on a value of a map via function ":keyword" i can subsitute that with a protocol?

17:46 chouser: SagiCZ: no, not quite. You'd probably use different record types (defrecord) instead of a map with a particular keyword value.

17:46 Switching from a multimethod to a protocol, you give up flexibility for the better performance.

17:46 SagiCZ: my defmulti looks something like this:

17:46 (defmulti observe :type)

17:46 and it dispatches according to the value of type

17:46 thedoodPL: whats the goto test lib for clojure?

17:47 SagiCZ: I am expecting to have around 20-50 of types eventually

17:47 chouser: SagiCZ: right, instead of different values for :type, you'd have to have different defrecord types.

17:47 anti-freeze: where coll = :users

17:47 SagiCZ: so the :type keyword (and value) would be a part of a record not a regular function right..

17:48 and the record would all implement the same protocol

17:48 chouser: That is, instead of (defn make-a-foo [] {:type :foo}) you'd need (defrecord Foo ...) (defn make-a-foo [] (Foo. ...))

17:48 SagiCZ: exactly.

17:48 I wouldn't actually recommend it unless you're sure you need to perf. Multimethods are lovely.

17:49 s/to/the/

17:49 SagiCZ: chouser: well since my app is performance critical I will definitely consider it.. then again I kind of liked the idea of maybe dispatching via something else than type in the future

17:50 also records are so ugly

17:50 chouser: SagiCZ: yep. Before making the change, you might try to measure the perf and make sure the multimethod dispatch is actually slow compared to the rest of the app

17:51 thedoodPL: Do you guys do tdd with clojure?

17:51 SagiCZ: chouser: yup.. i am way before optimizing change

17:51 thedoodPL: I personally dont but clojure is very suitable for TDD

17:51 since you have the whole referential transparent functions deal.. they are very easy to test

17:52 chouser: thedoodPL: clojure.test is a built-in test system. There's also 'midge' which I understand to be designed especially for TDD

17:52 SagiCZ: chouser: s/change/phase

17:52 anti-freeze: Why do you guys advise agains't macros so heavily anyway. I thought they were what made lisp ridiculously powerful (as preached by Let Over Lambda)

17:52 %s/./?

17:52 chouser: anti-freeze: they are powerful. When you need them, not having them is terribly crippling.

17:53 SagiCZ: anti-freeze: just what i said earlier.. they cant be manipulated at runtime because they are not objects like functions.. they are just rules for the reader

17:53 chouser: anti-freeze: when you do not need them, using them anyway just leaves you with their drawbacks.

17:53 thedoodPL: SagiCZ: thanks mate :)

17:53 TMA: anti-freeze: that is the responsibility part of 'with great power comes great responsibility'

17:53 anti-freeze: I see. What about the situations where a function will do, but it makes code marginally more complex and convoluted?

17:54 chouser: anti-freeze: I sometimes provide two APIs, one purely of functions and values, and then a trivial macro to tidy it up for the most common use cases.

17:55 anti-freeze: Yea, I suppose that makes sense. Thanks everyone

17:55 Love the clojure community :P

17:55 kristof: anti-freeze: Write functions for functionality. Write macros for language design. When Clojure ceases to be the proper language, make your own.

17:55 chouser: As a trivial example, see the source of the 'source' macro.

17:55 SagiCZ: chouser: which is very often done in the clojure core and other popular libraries

17:56 kristof: anti-freeze: And don't fall into the trap of using macros for functionality. Write functions to do those things. For instance, I've seen macros used to implement lazy evaluation, multiple evaluation, control flow...

17:57 anti-freeze: I think I'll stick to multimethods now until performance becomes an issue

17:58 chouser: Even libs like core.async which seems like it might be useless without its "go" macro, I sometimes wonder if a functional API wouldn't help it in some (perhaps relatively rare) cases.

17:58 thedoodPL: SagiCZ: any must read books that you'd recommend for a newcomer?

17:58 kristof: chouser: You can take my go macro out of my cold, dead hands

17:59 chouser: :-)

17:59 SagiCZ: thedoodPL: I recommend just one -> http://shop.oreilly.com/product/0636920013754.do and disrourage from Joy of Clojure and Programming Clojure

18:11 chouser: i started tinkering with defprotocol and defrecord and I just wanted to ask you one minor thing.. suppose I have a protocol thats defined by 3 methods.. i want to have 20 defrecords that implement the protocol..

18:11 1) can the implementation choose to not implement the function and have some default for it?

18:11 2) what if all the implementations should have the exact same fields, can they somehow inherit them?

18:21 hiredman: protocols let you have different behaviours for different things, if you want the same behaviour for many different things, that just sounds like a function

18:22 SagiCZ: no, the methods implementations would be vastly different for each record.. just the fields should be the same

18:22 chouser: 1) I don't think so. Instead you could have three separate protocols of one method each, and then extend them to default Object, and only override that as desired.

18:23 SagiCZ: oh.. cool

18:23 chouser: 2) no, but you could write a ... macro ... to generate defrecords with the same field list each time. :-P

18:23 SagiCZ: chouser: haha yeah here we go! thanks

18:24 chouser: ok, dinner time. Good fortune to you in your adventures!

18:24 SagiCZ: see you around!

18:35 thedoodPL: Is anyone here developing in clojure professionaly?

18:36 if so then where do you work ;)

18:50 weavejester: thedoodPL: I do, and London :)

18:51 thedoodPL: weavejester: what industry?

18:51 weavejester: thedoodPL: I'm a contractor, so no specific industry.

18:53 thedoodPL: weavejester: what kind of daily rates can you get in London? (clojure gigs)

18:54 weavejester: thedoodPL: It varies but generally between £400 and £500.

18:56 thedoodPL: weavejester: well thats not bad although London is crazy expensive. I've heard that 500 pd is reserved for the 'lucky' ones working in the financial industry

18:56 stain: weavejester: are you generally hired as "Clojure dude" (e.g. for Ring and Compojure work) or as "Make me something webby"?

18:56 thedoodPL: weavejester: how much exp. do you have?

18:57 weavejester: thedoodPL: Actually, most of my work has been with startups. I do have a fair amount of experience with Clojure, though.

18:58 I live outside London, and commute in when I'm needed on site.

18:58 stain: I'm usually hired for companies using or starting to use Clojure.

19:01 stain: weavejester: well, that's great that there are regular companies that consider Clojure right away

19:01 thedoodPL: weavejester: do you have a steady stream of contracts or are you on the bench often? I just want to get an idea about the job market there

19:01 stain: I generally just have to sneak Clojure in along the edges..

19:02 thedoodPL: stain: if I'm lucky I might be getting a full time clojure job this summer

19:02 :)

19:02 toxmeister: if you're interested in OpenCL + Clojure + rendering, you might like this little project: https://github.com/thi-ng/raymarchcl/ - most of it is actually from 2013, but only just got around last week to update it to work w/ latest Clojure versions

19:03 weavejester: thedoodPL: Most of my contracts have been fairly long. I haven't been without work for more than a month or two in the past three years. Recently I've decided to take a fairly long break, but that was a deliberate choice.

19:03 stain: thedoodPL: congratulations dude :)

19:04 thedoodPL: stain: the company that I was interviewed by last week told me that they might be getting a clojure project and if I'd be interested

19:04 clojurebot: Gabh mo leithscéal?

19:04 stain: thedoodPL: for our work it is often up to myself to decide technology.. but as I am generally the only one on the team using Clojure, then I know that if I use Clojure on a project I will end up also solely responsible for that code ..

19:05 thedoodPL: stain: where do you work?

19:05 stain: thedoodPL: well, it sounds good, although you should of course always be sceptical of companies who decide on technologies before a project has started

19:05 thedoodPL: University of Manchester

19:05 weavejester: thanks for your little IAMA :)

19:06 toxmeister: thedoodPL: FWIW I'm not purely doing web/serverside stuff, but was lucky enough to work mainly in clojure/clojurescript for various design & data visualization gigs. have almost used no other lang for my freelance projects since 2012 (only bits of python, C and JS here and there)

19:07 thedoodPL: stain: I went there for an interview for a java job and left with a possibility of getting a clojure one, best feeling ever :0

19:07 weavejester: np. I should also add that there are more companies that want permanent employees rather than contractors.

19:07 stain: weavejester: now, why did you make Ring? :)

19:08 weavejester: stain: I didn't, actually. Mark McGranaghan started the project.

19:08 stain: weavejester: are they all the kind of "Move to London and come work "permanently" on-site for a start-up with bare brick walls and 1.5 years left of funding?

19:08 thedoodPL: weavejester: there are almost none clojure ads on jobserve though :/ I was pretty sure that clojure job market in london was dead

19:09 stain: weavejester: my apologies.. still, responsible for a large chunk of it, right?

19:09 ring is cool stuff, so simple and flexible

19:09 weavejester: stain: I'm the current maintainer, and I believe I've written the vast majority of it, yes.

19:09 thedoodPL: stain: btw moving to london is kinda tricky i don't think I'd move there for a permie position for less than 50k, because its so freaking expensive

19:09 stain: thedoodPL: 50k? You need at least 75k.. and a partner earning the double

19:10 and then you can afford to rent a one-bedroom flat

19:10 weavejester: thedoodPL: I can only judge by the companies that I work for and the recruiters that contact me.

19:10 thedoodPL: stain: nah one bedroom flats run for 1200-1500 in decent areas dude ;)

19:11 stain: then again here in Warsaw you can get a pretty luxorious apartment for 700 quid

19:11 stain: thedoodPL: that is still insane.. when I moved to Manchester 10 years ago I paid £550/month for a two-bedroom flat

19:11 to be fair, it was not a decent area

19:12 just a bit of car tires burning in the street.. two neighbours strangling each-other.. That kind of thing!

19:12 thedoodPL: stain: ;)

19:12 stain: good learning experience for a culture-poor Norwegian

19:13 btw, I stopped the two stranglers so nobody died

19:14 weavejester: Outside the M25 it gets more reasonable, but that's a long commute in.

19:15 thedoodPL: weavejester: I've found you on twitter ;)

19:22 weavejester: is there a functional or clojure'an equivalent of SOLID principles or uncle bobs clean code? Or some guidelines on writing good clojure code

19:24 stain: thedoodPL: just forget anything you might still remember from Java

19:24 except perhaps the String methods

19:25 keep things simple and concise. Don't overengineer it, but make reusable functions.

19:25 weavejester: thedoodPL: Have you watched "Simple Made Easy"?

19:25 stain: data structures are king. Yet they should also be simple and consise.

19:26 btw.. I was not concise in my spelling of consise there

19:26 thedoodPL: weavejester: no I have not, I'll watch thanks :)

19:26 I'll watch it*

19:26 stain: xD

19:27 weavejester: thedoodPL: IMO it explains a lot about Rich's reasoning behind a lot of the decisions in Clojure.

19:27 Like *why* Clojure prefers data structures

19:29 thedoodPL: OK guys thanks for the chat I'm going to get some sleep I've got to wake up before 7 today ;)

19:29 have a good night :)

20:13 stain: if I have a couple of protocols, and also some imported Java classes which I (extend-type) to support those protocols, is there a general naming style I should follow? E.g. I've gone with P* for the protocols, so that I have (extend-type Graph PGraph (blah [g] (.getBlah g)))

20:14 or should I just call them without any prefix and use fully qualified names for the Java types

20:21 toxmeister: stain: i generally don't like prefixes, but for protocols have always been using "P*" as well...

20:27 amalloy: P is a bizarre prefix i have never seen used for protocols. i think the two main camps are Foo and IFoo, since it's like an interface

20:28 justin_smith: amalloy: the hawaiian-detective naming convention specifies that all protocol names must be suffixed with -PI

20:43 Bruce_Wayne: hey what is the best way to use clj files in cljs files?

20:43 like require a clj ns in a cljs ns?

20:50 chouser: you can't really. clj runs in jvm, cljs in javascript.

20:51 with the 1.7 RCs you can write a .cljc file that can be require'd by both clj and cljs

20:52 Bruce_Wayne: chouser: interesting

21:47 TEttinger: pharaoh, you made the same mistake as the horse naming competion

21:47 competition

21:47 justin_smith: oops

21:47 TEttinger: the horse that won the kentucky derby was American Pharoah

21:48 spelled just like that

22:27 justin_smith: eventually the horse people are goingto break down and just use UUIDs

22:27 they aren't allowed to reuse names

22:28 best horse name ever, potoooooooo

22:28 gfredericks: ,(def horse-count (atom 1000000))

22:28 clojurebot: #'sandbox/horse-count

22:28 gfredericks: ,(str "horse-" (swap! horse-count inc))

22:28 clojurebot: "horse-1000001"

22:28 justin_smith: clojure version ##(apply str "pot" (repeat 8 \o))

22:29 ,(apply str "pot" (repeat 8 \o))

22:29 clojurebot: "potoooooooo"

22:33 Bruce_Wayne: justin_smith: is there a way to require a clj ns in a cljs ns?

22:33 I’d like to use some of the clj functions in my cljs handlers

22:33 justin_smith: I’m working in reframe

22:33 justin_smith: Bruce_Wayne: like chouser mentioned, you can use cljc

22:34 Bruce_Wayne: what about cljx?

22:34 justin_smith: with cljc being a part of the core language, I wouldn't make something with cljx right now

22:37 Bruce_Wayne: justin_smith: do you know any good examples using cljc?

22:37 justin_smith: there are some good examples here - it's not complex so the stuff here was enough for me to do everything I needed http://dev.clojure.org/display/design/Reader+Conditionals

22:43 bbloom: Bruce_Wayne: fipp uses cljc to good effect now

22:44 https://github.com/brandonbloom/fipp/tree/master/src/fipp

Logging service provided by n01se.net