Fork me on GitHub
#clojure
<
2016-01-19
>
mheld00:01:08

for the record, the liberator has great market penetration (no pun intended)

jfntn00:01:34

Is it completely impossible to (extend-type SomeDeftype SomeJavaInterface …)?

danielcompton02:01:26

@alexmiller: do you have any update on the state of clojure survey?

Alex Miller (Clojure team)02:01:39

I wrote a long thing and other people are editing it but they're busy so... It's coming

jonahbenton04:01:35

@jfntn yes, extend* require protocols. if you need a class whose superclass is SomeDeftype which implements SomeJavaInterface, look at :gen-class, though you will have to be careful about compilation order; if hopefully you just need an instance that does the same then look at proxy

jimmy04:01:48

hi guys in clojure how can we define defmethod in another namespace separated from defmulti ?

jfntn04:01:40

@jonahbenton: makes sense, looks like I won’t be able to do this without an instance-level wrapper… Thanks for the explanation!

Alex Miller (Clojure team)04:01:29

@nxqd: the defmulti is a function var just like any other - just refer it in your ns then use a defmethod like usual

mheld04:01:36

I have a ring handler that spits out other ring handlers (thus requiring to be called twice on a request to get a response) — is there a better way of doing this?

sashton05:01:29

@mheld: here's my understanding of ring handlers. A handler should take the request map and return a response map. It should not return another handler. A 'middleware' function should take some args (often including a handler) and return a handler. The handler which the middleware function creates will either modify the the request map before passing it to the original handler, or the response map which it receives from the handler. Or the middleware can do more complex stuff -- pick one of a list of handlers to use, log some stuff, check authentication, etc. For example:

(defn hello-handler
  "Says hello to someone"
  [req]
  {:body (str "Hello, " (:name req))})
=> #'user/hello-handler

(defn make-loud
  "Middleware to convert :name param to uppercase. This function takes a handler, and returns a new handler"
  [handler]
  (fn [req]
    (->> (update req :name clojure.string/upper-case)
         (handler))))
=> #'user/make-loud

(def root-handler 
  (make-loud hello-handler))
=> #'user/root-handler

(root-handler {:name "Steve"})
=> {:body "Hello, STEVE"}

mheld05:01:28

@sashton: I get that, but for some reason if I don’t I get a liberator.core$resource$fn__29104 cannot be cast to java.util.Map error

mheld05:01:43

which makes it seem like the handler isn’t being applied enough

mheld05:01:07

and I do call (make-handler {hash-of-urls} {:url-tag->handler})

sashton05:01:10

I haven't used bidi, but I'm guessing it would be something like this:

(def root-handler
  (make-loud 
    (make-handler ["/hello" hello-handler])))

sashton05:01:42

can you paste your route/handler code?

mheld05:01:57

make-handler searches through the keys of the route hash to find the right handler for the action, then calls that handler on the request

mheld05:01:29

(user-handler {:uri "/api/users/119" :params {:id 119}}) -> #object[liberator.core$resource$fn__29104 0x4ede08e6 "[email protected]"]

sashton05:01:07

what if you change handler-map to:

(def handler-map
  {:user            (fn [req] {:body "found a user"})})
Then run it again. Any difference?

sashton05:01:48

eliminate liberator to see if it is the cause, or something else

mheld05:01:23

that works!

sashton05:01:56

hmm, okay. sounds like something between liberator and bidi then

sashton05:01:13

i've used liberator before, but not bidi, so i don't have any ideas

mheld06:01:44

A parameterized resource, which is defined using (defresource name [param & params] ...) does not define a ring handler function like a regular resource but a function that produces a ring handler.

mheld06:01:48

good to know

mheld06:01:42

so (defresource user [param]…) doesn’t give us a handler 😞

mheld06:01:53

for those looking in the history

jethroksy09:01:42

I'm managing a websocket-client connection with aleph, aleph returns a duplex stream, how would you store and manage this state? In an agent? I would need to periodically check if the websocket connection is still open and reset it where necessary.

aurelian15:01:30

,(doc partition)

meow16:01:48

welcome @immoh @luiz @last.khajiit @buntha @cl0jurian @danielytics and everyone else who hasn't been welcomed yet simple_smile metal

jonahbenton16:01:09

hey @jethroksy, could use an agent but from a semantics perspective it may be a better use case for an atom. It's more of a stateless resource, in the sense that sending some data over a websocket doesn't yield a new websocket.

jethroksy17:01:33

@jonahbenton: got it. I'm currently spinning off 2 go loops, one to constantly ping, and another to constantly check for replies, if not swap! the atom with a new ws connection. simple_smile

jonahbenton17:01:37

@jethroksy: cool, sounds good.

kosecki18:01:01

need some help, having such a sequence '({:a 1, 😛 2} {:a 3, 😛 4}) how to get {:avg-a 2, :avg-b 3}

kosecki18:01:40

don't know why, but it smells for me, there must some idiomatic way to do that

donaldball18:01:52

(when (seq numbers) …) may be more idiomatic

ddellacosta18:01:46

yeah, using (when (seq numbers) …) is definitely more idiomatic. Otherwise this is a place where I wish we had a viable Option type in Clojure

ghadi18:01:27

(defn average [numbers]
  (when (seq numbers)
    (/ (apply + numbers) (count numbers))))

ghadi18:01:31

kosecki: ^

ghadi18:01:42

one-armed if == when

ghadi18:01:30

s/ keyw / k

ghadi18:01:04

the k naming is idiomatic

ghadi18:01:40

Also, filter + map == keep

ghadi18:01:04

I'd kill the whole function only-some-by-prop

ghadi18:01:24

and do (average (keep :temperature measured-values))

ghadi18:01:47

Keywords are functions and can be applied by any seq operation

ghadi18:01:04

clojure core is small and huge at the same time

cl0jurian18:01:14

@meow thanks it's nice to be here

kosecki18:01:12

@ghadi: besides :temperature there is also :rain so trying to juxt it somehow

ghadi18:01:42

ok, but for what purpose?

ghadi18:01:31

i was thinking

{:average-temperature  (average (keep :temperature measured-values))
 :average-rain         (average (keep :rain measured-values))}

kosecki18:01:29

yeah but this code repeatition, maybe would create fn from defn avg [kw] (average (keep kw measured-values)

ghadi18:01:02

naaah. it's too early to prematurely abstractify

kosecki18:01:26

hmm, might be

ghadi18:01:23

keep it simple. better to use small composable functions. 1 helper (average) then a calculation (the map) made out of core function

ghadi18:01:47

if you abstract in to a fn, then you have a fn that does two things.

ghadi18:01:58

i feel like there should be a corollary to premature optimization is the root of all evil:

ghadi18:01:02

premature abstraction

bradford18:01:14

I've noticed that a lot of my code combines apply / merge / map. I'm building JSON config files. So I map an fn on some values, then combine the many little maps into a big map with apply merge. Is there an elegant way to combine these?

ddellacosta19:01:28

would have to see some examples @bradford

bradford19:01:40

sure. like

{:google_pubsub_subscription (apply merge (create-subs g a-graph))}
and
(defn create-subs [g a-graph]
  (map #(create-sub g % a-graph) (:sinks a-graph)))

kosecki19:01:18

ghadi: the thing you helped me came from here https://github.com/kosecki123/netatmo-parser that's a very first clojure code I wrote

ghadi19:01:44

bradford: I think part of the same advice above to @kosecki applies. There is nothing wrong with assembling a bunch of core functions, though there may be some more idiomatic way to string them together.

ghadi19:01:07

regarding your second function create-subs, all it does is apply a function to a collection

ghadi19:01:41

better to make it a function of an item itself, rather than mapping over the collection

ddellacosta19:01:33

I’m struggling to see how you aren’t clobbering everything at the :sinks key when you do that merge

ddellacosta19:01:33

(and whatever other keys are duplicated)

bradford19:01:37

@ghadi: Good point, though what do you mean 'make it a function of an item itself'? And @ddellacosta, I actually want to clobber the :sinks key. This file format I'm generated wants {:a 1 😛 2 :c 3} instead of [{:a 1} {:b 2} {:c 3}], if that's what you mean?

ghadi19:01:42

Generally if the body of your function is (map some-calculation collection) you should simply make the body the calculation itself

ghadi19:01:19

that way you can consume the calculation elsewhere, unit test it... etc.

bradford19:01:39

Ohhhhhhhh. That does make sense.

ghadi19:01:01

yeah, it adds little value to actually map the function

shriphani19:01:09

Hi, I have been trying to wrap my head around Factual’s durable-queue and I seem to be misunderstanding something. I have 2 async/go-loops - one of these keeps inserting and the other keeps reading from the queue. Is this the wrong pattern? Should I synchronize access to the queues?

bradford19:01:01

@ghadi: I'm sorry -- how do I apply a function to a collection without map? I have the feeling I'm about to slap my forehead here.

ghadi19:01:31

Use map by all means, just don't use it in the body of the function. Move it to the part of the code that consumes this fn

ghadi19:01:40

Just makes that function way more reusable.

bradford19:01:51

Oh! Got it. Thank you! I wish there was a "Ideomatic Clojure Best Practices" kinda thing. I guess equivalent to OOP "Design Patterns", but not as cringe-worthy.

ghadi19:01:52

Imagine you have two transformations that have to happen. If you don't explicitly map the first transformation, you can simply smush them together with comp and then use map.

ghadi19:01:11

Yeah, it's a subtle stylistic point

bradford19:01:53

This should clean things up a bit. Rad. Thanks!

kosecki19:01:52

@bradford: you should definately check the "The Joy of Clojure" book, it contains a lot of great examples

bradford19:01:19

@kosecki: Thanks! I picked up "For the Brave and True" and "Clojure Programming", everyone recommends "Joy" as well.

ghadi19:01:53

the design pattern in question here is sorta "single-responsibility principle". Do one thing (transform an item) rather than N things (transform each item)

bradford19:01:22

Whaaaa I can order "The Joy of Clojure" and get it delivered today. What is this wizardry.

jaen19:01:29

Did someone say "design patterns"? I found this a pretty good read re: that - http://mishadoff.com/blog/clojure-design-patterns/

bradford19:01:29

@jaen: I'm stressed out now remembering all that "Gang of Four" stuff, need rum.

jaen19:01:10

Well it's not GoF's fault that some languages need bandaids for essential functionality : V

donaldball20:01:22

🍰 Congratulations!

Alex Miller (Clojure team)20:01:39

Many thanks to all the contributors!

ghadi20:01:17

Nice going!

bradford20:01:49

YISSSSSSSSSSSSSSSSSSSSSSSSSSSSSssssssssssssssss

jjttjj20:01:05

anyone know of a good example of a non-toy open source thing on github that uses component and has a lot of tests?

jjttjj20:01:24

or i guess any large app using component would be cool

dnolen20:01:42

@cfleming: probably already on your radar but it would be nice if types / records appeared in the Project Structure list in Cursive

danielcompton20:01:13

If I have this code:

(map
   (fn [d] {:group_name (.getGroupId d)
            :jar_name (.getArtifactId d)
            :version (.getVersion d)
            :scope (or (.getScope d) "compile")})
    (.getDependencies model))
and (.getDependencies model) returns java.util.List<Dependency>, should/could Clojure be able to pick up that d is a Dependency? I’m having to typehint the function to avoid reflection warnings, but I wondered if it’s possible to know this without type hinting.

jaen20:01:48

I'd hazard a guess at "no". Generic types are not reified in Java after all.

pguillebert20:01:04

I think type erasure will delete the generic

borkdude20:01:39

would Clojure know it if it wasn't the case? I doubt that also:

user=> (map (fn [s] (.length s)) ["foo" "bar"])
Reflection warning, /private/var/folders/7t/gpzjxhts24d5wvqys1dfvrd80000gn/T/form-init2551413801351333897.clj:1:14 - reference to field length can't be resolved.
(3 3)

jaen20:01:56

PersistentVector isn't even generic IIRC, so that's a bit orthogonal, I think.

jaen20:01:25

And it's also somewhat language-dependent. IIRC Scala does something to ensure you can query and instantiate generic types at runtime.

ghadi20:01:38

borkdude: no it doesn't know. s is a generic parameter

ghadi20:01:31

(memfn ^String length) is another cute way to do this sort of thing, sans reflection.

ghadi20:01:57

But arguably the way you wrote it is more obvious/clean

borkdude20:01:11

@ghadi: would my example be any different from @danielcompton in terms of reflection?

ghadi20:01:35

nope. All he needs to do is tag the arg d with ^Dependency.

ghadi20:01:31

there's very very limited type inference. But typically in my experience, if you hint the argument, then chains of calls within the body infer types properly.

ghadi20:01:50

(map (memfn ^String length) ["foo" "bar"]) was what I was hinting at..

borkdude20:01:05

I understood

jaen20:01:44

Clojure inference is very limited, since it's a dynamic language at core. How can you ensure your vector will contain only elements of a single type at compile-time with Clojure?

jaen20:01:11

If you can't do so, you can't also infer that s will receive arguments of type that have a length method.

borkdude20:01:35

even if you would have a homogenous collection, Clojure would not infer it I think, because of well yeah, type erasure

borkdude21:01:40

these things are hardly pain points, except when you're doing a lot of iterations and need the performance

jaen21:01:48

What I mean is that in Clojure you can't even ensure at compile time that a collection is homogenous.

jaen21:01:24

Well, except by not putting different things in it.

jaen21:01:37

So there's no reliable way to infer that.

ghadi21:01:49

So even if clojure properly infers something at compile or runtime, it still emits casts. Arguments in clojure are either Object or long or double

ghadi21:01:10

(as in, there are checkcasts in the bytecode)

borkdude21:01:13

true. compile and run time are a blended experience in Clojure

jaen21:01:18

Yeah, this also; all Clojure functions are generic over types and there's no monomorphisation in Clojure.

jaen21:01:39

@ghadi: if I understand correctly there's no way to overload over type hints in plain Clojure, yes?

ghadi21:01:54

not sure what you mean

jcromartie21:01:23

no type overloading, period; multimethods and protocols use different dispatch method from fns

jcromartie21:01:45

but the type based dispatch of a protocol is about the best you can do

jaen21:01:45

@ghadi: what I mean is that means (defn whatever [^int arg] ...) (defn whatever [^double arg] ...) is illegal in Clojure, yes?

jcromartie21:01:46

(I could be wrong... I guess it still has to emit casts)

jcromartie21:01:01

it's not illegal, the latter just replaces the former

borkdude21:01:11

@jaen: it's not illegal, but you would overwrite the first with the second 😉

ghadi21:01:14

the former is illegal

jaen21:01:26

Didn't think it was, but that tidbit about about the only three types of arguments seem to mean you can't overload like that.

jaen21:01:46

Hah, yeah, right, of course it would overwrite the def '

borkdude21:01:50

@jaen: but if you write an overloaded arity function like (fn ([x] ....) ([x] ....)) then you'll get an error

ghadi21:01:50

I wrote the patch to make it illegal a couple years ago. 😃

ghadi21:01:11

CompilerException java.lang.IllegalArgumentException: Only long and double primitives are supported... compilig...

ghadi21:01:21

you didn't try it in the REPL 😉

jaen21:01:34

Yes, I didn't; I kind of assumed I can typehint int ; d

jaen21:01:05

Didn't need to write any performance-sensitive code so far so don't know typehinting ins&outs.

ghadi21:01:19

regarding typehints, if you hint ^Dependency as the argument, it changes nothing about the signature of the compiled code. It's still an Object parameter

ghadi21:01:50

the typehint is only for hinting later instance method invocations

ghadi21:01:54

in the body

borkdude21:01:04

yes, you can pass anything you want still

jaen21:01:18

> it changes ​nothing​ about the signature of the compiled code. It's still an Object parameter Yeah, that was basically the intent of my question - if the type signature of the method stays the same you can't overload.

ghadi21:01:52

(shit will fail with a ClassCastException later in the body when you use the arg if it's the wrong hint)

ghadi21:01:20

those are the only signatures allowed for functions ^

jaen21:01:10

Seems the dodo bird is not extinct after all : D

jaen21:01:17

Oh, just poking fun at the names, nothing much.

jaen21:01:49

Anyway that's an interesting thing to be aware of that typehints are just basically casts.

borkdude21:01:16

@ghadi: this just works:

borkdude21:01:20

((fn [^String s] (str s 1)) 1)

ghadi21:01:24

yeah you can typehint conflicting things on different branches.

ghadi21:01:57

@borkdude: that's correct. you can typehint any subclass of Object, but the signature of the method is still Object

ghadi21:01:07

Regarding primitives, only long or double

borkdude21:01:33

@ghadi: but nothing fails because of a cast. or is it only casted when doing interop?

ghadi21:01:14

args only casted when you either call an instance or a static Java method

ghadi21:01:41

str handles the Long argument just fine.

ghadi21:01:58

but had you done .length, you'd have a CCE

ghadi21:01:28

it remains to be seen how Clojure will handle Value Types when they arrive (probably Java 10).

ghadi21:01:44

Because there will be a combinatorial explosion of "primitives", not just long/double

bradford21:01:29

Is https://github.com/clojurewerkz/titanium still being updated, or should I seek out something else for Graph-y Database-y things?

bradford21:01:15

I don't really need a database per se, just graph creation + query language

bradford21:01:19

it's all in-mem

cfleming21:01:31

@dnolen: Yeah, definitely - there’s a bunch of stuff missing from the structure view right now (e.g. multimethod implementations)

bradford21:01:45

Right now I'm using Loom, which is v. cool but doesn't let me write queries, just traverse.

borkdude21:01:16

@bradford: what about Datomic

bradford21:01:48

@borkdude: I think I need something a bit more graph-y, so I can answer questions like "Give me all nodes with in-degree 2 with :label 'user'"

jaen21:01:23

I think you can do graph-y stuff with query functions - https://hashrocket.com/blog/posts/using-datomic-as-a-graph-database - but not sure if that's good enough for you.

rickmoynihan22:01:42

@bradford: Might not be what you're looking for but there's always RDF and SPARQL... You can express precisely that kind of thing with a SPARQL property path ( https://www.w3.org/TR/sparql11-property-paths/ ) - http://rdf4j.org/

rickmoynihan22:01:15

@bradford: rdf4j has in memory (and disk backed) sparql repositories too

martinklepsch22:01:31

@bradford: this is very low level but maybe that's what you want: https://github.com/thi-ng/trio/ ?

ghadi22:01:30

Speaking of graphs, I would really like an ad hoc in memory graph-like heap, similar to what @bbloom has been ranting about

ghadi22:01:48

(on his episode of the Cognicast)

ghadi22:01:06

the only problem with STM is that memory isn't reified

ghadi22:01:13

like it is in Datomic

ghadi22:01:30

I can't grab a reference to a heap as a value

ghadi22:01:49

I think this will become super important with non-volatile memory

ghadi22:01:38

But it has practical applications: Most of writing a compiler is creating graphs and trees

ghadi22:01:58

some hybrid heap/datomic thing would be ideal for that

ghadi22:01:15

just shooting from the hip

rickmoynihan22:01:50

@ghadi: agreed... that would be pretty sweet

meow23:01:13

@ghadi: I like the way you think.

ghadi23:01:30

you'd like @bbloom a lot more 😃 immutable heaps makes GC interesting.

jaen23:01:29

Dang, were it a blogpost to read, immutable heaps sound really interesting

bbloom23:01:07

@ghadi I’m sloooowly but surely working on it

ghadi23:01:48

you can always peer pressure @bbloom to write a post... but then it takes him away from being the fucking Nostradamus of the community

jsa-aerial23:01:28

Re: Clojure 1.8, is direct linking always 'on' or on by default (with a global switch to toggle it)? Putting ^:redef on everything if dereferencing behavior was wanted isn't too scalable...

ghadi23:01:36

direct linking is on for the clojure jar, but it's off by default for your application

jsa-aerial23:01:17

OK, sounds good, but I guess that begs the question then of how to turn it on?