Fork me on GitHub
#clojure
<
2022-08-30
>
Setzer2209:08:37

I'm working with Java interop, and have a type implementing java.util.Collection. The thing is, no matter what I try, I can't call its .add method. I'm getting the following error instead:

No matching method add found taking 1 args for class
org.camunda.bpm.model.xml.impl.type.child.ChildElementCollectionImpl$1
I can call every other method in Collection, like .isEmpty, .clear or even .addAll! But there doesn't seem to be a way to call .add without getting the error.
(def my-object (...))

(isa? (.getClass my-object) java.util.collection) ; => true

(.clear my-object) ; => works

(.addAll my-object [...]) ; => works

(.add my-object ...) ; => Throws the error above

(seq (.getMethods (.getClass my-object))) ; => This lists "add" among the class' methods
I honestly don't have a clue what's going on there, what could be causing this strange behavior? 😅

reefersleep11:08:28

The error message seems straightforward. Does the add that you find in the class’ methods take zero arguments or more than 1 argument?

reefersleep11:08:03

Maybe you have some stale version of the impl loaded into your runtime that is different from what you have in your source code now?

Alex Miller (Clojure team)11:08:35

Try type hinting my-object with ^java.util.Collection

Alex Miller (Clojure team)11:08:56

Type inference will work from the type of your object but that may actually be too specific here and you're getting into module visibility issues or something

didibus15:08:26

I don't think Collection has an add method

didibus15:08:49

Oh no it does.

escherize15:08:46

What’s a good way to diff dependencies between different clj aliases? I am using

diff <(clojure -X:deps tree) <(clojure -X:my-stuff:deps tree)
But those produce the same thing. I see that my-stuff is pulling in additional dependencies, though so I expected them to be different

Joshua Suskalo15:08:18

clojure -X:deps tree :aliases '[:my-stuff]'

seancorfield15:08:50

☝️:skin-tone-2: You beat me to it -- for -X:deps you need to specify the aliases as an argument to the command.

Alex Miller (Clojure team)15:08:11

but use list instead of tree

Joshua Suskalo15:08:08

Also definitely use clojure and not clj here, as rlwrap messes up the terminal state after exiting with this command.

escherize15:08:24

Thanks for the help :)

Alex Miller (Clojure team)15:08:03

try -X:deps list instead

Anders Eknert16:08:46

Hey everyone! What would be an idiomatic way to determine whether a map is a “submap” of another map? I would need to work recursively, but not require that all keys be present, so e.g. {:b 2 :c {:e 4}} would be considered a submap of {:a 1 :b 2 :c {:d 3 :e 4}}

Anders Eknert16:08:53

interesting, thanks! I’ll take a look :thumbsup:

1
dpsutton16:08:28

would (= (select-keys possible-super-map (keys sub-map)) sub-map) work?

dpsutton16:08:14

oh i missed how the submap works recursively

Anders Eknert16:08:53

yeah, that’s the one thing I’ve struggled with as well 😅

Anders Eknert16:08:56

@U050ECB92 it’s not really clear to me how I’d use that library to accomplish what I need.. do you think you could point me in the right direction? 🙂 FWIW, I’m not using this in the context of testing

dpsutton16:08:58

embeds looks like the concept you want

Anders Eknert16:08:07

agreed… calling that with one argument (like my map) returns a matcher.. but I’m not sure how to use that to match against the other map

dpsutton16:08:13

yeah i was looking through. not super clear to me

dpsutton16:08:52

(let [result# (core/match matcher# actual#)
             match?# (core/indicates-match? result#)]
from the match? clojure.test extension

Anders Eknert17:08:48

nice! this looks like a way forward :thumbsup: although the docstring starts with “For internal use”… they’ll never catch me!

escherize17:08:35

You can flatten the map, and perform the thing Dan said to do. {:a {:b 1} :c 2} => {[:a :b] 1 [:c] 2}

escherize17:08:52

I have written that function ^

escherize17:08:02

you can use something like symbol-paths from here: https://github.com/escherize/tracks/blob/master/src/tracks/core.cljc#L4

(require '[clojure.set :as set])
(defn ->key-paths
  ([x] (into {} (->key-paths x [])))
  ([x path]
   (if (map? x)
     (mapcat #(->key-paths (val %) (conj path (key %))) x)
     {path x})))

;;(->key-paths {:a 1 :b 2 :c {:d {:e [3 4 5] :x 6}}})
;;;; => {[:a] 1, [:b] 2, [:c :d :e] [3 4 5], [:c :d :x] 6}

(defn subset? [a b]
  (set/subset?
   (set (->key-paths a))
   (set (->key-paths b))))

(subset?
 {:a 1 :b 2}
 {:a 1 :b 2 :c {:d {:e [3 4 5] :x 6}}})

rolt17:08:24

do you care about speed ? if not: (nil? (first (clojure.data/diff subm m))) should work right ?

Anders Eknert20:08:58

Nice! Thanks everyone who chipped in here 👍 I have a few paths to explore now 😃

didibus18:08:02

(= (class (proxy [Throwable] [nil nil false false])) (class (proxy [Throwable] [nil nil false false])))
;;=> true
It seems proxy is somewhat smart and doesn't create duplicate anonymous classes?

hiredman18:08:04

proxy is a whole thing

hiredman18:08:26

it creates a mutable thing named after, uh, I forget, maybe the namespace it is in + the implementing classes, and then instantiates that thing and mutates it to replace methods with whatever

didibus19:08:06

I see, just going to write some Java classes directly then