Fork me on GitHub
#clojure
<
2020-04-28
>
coby03:04:45

Anyone know of a good drop-in replacement for the standard GraphiQL GUI that parses EDN? I'm sure I could toss something together with ClojureScript, but figured I'd ask.

Spaceman05:04:15

Is there a more concise way to write this function? (filter #(if (some? (second %)) %) {:foo nil :bar 89})

adi05:04:02

(filter (comp not nil? val) ...)

seancorfield05:04:47

Better to use some? instead of not nil?

seancorfield05:04:08

But, yes, better to use val than second when dealing with map entries.

seancorfield05:04:06

@U010Z4Y1J4Q This really feels like a question that is better suited to the #beginners channel where people have opted-in to help with basic questions like this...

adi05:04:15

Ah, some? ... I didn't remember it. Yes, this would be cleaner: (filter (comp some? val) ...)

seancorfield05:04:43

@U051MHSEK The OP mentioned it in their question.

adi05:04:04

I misread it as some and that just shows me what happens if I haven't written Clojure in a while ¯\(ツ)

seancorfield05:04:54

And another reason why questions like this belong in #beginners rather than #clojure ...

👍 4
seancorfield05:04:13

@U010Z4Y1J4Q I've added you (back) to the #beginners channel.

zane18:04:51

I wonder if #beginners is misnamed.

zane18:04:13

It’s an attribute of the questioner, not the question.

seancorfield18:04:39

Happy to discuss potential renaming in #community-development but we try to rename channels only very occasionally (since channel names are often documented out in the wild and it's confusing if someone comes here and those documented channels no longer exist).

4
zane19:04:56

Makes sense!

Spaceman05:04:33

Basically what I want is to return a map that contains only the key value pairs that are non-nil {:bar 89}. It doesn't have to a list of vectors of key-value pairs ([:bar 89]) as in the result of the above example.

Spaceman06:04:31

I have this following idiom in my code:

(deftest my-test
   (run-test-sync
       (is (= 1 2)) ;; etc.
   )
And it seems like a good idea to create a macro which would replicate this like so:
(deftest-sync my-test
   (is (= 1 2))
)
And I have tried this:
(defmacro deftest-sync [name test]
  `(deftest ~name ~(run-test-sync ~test))
  )
But on doing :
(macroexpand '(deftest-sync some-test (is (= 1 1))))
I simply get the result:
(deftest-sync some-test (is (= 1 1)))
What am I doing wrong?

Ben Sless07:04:56

You unquoted twice, you don't want to unquote the entirety of the run-test-sync. Should probably be

(defmacro deftest-sync [name test]
  `(deftest ~name (run-test-sync ~test)))
(note the missing tilde)

Spaceman07:04:31

That still gives (deftest-sync some-test (is (= 1 1))) on macroexpand

Ben Sless07:04:01

Are you sure? I just tried this in the repl:

user=> (defmacro deftest-sync [name test]
  #_=>   `(deftest ~name (run-test-sync ~test)))
#'user/deftest-sync
user=> (macroexpand '(deftest-sync some-test (is (= 1 1))))
(user/deftest some-test (user/run-test-sync (is (= 1 1))))

Spaceman07:04:56

yeah, I'm sure. Could it be because it's a cljs repl?

Ben Sless07:04:18

I wouldn't know, never worked with cljs

Spaceman07:04:19

Yeah it's working in the clojure repl but not in the clojurescript repl

Spaceman08:04:16

bug in the repl or in cljs itself?

Spaceman08:04:23

actually it woks now

Spaceman08:04:37

However, the macro doest seem correct

Spaceman08:04:33

(deftest my-test (run-test-sync (is (= 1 1)) (is (= 2 1)) ) ) evaluates to #'mytest

Spaceman08:04:37

But (deftest-sync my-test    (is (= 1 1))    (is (= 2 1))       ) evaluates to (deftest nil nil)

valerauko10:04:42

can someone explain me the reason having definterface and deftype inside a do in the repl won't work? i have to deal with a macro that generates something like (numbers all gensyms)

(do
 (def foo)
 (do
  (definterface G__49771 (invoke [G__49772]))
  (deftype foo49770 []
   G__49771
   (invoke [_ G__49772]
     (let [bar G__49772] bar))))
 (let
  [G__49769 (new foo49770)]
  (defn foo {}
    ([G__49773]
     (.invoke G__49769 G__49773)))))
this dies on the repl at deftype saying,
Syntax error compiling deftype* at (/tmp/form-init6201477943960772507.clj:7:3).
Unable to resolve symbol: G__49771 in this context
it works if i compile/run the code. i can also get it to work manually in the repl if i remove the dos. how could i get this to work in the repl?

bronsa10:04:56

it works here on the repl

bronsa10:04:02

which repl are you using?

bronsa10:04:32

if you're using some fancy repl that wraps input commands somehow, that would explain it

bronsa10:04:00

as it would prevent the unwrapping of do that clojure does for toplevel dos

valerauko10:04:40

i was starting a headless lein repl and connect to it from atom with clojure party repl

valerauko10:04:55

and indeed, going directly into a lein repl, it really does work

bronsa10:04:56

ok, I don't know what that is but it sounds like this is what's happening

valerauko10:04:08

thanks! it sure is...

valerauko10:04:48

gonna debug this more and try filing a bug report with the plugin

valerauko10:04:20

everyone on the team uses the same setup so we were all getting the same errors...

valerauko10:04:21

thanks again!

bronsa10:04:53

a minimal repro should be just (do (deftype A []) A) FWIW

💯 4
Michael J Dorian14:04:57

Hey friends, I've got a plan to tackle a problem but I'd like to have a better plan, if one exists. I've got a string, and the string represents clojure code. I need to remove all the line endings from this string, without altering the compiled value of it. It will always be a hashmap, starting with { and ending with }. I would just do (str/replace string #"\n" ""), but that breaks when the map contains ;comments, and alters the value of string literals So what I'm thinking of doing is making a loop that loops over each char in the string and removes newlines UNLESS they terminate a ;comment, OR if they're inside a string literal. Ofcourse ;comments don't count if they're in a string literal, and string literals can't start inside a comment. Is this a good plan? It feels like a not-great plan, but I'm stumped for other options. Thanks!!

Kevin14:04:11

Is it important to preserve the comments?

Michael J Dorian14:04:17

Yes, unfortunately. I'm doing some code formatting, and I wasn't able to remove newlines with rerwite-clj

dominicm14:04:24

@doby162 I'd use parcera

dominicm14:04:39

You can match whitespace nodes, and remove newlines from the string in them.

dominicm14:04:40

You may need to match the comments too, I can't remember if the ast distinguished or not, but it'll make it easier for sure.

Michael J Dorian14:04:18

Well, thanks! I'll give this a try. Also, if anyone happens to know that this Should have actually been easy with rewrite-clj, let me know! It seems to skip whitespace, so far as I can tell

dominicm14:04:49

There's definitely some way to get rewrite to do this, but I think parcera is more ergonomic.

Michael J Dorian14:04:41

simple_smile thanks a bunch, I had a feeling plan-a wasn't going to be the best

ghadi14:04:43

if you have a string with clojure forms in it, consider reading the forms, then prning them to a file, then running a source code formatter on the file

ghadi14:04:59

reading as in clojure.core/read

Michael J Dorian15:04:46

Ah, a code formatter is what I'm trying to do!

dominicm15:04:39

Yeah, clojure core doesn't have a good facility for that due to dropping comments

dominicm15:04:05

I wrote my code formatter with parcera and enjoyed it

👍 4
👀 4
arnaud_bos15:04:37

Out of curiousity I just too a look at parcera, I'm curious about this line: https://github.com/carocad/parcera/blob/master/src/Clojure.g4#L34 Seems like this will parse odd "inputs" without an issue whereas maps should be key-value pairs, am I right? I don't have experience with antlr.

Michael J Dorian15:04:23

Luckily in my case I'm not responsible for the correctness of inputs... I just need to not break the code 😁

Michael J Dorian15:04:41

rewrite-clj will object if you attempt to make a hashmap with an odd number of forms though

arnaud_bos15:04:42

Yeah, right. I'm asking especially because I took the tools.reader wrapper path in a current side project especially because I needed something like '{' input* '}' inside maps and neither tools.reader nor rewrite-clj allowed it. I overlooked antlr as too complex but looking at parcera I feel like stealing the g4 file would work and allow me to remove 80% of my code...

parrot 4
Ramon Rios16:04:45

Expected:
"CREATE TABLE test_table (some_column varchar(255), oth
er_column varchar(255) CONSTRAINT constraint_name UNIQUE KEY (`some_column`,`other_column`))"
Actual:
"CREATE TABLE `test_table` (`some_column` VARCHAR(255),
 `other_column` VARCHAR(255)) CONSTRAINT `constraint_name` UNIQUE KEY (`some_column`, `other_column`)"
Folks, i'm trying to add the constraint statement inside the parentheses, intead of have ou of it, as have in expected. Do you folks have any insight of how can i do it?

Ramon Rios16:04:37

(let [base-sql (str "CONSTRAINT " (ddl/escape-identifier ddl name))
        cons-sql (clojure.string/join ", " (map #(ddl/escape-identifier ddl % ) columns))]
    (str base-sql " " type " (" cons-sql ")"))
That's the current code i did for it.

lukasz16:04:49

If it's an option, I'd suggest looking at HugSQL https://www.hugsql.org - it has built in ways of passing identifiers etc

Ramon Rios16:04:20

We already use another implementation. Once i'm expanding a existent library, probably not going work on it now. But thanks for the suggestion

Ramon Rios16:04:59

(defn join-string 
  [query specs]
  (let [count (-> (count query) (- 1))] 
      (-> (subs query 0 count)
          (str " " specs ")"))))
Found a way to do this. Hope it's not a McGayver solution

noisesmith17:04:53

using count to bind something called count is a bit odd

noisesmith17:04:16

perhaps (let [length (dec (count query))] ...) or (-> query count dec)or whatever

daniel.spaniel17:04:58

is there a nice and friendly way in clojure to convert from scientific notation 1.87E+5 to 187000.0 ? i really want the bigint 187000 .. but any longer version will do

Alex Miller (Clojure team)17:04:47

both are different representations of the same number

Alex Miller (Clojure team)17:04:11

there are ample formatting options for converting from a number to a string in the jdk

daniel.spaniel17:04:32

i will check java formatter then

Alex Miller (Clojure team)17:04:42

full spec is at https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html and this is supported in the clojure format function

Darin Douglass17:04:42

user> (Float/parseFloat "1.87E+5")
187000.0
user> 

Alex Miller (Clojure team)17:04:39

you should typically prefer Double/parseDouble over Float/parseFloat

👍 4
daniel.spaniel17:04:03

will check out that Double/parseDouble

daniel.spaniel17:04:42

same answer .. but what is reason to prefer Double ?

Alex Miller (Clojure team)17:04:08

Clojure decimals are always doubles - Clojure doesn't support java floats

daniel.spaniel17:04:20

gotcha .. good to know

Alex Miller (Clojure team)17:04:05

single precision floats are pretty bad, really only useful if you want something where you are ok with bad precision and trying to shave heap memory

daniel.spaniel17:04:33

whao .. that was far too easy. thanks mate 🙂

Alex Miller (Clojure team)17:04:46

there is also a function to make a bigint

Alex Miller (Clojure team)17:04:47

user=> (bigint 1.87E+5)
187000N

Alex Miller (Clojure team)17:04:03

it's unclear to me what the type of either your input or desired output is

daniel.spaniel17:04:40

gotcha .. yeah .. i need the bigint .. so that one is nice too .. either way .. i have my answer with 2 good ideas

wcohen18:04:47

@abrooks re your question about geo from a while back, happy to answer any questions you have. i just made a new channel called #gis if that’s a useful place to organize conversations — not sure what else is important to do in terms of channel management, or if it’s better to try to encourage discussion on zulip or another platform instead

wcohen18:04:25

development on factual/geo has been pretty limited recently, though i am trying to get it working with cljs now that bundle support is there. i’ve also been working on and off on willcohen/ovid and willcohen/aurelius as libraries that build on top of factual/geo and try to streamline what i do day-to-day with GIS, though as you can see they’re basically still undocumented and haven’t even hit a first release

Alan Thompson19:04:20

Excellent series of videos by Uncle Bob Martin:

seancorfield19:04:50

They don't belong in #clojure but feel free to post them to #news-and-articles (or #off-topic since they aren't Clojure-related, right?)

dabrazhe21:04:13

Hi. What's a more concise way to call (not zero?), this feels too verbose:

(filter (every-pred number? #(not (zero? %)) odd?  #(< % 7)) [0 1 0 2 5 9 0 3 0 4 -1 -2 :a {} ])

dpsutton21:04:43

(complement zero?)

dpsutton21:04:02

not more concise i guess

dabrazhe21:04:46

nope, that's even longer : )

dabrazhe21:04:02

though I am wondering why (complement zero?) works in the filter as is and (not zero?) needs to be wrapped in an anon. function..

nickmbailey21:04:55

complement returns a function, not returns a value

dabrazhe21:04:51

yep, i guessed it's some of this kind of magic 🙂

dabrazhe22:04:12

@U11BV7MTK (complement zero?) wins, there are fewer brackets and therefore it's more readable and less thinking 'wtf had I written a year?' ago : }. thanks

noisesmith22:04:21

sometimes I wish things like partial, complement, comp all had shorter names

noisesmith22:04:44

eg. complement could be ~ or even !

dpsutton23:04:38

Oh I really like that

potetm23:04:48

(def not-zero?
  (into #{}
        (remove zero?)
        (range Long/MIN_VALUE
               Long/MAX_VALUE)))

trollface 8
4
dabrazhe19:04:44

@U051SS2EU I wished for the shorter names as well, especially to use in (comp) and settled on (def pa partial)

nickmbailey21:04:06

well you can just def that to something more concise

Tyler22:04:42

#(not= % 0)

noisesmith22:04:52

you shouldn't use = to check for 0, at least one should use ==, and zero? exists for a reason

seancorfield22:04:14

Quick interop/reflection question: If you have a (Java) object and you know it has a .close method but it does not have a predictable base class or interface you can use as a type hint, is there a way to call the (unique, no-arg) .close method without triggering a reflection warning from (set! *warn-on-reflection* true)?

seancorfield22:04:16

The concrete situation here is that HikariCP and c3p0 both provide connection pooled datasource objects and both have .close methods but their datasource types have nothing in common that has a .close method -- c3p0 has its own PooledDataSource class that implements .close (and that in turn extends javax.sql.DataSource) where HikariCP implements .Closeable (which has .close in it).

seancorfield22:04:29

I'm happy to do actual runtime reflection to find and call the .close method, as long as it avoids Clojure's reflection warning (but I'm looking for some guidance on the simplest code to achieve that).

noisesmith23:04:25

in the past I've used a dispatch to ensure there was only one code-path for each type, eg. you could have a multimethod or protocol where the implementations would look the same except the type hint

noisesmith23:04:58

it might be overly precious to use a macro for this, if it's not a repeating pattern you could even use cond

seancorfield23:04:27

The set of possible input classes is actually open-ended in this case.

seancorfield23:04:14

I have some reflection code that works but it's ugly 🙂

noisesmith23:04:56

in that case you could use a protocol or multimethod and extend it to each thing, clojure won't complain about runtime protocol dispatch

didibus23:04:39

Where they mention the current solutions are multi-methods, protocols or instance? checks

noisesmith23:04:21

yeah, since this is open and not statically knowable, protocol or multimethod actually fit here IMHO

seancorfield23:04:07

No, this has to be self-contained and require no extension by users.

seancorfield23:04:19

So far

(defn- attempt-close
  "Given an arbitrary object that almost certainly supports a `.close`
  method that takes no arguments and returns `void`, try to find it
  and call it."
  [obj]
  (let [^Class clazz (class obj)
        ^java.lang.reflect.Method close
        (->> (.getMethods clazz)
             (filter (fn [^java.lang.reflect.Method m]
                       (and (= "close" (.getName m))
                            (empty? (.getParameterTypes m))
                            (= "void" (.getName (.getReturnType m))))))
             (first))]
    (when close
      (.invoke close obj (object-array [])))))

seancorfield23:04:20

That avoids reflection warnings from the compiler and calls the first 0-arity .close method it can find that returns void.

seancorfield23:04:16

It's so next.jdbc can support Stuart Sierra's Component library without needing it as a dependency in a nice, generic way:

(defn component
  "Takes the same arguments as `->pool` but returns an entity compatible
  with Stuart Sierra's Component: when `com.stuartsierra.component/start`
  is called on it, it builds a connection pooled datasource, and returns
  an entity that can either be invoked as a function with no arguments
  to return that datasource, or can have `com.stuartsierra.component/stop`
  called on it to shutdown the datasource (and return a new startable
  entity)."
  [clazz db-spec]
  (with-meta {}
    {'com.stuartsierra.component/start
     (fn [_]
       (let [pool (->pool clazz db-spec)]
         (with-meta (fn ^DataSource [] pool)
           {'com.stuartsierra.component/stop
            (fn [_]
              (attempt-close pool)
              (component clazz db-spec))})))}))

noisesmith23:04:25

what about an instance? check that special cases c3p0 (grandfathers it in) and demands all other inputs be http://java.io.Closable ?

👍 4
seancorfield23:04:41

(def ds (component/start (next.jdbc.connection/component CPDSClass {:dbtype "..." :dbname "..." ...})))
(next.jdbc/execute! (ds) ["select ..."])
(component/stop ds)

seancorfield23:04:48

I don't know that you can rely on arbitrary connection pooling libraries implementing .Closable and next.jdbc cannot introduce a direct dependency on a specific one (such as c3p0).

seancorfield23:04:42

The joys of writing dependency-free libraries that can behave generically... 🙂

🙂 4
didibus23:04:04

Hum... What about letting the user provide the type hint?

didibus23:04:46

There's something about hidden reflection in a library dependency that seems dirty to me.

didibus23:04:17

Making a GraalVM build will require a big deep dive now for example.

didibus23:04:25

Like what if component let you pass in the close function?

seancorfield23:04:44

Horrible usability.

seancorfield23:04:30

(although I suppose I could default the close-fn to (fn [^.Closeable ds] (.close ds)) and force poor old c3p0 users to override it... not that HIkariCP doesn't also have its own weirdness)

noisesmith23:04:30

or default it to (memfn close)which silently reflects I was wrong, it does reflect

seancorfield23:04:15

I wouldn't be surprised if there are other things that prevented GraalVM binaries to be produced from next.jdbc programs already -- Borkdude is working on JDBC support in Babashka and, so far, has only managed to get PostgreSQL supported -- both MySQL and SQLite seem somewhat incompatible with Graal...

dpsutton23:04:29

Can you just set warn on reflection false above it and then reenable afterwards?

seancorfield23:04:31

@U051SS2EU Oh really? Interesting... let me try that...

seancorfield23:04:25

((memfn close) pool) produces a reflection warning @U051SS2EU

noisesmith23:04:11

yeah - sorry I did edit above

seancorfield23:04:20

@U11BV7MTK That sounds... deliciously horrible...

😂 4
4
didibus23:04:50

Maybe just keep the warning?

didibus23:04:22

What's the big deal? I mean, if you are doing reflection, why not be explicit about it if the user cares to know.

seancorfield23:04:02

@U0K064KQV for folks who set reflection warnings on for their whole build, why should they have to suffer my code producing a warning? Folks create GitHub issues about that sort of stuff. No, just no.

seancorfield23:04:03

@U11BV7MTK That certainly does hide the reflection warning but a) that feels like cheating and b) that's still going to trip anyone who uses Graal, right?

noisesmith23:04:12

gh issue "this code reflects" response "get rid of reflection by providing this arg / extending this multimethod"

didibus23:04:18

I mean I get it, but I'm not a fan of circumventing the warning either. If I set warn-on-reflection it's because I want to know if reflection is happening anywhere in the code, libraries included

seancorfield23:04:46

Right, and it's important to me that my library is "clean" in that respect.

dpsutton23:04:16

Well it seems in line with your intention that you are open to reflection. It’s not a warning it’s intentional

didibus23:04:17

With respect to not be doing reflection? Or not warning about doing it?

dpsutton23:04:31

Could graal people use this regardless of the warning? The reflection will kill them not the warning

didibus23:04:53

It's probably irrelevant in this case, so it might be the right trade off, but what if I was calling component in a hot loop? I know what doesn't sound realistic, but I'm just trying to explain why I kind of don't like it if my dependencies secretly try to hide important aspects from me.

noisesmith23:04:33

actually connecting to a db is so much slower than reflecting on a method though

didibus23:04:46

My personal vote would be, leave the warning, but have a mechanism where the user can get rid of it by say providing the close function or a type hint.

seancorfield23:04:54

If using java.lang.reflect kills Graal then it's a non-starter too... which is moving me closer to @U0K064KQV’s suggesting of optionally passing in the close function at this point

seancorfield23:04:14

(and defaulting it to the .Closeable version)

noisesmith23:04:47

that means you get a runtime crash when the hint doesn't match the impl coming in

didibus23:04:32

Actually, you can use java.lang.reflect, but you need to tell Graal which class needs reflecting over

noisesmith23:04:37

unless you protect it in a conditional branch with an instance? check I guess

didibus23:04:53

So if you document it properly it might be fine as well.

didibus23:04:48

I thought they were hints, because if Clojure compiler doesn't actually find the method on the type it defaulted back to Object?

didibus23:04:42

Though I guess there is the weird case of a connection pooling library that wouldn't have a .close method at all?

noisesmith23:04:27

@U0K064KQV

(ins)user=> (def hinted #(.close ^.Closeable %))
#'user/hinted
(ins)user=> (defprotocol Distance (close [this]) (far [this]))
Distance
(ins)user=> (hinted (reify Distance (close [this] true)))
Execution error (ClassCastException) at user/hinted (REPL:1).
class user$eval202$reify__203 cannot be cast to class .Closeable (user$eval202$reify__203 is in unnamed module of loader clojure.lang.DynamicClassLoader @50a3d0f6; .Closeable is in module java.base of loader 'bootstrap')

noisesmith23:04:15

once you hint, the method is specialized on the class, and other methods with the same signature but different class with crash

noisesmith23:04:07

I discovered this the hard way implementing a setUncaughtExceptionHandler for a kafka stream (that just happened to accept the same types / args as Thread.setUncaughtExceptionHandler without inheriting Thread)

seancorfield23:04:45

Yeah, that's an interesting usability question @U051SS2EU...

didibus23:04:52

Interesting, didn't know that.

seancorfield00:04:43

Thinking about this some more, next.jdbc uses clojure.java.data for the connection pooling stuff which is full of explicit Java reflection stuff... So I'm worrying too much about this since ->pool already depends on the java.lang.reflect stuff!

seancorfield00:04:08

So I've gone back to this

(if (isa? clazz .Closeable)
                (.close ^.Closeable pool)
                (attempt-close pool))
where attempt-close is the java.lang.reflect-based thing above.

seancorfield00:04:21

Thank you everyone for your input on this. I guess allowing users to pass in their own close-fn might also be worthwhile just to deal with connection pooling libraries that don't even have a .close function...

noisesmith00:04:10

there's also this if you don't otherwise need to extract the class

(instance? java.lang.CharSequence "hi")
(which becomes Closeable/ pool of course)

noisesmith00:04:13

the rest of clojure is so unbelievably consistent, the difference between isa? and instance? arg order sticks out

seancorfield00:04:32

Yeah, it caught me out when I tried it half an hour ago -- the way next.jdbc.connection/->pool works is that it already takes a Class so I'm using that to provide the default close-fn before creating the pool instance.

jaihindhreddy03:04:25

extension via metadata to not depend on the component lib. Cool!

seancorfield03:04:18

It all started as yak shaving due to Jacob O'Bryant's announcement of his Component alternative which inspired me to remove a record from a Component at work and then I started thinking about next.jdbc 🙂

👍 4
potetm23:04:29

wrap the call in a protocol? does that work?

noisesmith23:04:37

I suggested that or multimethod in the thread above, I don't think he liked the idea