Fork me on GitHub
#clojure
<
2021-09-27
>
didibus00:09:58

Other topic, I just realized its a bit annoying how if an exception is wrapped, you can no longer catch on the type of the original exception. It means that you can't attach more information to an existing exception and have the callers catch on those. I've noticed this, because sometimes I wrap something in ex-info to add more details, but then you need to catch the clojure.lang.ExceptionInfo instead. I don't know if anyone has a trick for that too?

seancorfield00:09:18

Nearly all my catch clauses use Throwable šŸ˜‚

šŸ˜‚ 1
mpenet04:09:51

We came with a way to deal with this at work https://github.com/exoscale/ex we basically use ex-data.type to specify what the ex represents and use an internal hierarchy to allow doing try/catch on it that s aware of that hierarchy.

mpenet04:09:19

And since you have a hierarchy representing your error "types" you can use it in other contexts than try/catch, ex with multimethods (like for rendering the error to the user, reporting, logging)

didibus04:09:43

Hum, nice, ya I considered a custom try/catch, but I've been hoping to get around it, since I'm writing a lib, and I feel its weird to ask people to now use a custom try/catch as well.

mpenet05:09:06

It's very simple and also fully compatible with the default try/catch/finally, you can mix patterns. But yes it forces you to use that (or the associated functions)

didibus05:09:27

I decided to go with a registry, so I have a ex-details function, and people can call that on a thrown error and it'll return the map of details attached with it.

mpenet05:09:03

Catching throwable is considered bad practice. Arguably it's ok if you're careful but it's easy to get into doggy situations

Maciej Szajna12:09:43

I'm in the same boat, catching all most of the time. The thing is, what I tend to need to express is 'if this operation fails', and not 'if this operation fails in this specific way'. Some of the time I may not even be fully aware of all the failure modes, all I know is that the operation is risky (like, involves IO) and I need to recover somehow. What is key is being able to properly scope the try to only cover the operation in question. This is notoriously hard and I cannot recommend rufoa/try-let enough.

seancorfield17:09:44

> Catching throwable is considered bad practice. Arguably it's ok if you're careful but it's easy to get into doggy situations That's why I put a šŸ˜‚ on it. And I would advise people, in general, not to do it. But it sums up my feelings about Java's whole checked exceptions nonsense šŸ˜•

didibus01:09:56

Is there a way to run proxy at runtime, where I get the name of the class dynamically?

didibus01:09:59

I want to do something like:

(defn ->ex-data
  [ex data]
  (proxy [ex clojure.lang.IExceptionInfo] []
    (getData [] data))
To create a child of the type of ex that also implements IExceptionInfo

didibus02:09:26

Ok, its possible if you use get-proxy-class with construct-proxy and init-proxy like so:

(defn ->ex-data
  [ex data]
  (-> (get-proxy-class (class ex) clojure.lang.IExceptionInfo)
      (as-> px (if (ex-message ex) (construct-proxy px (ex-message ex)) (construct-proxy px)))
      (init-proxy {"getData" (fn [_this] data)})
      (.initCause ex)))

ghadi02:09:37

Generally avoid typed exceptions

šŸ‘ 1
didibus02:09:29

I'm really just trying to decorate an exception, with a map of data, but such that it retain its original type.

didibus02:09:51

What I have isn't robust though, because I can't easily figure out the correct way to recreate a new child instance.

didibus03:09:50

I'm tempted to use a WeakHashMap instead. Has anyone used that before, if I have a WeakHashMap of object -> data, it should let me attach arbitrary additional data to specific instances of an object in a GC safe way correct? Where as soon as the object gets GCed the entry in the map will too and thus its associated data. And the map will not prevent the object from being GCed right?

Timofey Sitnikov11:09:19

Good morning, I use next-jdbc for interfacing with db and I have been trying to learn how to test the db, and looking at the: https://github.com/Bigsy/pg-embedded-clj. I wonder if anyone else is using it? Does it make sense to use or or is there a pitfall?

seancorfield17:09:48

That's what next.jdbc itself uses in its own test suite @timofey.sitnikov

kenny14:09:05

A sorted set cannot have multiple values that compare equally. Is there a data structure that permits that?

borkdude14:09:03

priority queue?

kenny14:09:36

Ooo, interesting! It looks like it may work. It seems like most implementation for this are targeted towards the usual queue use case of pop/peek. I'm after the same ops a sorted set provides: (r)?(sub)?seq.

kenny14:09:35

This sounds exactly like what I want šŸ˜€

kenny14:09:50

Is there a specific noun for an implementation of a sorted bag/multiset where it behaves exactly the same as a set (values unique by hash), and the sort allows for values to compare identically?

p-himik14:09:31

Just to be clear - you have values, for which

(= a b)
=> true
(= (hash a) (hash b))
=> false
Is that right?

noonian14:09:15

You could use a sorted map where the values are vectors of the entries that compare identically

āœ”ļø 1
kenny14:09:40

No, sorry for the confusion. I'm specifically after a sorted set impl that allows for items that compare identical (i.e., comparator returns 0), but set semantics are based on the value. e.g., the following would returns a set of 3 items

(sorted-set-by #(compare (:k %1) (:k %2))
  {:k 0
   :v "a"}
  {:k 1
   :v "b"}
  {:k 0
   :v "c"})
=> #{{:k 0, :v "a"} {:k 1, :v "b"}}

emccue15:09:21

> Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must beĀ consistent with equalsĀ if it is to correctly implement theĀ `Set`Ā interface. (SeeĀ `Comparable`Ā orĀ `Comparator`Ā for a precise definition ofĀ consistent with equals.) This is so because theĀ `Set`Ā interface is defined in terms of theĀ `equals`Ā operation, but aĀ `TreeSet`Ā instance performs all element comparisons using itsĀ `compareTo`Ā (orĀ `compare`) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a setĀ isĀ well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of theĀ `Set`Ā interface.

emccue15:09:40

so if we made a set that did that it wouldn't be a proper Set in java terms

emccue15:09:52

but you can still make it, so here is a stab:

emccue15:09:43

(defn create [key-fn]
  {::key-fn        key-fn 
   ::order         (sorted-set)
   ::values        #{}
   ::values-by-key {}})

(defn insert [ss value]
  {::key-fn        (::key-fn ss)
   ::order         (conj (::order ss) ((::key-fn ss) value))
   ::values        (conj (::values ss) value)
   ::values-by-key (update (::values-by-key ss) ((::key-fn ss) value) conj value)})

(-> (create :a)
    (insert {:a 1})
    (insert {:a 2}))
=> #:example.sorted-set{:key-fn :a, :order #{1 2}, :values #{{:a 1} {:a 2}}, :values-by-key {1 ({:a 1}), 2 ({:a 2})}}

(defn contains [ss value]
  (contains? (::values ss) value))

(defn as-seq [ss]
  (mapcat (::values-by-key ss) (::order ss)))

(as-seq (-> (create :a)
            (insert {:a 1})
            (insert {:a 1 :b 3})
            (insert {:a 2})))
=> ({:a 1, :b 3} {:a 1} {:a 2})

emccue15:09:21

its not fit to be a general purpose thing, but does that fit your use cases?

emccue15:09:32

(-> (create :a)
    (insert {:a 1})
    (insert {:a 1 :b 3})
    (insert {:a 2}))
#:example.sorted-set{:key-fn :a,
                     :order #{1 2},
                     :values #{{:a 1} {:a 2} {:a 1, :b 3}},
                     :values-by-key {1 ({:a 1, :b 3} {:a 1}), 2 ({:a 2})}}

kenny15:09:41

That's a great find @U3JH98J4R. I was looking for exactly that javadoc. It makes sense that it does not fit Java's Set. Thank you. Also, the snippet does look like it covers the use case! I'm thinking about extracting this into a small lib that works just like a sorted-set.

emccue15:09:52

yeah, do whatever you want with it

emccue15:09:17

i think the values in values-by-key should be sets too, my bad

emccue15:09:49

or...something

emccue15:09:57

your court be the ball

simple_smile 1
kenny16:09:18

Thinking about calling this thing a SortedMultiset, but not sure if that is accurate given it's a bit at odds with the definition of Multiset.

kenny16:09:37

This would be a sorted multiset with multiplicity capped at 1 and value equivalence defined by Set.

mmer15:09:09

Is there a way of checking if a var is a simple type or not?

noisesmith16:09:00

if random classes are not considered simple, my instinct would be to check for the simple types explicitly

(import (clojure.lang Keyword
                      Symbol)
        java.util.regex.Pattern)

(defmulti simple? type)

(defmethod simple? :default [_]
  false)

(defmethod simple? nil [_]
  true)

(defmethod simple? Number [_]
  true)

(defmethod simple? Keyword [_]
  true)

(defmethod simple? Symbol [_]
  true)

(defmethod simple? CharSequence [_]
  true)

(defmethod simple? Pattern [_]
  true)

maverick18:09:31

anyone know why we'd get a classnotfound clojure.pprint

Fredrik18:09:37

What's your code? Try (require 'clojure.pprint) first.

hiredman18:09:01

some examples

% clj
Clojure 1.10.2
user=> clojure.pprint
Syntax error (ClassNotFoundException) compiling at (REPL:0:0).
clojure.pprint
user=> (require clojure.pprint)
Syntax error (ClassNotFoundException) compiling at (REPL:1:1).
clojure.pprint
user=> (require 'clojure.pprint)
nil
user=>

maverick16:09:13

OKay thanks

randomm char01:11:25

clojure.pprint/pprint

randomm char01:11:11

when in another namespace

Noah Bogart21:09:33

I'd like to run my test suite (or a subset of my test suite) and get a flame graph of the code that is run (to see which parts are slowest/where the most time is spent). Is that possible?

Noah Bogart21:09:50

I'll check that out. Idk how I missed it

waffletower21:09:17

Docker question -- the official clojure:latest Docker image has boot, tools.deps, and lein installed. It is a bullseye image. However, none of the static tagged images seem to have all 3 toolsets available. There are currently 902 images so I may have missed something. Is there a tag that I could pin, preferably with openjdk-11 installed, that has all 3 toolsets pre-installed? Can make a custom image I guess if this stumps or bores everyone.

waffletower21:09:13

I tried clojure:bullseye, and it just has lein installed.

vncz23:09:28

@U0E2268BY Iā€™m curious why you need all of them :thinking_face:

waffletower00:09:00

Don't need boot, there is a project that builds java classes with lein and also uses tools.deps, could change it I guess.

waffletower00:09:14

the clojure:latest image does have all three

waffletower00:09:39

was wondering how/why that was without explicit tagging on it

ghadi14:09:49

you can use tools.build now to build java classes and retire that function from lein

vncz14:09:41

I just tried the new tools.build and yes, works perfectly!