clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
zendevil 2021-03-12T06:30:13.047600Z

I’m doing a db query using the monger library like so:

(q/with-collection db "videos"
             (q/find {})
             (q/sort {:date 1})
             (q/paginate :page page :per-page 5))
However, when I do page 1, I get the following ids:
("6011a14028dacb0004d7475c"
"6011a1ea28dacb0004d7475d"
"60119fe128dacb0004d7475a"
"602a15665273b0b82c3ded1c"
"6011a0b428dacb0004d7475b")
when I do page 2, I get these:
("6011a14028dacb0004d7475c"
"60119fe128dacb0004d7475a"
"602a15665273b0b82c3ded1c"
"6011a0b428dacb0004d7475b"
"60124ed4afa8e90004ab71a0")
The problem is that there’s an overlap of ids between the two pages. I expect the pages to show ids with no overlap. How to fix this?

svt 2021-03-12T08:23:40.048400Z

What would you suggest for using Graphql in Clojure?

agile_geek 2021-03-12T08:31:04.048500Z

Take a look a Lacinia

agile_geek 2021-03-12T08:31:28.048700Z

https://github.com/walmartlabs/lacinia

borkdude 2021-03-12T12:14:15.050200Z

@nilern About yesterday's discussion: I guess Clojure has the same kind of issue but smaller in scope and more apparent to a user who defines things with proxy:

user=> (ifn? (proxy [clojure.lang.APersistentMap] []))
true
So the predicate returns true, while at runtime you will get an UnsupportedOperationException when trying to call it as a function

nilern 2021-03-12T12:35:42.050400Z

Oh. But much more tolerable since it is so rare and already annoying to have to use proxy.

borkdude 2021-03-12T12:39:38.050600Z

yeah, and the scope for which this will give "false" positives is much smaller

restenb 2021-03-12T12:42:22.052Z

puzzle: given a vector of vectors like [[1 5 3][4 10 35 9][2 7 19]], I want to pick the one that contains the highest single value. In this case, it would be [4 10 35 9]since 35 is the highest number in any of the vectors.

Joe 2021-03-13T15:30:51.093900Z

How about

(last (sort-by #(apply max %) [[1 5 3] [4 10 35 9] [2 7 19]]))

restenb 2021-03-12T12:42:59.052500Z

there are ways to do it with a couple of let-bindings and .indexOfat the end, but ...

javahippie 2021-03-12T12:51:16.052600Z

javahippie 2021-03-12T12:51:19.052800Z

Definitely not the most optimized version

simongray 2021-03-12T12:56:00.053Z

this is mine - also not really optimised. It does handle the case that there can be more than 1 vectors to return, though.

(defn max-vecs
    [coll]
    (let [n (apply max (flatten coll))]
      (filter (partial some #{n}) coll)))

👍 1
simongray 2021-03-12T12:57:13.053200Z

or the code golf version:

(defn max-vecs
    [coll]
    (filter (partial some #{(apply max (flatten coll))}) coll))

borkdude 2021-03-12T13:12:42.053600Z

@restenb

user=> (max-key #(apply max %) [1 5 3] [4 10 35 9] [2 7 19])
[4 10 35 9]

borkdude 2021-03-12T13:13:37.054100Z

beware of empty collections, since max requires at least one arg

👆 2
borkdude 2021-03-12T13:13:55.054200Z

https://clojurians.slack.com/archives/C03S1KBA2/p1615554762053600

👍 1
1
simongray 2021-03-12T13:17:25.054600Z

TIL max-key @borkdude

➕ 1
borkdude 2021-03-12T13:18:06.054800Z

Weird naming

simongray 2021-03-12T13:18:11.055Z

indeed

restenb 2021-03-12T13:30:52.055200Z

thanks for all the replies guys! I didn't know about max-key either, that one is quite elegant.

vanelsas 2021-03-12T13:41:29.055400Z

Late to the party, this takes the input as requested and delivers the output too (not optimised)

(defn max-vec [v] 
  (let [res (map #(vector (apply max %) %) v)  
        m (into {} res)] (get m (apply max (keys m)))))

Jeremy Cronk 2021-03-12T15:34:09.062300Z

I have a weird issue coming up when I try to test a generated class that uses a gen-interface. The interface has a method that’s overloaded a few times, but the one in question is supposed to take and return a string. If I go into the REPL and create an instance of the class, then call the method with a string, everything’s totally fine and it gives me the right result. But for some reason when I run a test that does, as far as I can tell, the exact same thing, I get an AbstractMethodError and it’s saying giving the method signature as (Ljava/lang/String;)Ljava/lang/String, which I don’t understand at all. Maybe this is my inexperience with Java showing, but I just don’t understand what it’s doing differently between the test and calling it from the REPL. Is there something obvious going on here that a Java person might pick up on immediately?

2021-03-12T15:36:56.062400Z

that L prefix means it wants an array of string, which can be implicit if the method takes varargs

2021-03-12T15:39:08.063Z

you probably need to share your code (or a simplified version), but another issue is that gen-interface doesn't reload like normal clojure code, so your repl might not reflect the current code even if you reloaded the code

Jeremy Cronk 2021-03-12T15:40:47.064Z

Hm, okay. I don’t have my Leiningen REPL set up right, so it doesn’t reload correctly and I always end up exiting it and starting it again when I try testing it like this.

Jeremy Cronk 2021-03-12T15:43:36.065Z

My entire gen-interface is here:

(gen-interface
  :name XSLTTransformer
  :methods [[transform [java.io.File java.io.File] void]
            [transform [javax.xml.transform.Source java.io.File] void]
            [transform [java.io.File] String]
            [transform [javax.xml.transform.Source] String]
            [transform [String] String]
            [updateConfiguration [java.util.Map] void]
            [getConfiguration [] java.util.Map]
            [setConfiguration [java.util.Map] void]])
I have the signature set as String, so I don’t get why it would be looking for an array of strings

2021-03-12T15:44:15.065200Z

also gen-interface is a weird corner of the language, I've never needed it, there could be gotchas that I'm unaware of still. what's your use case - you need java code to use your lib via an interface?

2021-03-12T15:45:05.065400Z

or a java lib is written such that it takes an interface as a parameter?

raspasov 2021-03-12T15:45:36.065600Z

Safe version (also makes sure the original input vector is not empty, which also fails.

(when-let [coll (not-empty (remove empty? [[1 5 3][4 10 35 9][2 7 19]]))]
  (apply max-key #(apply max %) coll))

2021-03-12T15:46:04.065800Z

I don't see how any of those methods would end up taking or returning an array

Jeremy Cronk 2021-03-12T15:46:11.066Z

Well, I ended up creating this in a Java-ish way, but basically I have two XSLT transformers that I need to wrap with a consistent API that will be used from Java.

borkdude 2021-03-12T15:46:29.066200Z

You can also fold the empty? check into the predicate

2021-03-12T15:49:31.066500Z

I have a hunch this would be much easier using a gen-class, plus a implementation object that extends a clojure protocol

2021-03-12T15:50:00.066700Z

(in clojure land, each instance of the object would own as member data an implementation of the protocol)

Jeremy Cronk 2021-03-12T15:50:06.066900Z

Oh, okay, something weird is happening because I’m trying to delegate. This is probably a stupid approach, but I didn’t have a lot of time to get it done. Basically there are two gen-classes that implement the interface and then there’s a third class that implements the interface and uses its constructor to choose one of the other two classes to delegate to.

Jeremy Cronk 2021-03-12T15:51:25.067100Z

Ah, okay, so I’d want a protocol like “Transformable” or something, then define the methods from there?

2021-03-12T15:51:27.067300Z

right, you can still do the delegation with protocols, but protocols play nicer with the rest of clojure I think -the big gotcha here is that protocols don't differentiate methods for dispatch based on type, only name plus arg count

2021-03-12T15:51:47.067500Z

(I don't have proof that gen-interface doesn't have the same issue...)

borkdude 2021-03-12T15:53:33.068200Z

Is there an example of an abstract class in the Java stdlib that takes arguments in the constructor?

Jeremy Cronk 2021-03-12T15:53:52.068300Z

Interesting, thanks. I’ll have to reread the documentation for protocols - I’ve used them a bit, but I don’t have the experience to necessarily know when/why to use them. I still need to figure out what’s going wrong with my delegation for now, but what you’re suggesting seems like a better direction that’s more Clojure-ish.

2021-03-12T15:56:40.068500Z

the docs say that if you aren't compiling gen-interface is a no-op, are you using a separate aot step?

Jeremy Cronk 2021-03-12T15:57:10.068700Z

Yeah, I have the classes set to aot in my project file

2021-03-12T16:11:19.068900Z

I feel a bit irresponsible trying to weigh in here when I haven't used it (and also know it will be weird), but I don't think there are many people who use the function so I hope some answer is better than none

Jeremy Cronk 2021-03-12T16:12:26.069100Z

Aha, replacing the gen-interface with a protocol seems to have fixed the immediate issue - I’ll have to go back later and try to rearrange things to take better advantage of the protocol, but this gets me to where I need to be. Thanks!

2021-03-12T16:14:16.069300Z

consider writing a doc on http://clojuredocs.org or a blog post if you figure out how to make gen-interface work- it feels like a dark corner of the language currently

👍 1
alexmiller 2021-03-12T16:15:07.069600Z

maybe somewhere in swing

p-himik 2021-03-12T16:17:24.069700Z

java.lang.AbstractStringBuilder

p-himik 2021-03-12T16:19:35.069900Z

java.lang.VirtualMachineError, if you need a public constructor.

borkdude 2021-03-12T16:25:09.070200Z

cool, I wondered if the args to the super contructor can be dynamic and they can be:

(defn foo [m]
  (proxy [java.lang.VirtualMachineError] [(:msg m)]))

(prn (.getMessage (foo {:msg "bar"})))

👍 1
mafcocinco 2021-03-12T21:21:35.074700Z

Wasn’t sure if there was a channel for core.match. Had one very specific question: Is it possible to dynamically generate patterns from data at runtime (i.e. what is contained in the match form) or would it require some macro magic? All the examples that I have seen look to be static/“hard coded” into the source code.

borkdude 2021-03-12T21:26:59.075200Z

@mafcocinco core.match/match is a macro. the only way to make this more dynamic is to use eval

richiardiandrea 2021-03-12T21:29:09.076500Z

Hi there, I have a question, if I have an implementation like this

(s/fdef delete-by-id!
  :args (s/cat :impl any?
               :file-id ::id)
  :ret number?)

(defn delete-by-id!
  [impl file-id]
  (...)

(defmethod ig/init-key ::impl [_ {:keys [db]}]
  (with-meta
    {:db db}
    {`interfaces.file-repository/append-files append-files!
     `interfaces.file-repository/find-info-by-id file-info-by-id
     `interfaces.file-repository/find-content-by-id file-content-by-id
     `interfaces.file-repository/delete-file delete-by-id!}))
Should I expect the instrumented delete-by-id! to throw (cause it does not)

richiardiandrea 2021-03-15T18:22:41.147900Z

FYI this was answered here https://ask.clojure.org/index.php/10347/spec-instrumentation-does-not-work-with-extend-with-metadata

borkdude 2021-03-12T21:29:44.076600Z

$ bb -e "(defn dyn-match [pat & clauses] (eval \`(clojure.core.match/match ~pat ~@clauses))) (dyn-match [(+ 1 2 3)] [(+ 1 2 3)] :yo)"
:yo

mafcocinco 2021-03-12T21:31:24.076800Z

yeah, that is what I figured. Doable but kind of a bummer that we have to know the patterns ahead of time (or use eval). Would be cool if core.match had a data driven interface.

borkdude 2021-03-12T21:32:43.077100Z

I think the main reason it's a macro is that the pattern can be compiled to something efficient

borkdude 2021-03-12T21:33:08.077300Z

Take a look at matchete if you need something more basic and fn-driven: https://github.com/xapix-io/matchete

borkdude 2021-03-12T21:33:29.077700Z

or maybe even malli

mafcocinco 2021-03-12T21:37:19.077900Z

the usage of the patterns is going to be time sensitive, so I would like the benefit of the efficient compilation. If eval works, I would be fine with it as I run the compilation “offline”.

mafcocinco 2021-03-12T21:37:41.078100Z

I will check out your other suggestions too and see if one of those might be a better fit.

borkdude 2021-03-12T21:40:45.078300Z

Also #meander has an interpreter which accepts data instead of compile time patterns (it does both)

p-himik 2021-03-12T21:57:02.078600Z

AFAIK s/fdef will be checked against only if the corresponding function have been instrumented: https://clojure.org/guides/spec#_instrumentation

borkdude 2021-03-12T22:31:57.079Z

With malli:

user=> (m/parse [:catn [:a [:= 1]] [:b :any] [:c [:= 3]]] '[1 2 3])
{:a 1, :b 2, :c 3}

richiardiandrea 2021-03-12T23:34:56.079400Z

@p-himik yeah the function is instrumented