Clojurians
#clojure
<
2018-02-06
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

hagmonk00:02:51

defprotocol generates an interface - I've implemented that interface via gen-class, but the protocol machinery refuses to acknowledge it has been implemented. This seems to be in conflict with the docs: https://clojure.org/reference/protocols

hagmonk00:02:04

Anyone know if there's a trick here?

hagmonk00:02:52

eh, scratch that, it's just that f-ing bug where protocols lose their mind if you re-evaluate the namespace containing the protocol.

qqq07:02:01

for unit testing modules, is there a consensus on whether: option A = test defn and defn- OR option B = only test defn, don't test defn- ?

dominicm07:02:26

I would certainly hate it if exceptions were wrapped, so you will find no disagreement from me here.

suryapjr07:02:55

Hi people im new to clojure !

andy.fingerhut07:02:09

Welcome! I hope you find it as much a pleasure to use as we do

curlyfry07:02:30

Hi! #beginners is a great channel for newcomers.

synthomat08:02:38

G’day! Does someone know how to make clj-files loaded with load-file see the default classpath of clojure?

synthomat08:02:47

I load a clj-file outside of my sources and for every require it complains about not being able to find classes…

synthomat08:02:03

i tried using binding with *ns* which basically injects everything from the calling file, but then I’m still unable to load more dependencies from the loaded clj-file

synthomat08:02:00

oh whatever, works now… :face_with_rolling_eyes:

schmee09:02:07

how can you check whether a number is a primitive type?

schmee09:02:25

I think something’s wrong with my type hints and I don’t have a good way to check what’s going on

leonoel10:02:48

@schmee a good way to check what's going on with boxing is to look at the generated bytecode

schmee10:02:14

that’s what I’m doing now but it’s 1000 lines of bytecode, and I’m not a fluent reader yet :wink:

schmee10:02:43

I’ll try to make a more minimal example later, just wanted to know if there was a functions like primitive-int? or something

bronsa10:02:07

and it couldn't exist

leonoel10:02:00

because clojure functions only understand objects ?

bronsa10:02:27

and because the compiler will auto box/unbox as needed by the function call

schmee10:02:05

that makes sense

kauko10:02:31

Anyone used clj-gatling? I'm wondering whether it has support for assertions.

dominicm11:02:27

Exception in thread "main" java.io.IOException: No such file or directory, compiling:(clojure/core/specs/alpha.clj:1:1), compiling:(myapp/somewhere/core.clj:1:1) I'm getting this when running (compile 'myapp.somewhere.core) which is confusing, especially as I can do (require 'clojure.core.specs.alpha). Any hints?

dominicm11:02:49

Resolved my mkdir classes

schmee16:02:33

can I store a primitive long in a record?

schmee16:02:42

I have this snippet:

(defrecord Foo [^long x ^long y])

(defn foo []
  (let [f (->Foo 1 1)
        x (:x f)
        y (:y f)]
    x))

schmee16:02:02

using no.disassemble, I see this:

Local variable table:
        [pc: 31, pc: 120] local: f index: 0 type: java.lang.Object
        [pc: 73, pc: 120] local: x index: 1 type: java.lang.Object
        [pc: 117, pc: 120] local: y index: 2 type: java.lang.Object

schmee16:02:27

is the type not preserved through field access?

greg31616:02:01

I think you’d need (.x f) to do a field access - using the keyword is going to call (.invoke :x f) and I don’t think the compiler can know that this is a primitive field on f when you’re doing it via the keyword function

schmee16:02:10

that does the trick, thank you!

bronsa16:02:45

@schmee only long and double tho, like in function args

schmee17:02:27

more stupid questions: even when I have type-hinted the return type of a function to Foo, the value returned is still listed in my local variables table as a java.lang.Object, and there is a checkcast instruction to Foo before each field access. Would it be possible to give it the right type directly in the table and avoid these checks somehow?

schmee17:02:33

time for the most annoying question in the world: why?

bronsa17:02:06

because the clojure compiler doesn't do optimizations

bronsa17:02:12

simple as that

bronsa17:02:19

there's no technical reason

bronsa17:02:50

in fact, t.e.jvm does avoid those checkcasts and stores the items typed

bronsa17:02:53

there is one difference tho

bronsa17:02:08

if you do that, type hints become type decls

bronsa17:02:27

i.e. in clojure ((fn [^String x] x) 1) is valid, not in t.e

hiredman17:02:37

yes, I was going to say the other way to look at is type hints effect usage sites not storage locations

bronsa17:02:52

unless they're primitive type hints

bronsa17:02:54

:upside_down_face:

hiredman17:02:51

(let [x ...] (if ... (.foo ^A x) (.bar ^B x)))

schmee17:02:34

@bronsa ahh ok, so if they became type decls things would fail to compile instead of giving runtime errors?

bronsa17:02:07

you'd get a runtime classcast exception when trying to invoke the function / instantiate the type with the wrong object

bronsa17:02:53

sometimes it would cause a compile time exception rather than a runtime one

bronsa17:02:03

but little practical difference

schmee17:02:31

aight, thanks for the explanation

tanzoniteblack17:02:13

@kauko we make use of clj-gatling in a rather limited capacity, but it kinda has support for assertions? If you use assertions, it will count everything that fails as an error due to an exception being thrown, but what you really want is to just return the check you used in the assertion to clj-gatling for it to know whether it was a success/failure. i.e. instead of doing (assert (= (:status (my-api-call)) 200)) have the function you're using with clj-gatling just return the (= (:status (my-api-call)) 200)

noisesmith18:02:25

the protocol doesn't lose its mind, you create two protocols with the same name

lee.justin.m19:02:04

in core.async, is there an nice way to run a bunch of asynchronous (i.e. channel returning, like cljs-http for example) in sequence? I’m have a sequence of data that needs a single remote call per element in the sequence, and what I’m doing now is a loop-recur inside a go block. it works, but it feels gross

lee.justin.m19:02:06

example might help:

(defn register-files
  [files]
  (go
    (loop [file-ids []
           files files]
      (if-let [file (first files)]
        (recur (conj file-ids (<! (register-file file)))
               (rest files))
        file-ids))))

jrootham19:02:34

Has anyone seen "This ResultSet is closed" errors from heroku (or anywhere else)? I am using jetty with with-db-connection. I have one instance that works and other (more recent) instances that fail on updates.

lee.justin.m19:02:13

@joelsanchez thanks. i think that will fire off all of the async calls at once and then wait for them, right? I’m looking to control the degree of concurrency (in my example, i block until each one returns, but eventually I’d like something more sophisticated, like what the bluebird library gives me in JS)

joelsanchez19:02:26

@lee.justin.m

joelsanchez19:02:40

(defn get-file-id-async [id]
  (go {:id id
       :result (+ 1000 id)}))
(go (println (<! (let [ids [1 2 3 4]
                       channels (map get-file-id-async ids)
                       merged (clojure.core.async/merge channels)]
                   (clojure.core.async/into [] merged)))))

joelsanchez19:02:44

try it in a repl

joelsanchez19:02:19

to control the degree of concurrency use pipeline

joelsanchez19:02:37

of course you could also just merge some of the channels, take from the resulting channel, then merge some more channels....

joelsanchez19:02:28

into takes all of the messages from the channel, merge merges the results from the channels you give to it

lee.justin.m20:02:23

thanks that’s helpful. some combo of merge and pipeline will surely do what i’m looking for

noisesmith20:02:02

the most common cause of this error is using the data outside of the context of the connection - this can happen with laziness especially

mv21:02:57

Hey, I’m trying to pick a clojure stack for an API backed by Datomic. I’m looking at compojure, liberator, and pedestal. Any advice or articles about picking one? Is liberator still supported/recommended?

mv21:02:46

I should also say I plan on putting a cljs frontend in front of it, so an EDN communication seems ideal

joelsanchez21:02:48

not EDN but you could use chord and communicate with fressian...keeps clj data structures

mv21:02:58

Interesting

andy.fingerhut21:02:09

Is it still true that with fressian you can put Clojure immutable sets in one end, and get Java mutable sets out the other? https://dev.clojure.org/jira/browse/DFRS-5

greg31621:02:55

I think transit/json is more common than fressian for front-end communication

joelsanchez21:02:32

gosh...was thinking about transit. fressian is a bit overkill :stuck_out_tongue:

greg31621:02:34

if you want a binary encoding I’d go with CBOR, which is based on an open standard

andy.fingerhut21:02:35

If so, that interacts poorly with Clojure hash function in 1.6 and later, where even though immutable and mutable sets are = using clojure.core/=, they have different hash codes, so using them as elements of other sets, or keys in hash-maps, leads to bad results.

greg31621:02:07

you could get the best of both worlds with content negotiation - pass Accept: application/edn when you’re poking the API by hand, and Accept: application/cbor (or transit+msgpack, or whatever) when you want efficiency

joelsanchez21:02:39

tbh in my own app I ended up using a custom json format to allow keeping sets and vectors...to be able to read the frames in the Chrome WS "frames" view (readable only with json)...to debug WS

andy.fingerhut21:02:16

I haven't used transit before -- I'd guess it maybe does better at preserving immutability in sets, maps, vectors, lists, etc.?

hiredman21:02:57

@andy.fingerhut

user=> (type (fress/read (fress/write #{})))
java.util.HashSet
user=> 

hiredman21:02:51

you can add your own custom tag handlers, so you could have fressian decode sets to immutable sets

andy.fingerhut21:02:22

Just seems like a really odd default, especially an intentionally chosen one after it is pointed out, for "value of values" kinds of folks.

andy.fingerhut21:02:38

But it probably makes more sense given more background, and/or backwards compatibility constraints.

greg31621:02:54

https://github.com/greglook/clj-cbor is better-behaved than that by default :slightly_smiling_face:

greg31621:02:31

transit+json does have the advantage that you can poke around in the response data using most browser consoles out-of-the-box

alexmiller21:02:28

if you’re going from clj to cljs, transit is far and away preferred over fressian

alexmiller21:02:38

json decoders in js are highly optimized, and transit caching and compression means transit over json can be substantially faster than json itself

andy.fingerhut21:02:05

Does it preserve immutable collections by default?

andy.fingerhut21:02:54

or maybe preserve is the wrong word -- does the reader create immutable collections by default?

alexmiller22:02:19

the cljs transit reader will create cljs data structures, so yes

alexmiller22:02:53

or rather, it creates something that conforms to the transit interfaces which I assume is cljs data structures, but I have never actually used it myself

alexmiller22:02:04

ok, looked at the code - creates cljs data structures

mv22:02:30

I’m not seeing any documentation about moving Vase from being backed by in-mem Datomic to a proper datomic backend.. is that an uncommon use case?

andy.fingerhut22:02:21

Just did a quick check with Clojure/JVM, and without me using any special settings the reader returns immutable maps, vectors, and sets. Nice.

andy.fingerhut22:02:37

(the transit-clj reader, that is)

andy.fingerhut22:02:14

Even when one of the objects written into the stream was a java.util.HashSet, it came back as clojure.lang.PersistentHashSet

alexmiller22:02:43

I think it’s probably just not doc’ed. what would be different than just using a different datomic uri?

mv22:02:47

I believe that you are right, it’s just a URI at the top of the *_service.edn