Fork me on GitHub
#beginners
<
2022-11-30
>
mister_m02:11:21

https://clojure.org/guides/spec#_instrumentation_and_testing, is there a faster way to instrument every function in a project that has an associated spec fdef than doing it one at a time? Maybe at the level of a namespace?

Ferdinand Beyer07:11:04

Check out the https://clojure.github.io/spec.alpha/clojure.spec.test.alpha-api.html#clojure.spec.test.alpha/instrument for instrument:

Usage: (instrument)
       (instrument sym-or-syms)
       (instrument sym-or-syms opts)

Instruments the vars named by sym-or-syms, a symbol or collection
of symbols, or all instrumentable vars if sym-or-syms is not
specified.
Just use (instrument) and all fdefs will be instrumented.

mister_m19:11:54

Cool, thank you

Jon Olick03:11:31

Does aset coerce the value to the actual backing type?

Jon Olick03:11:49

if somebody does an int-array, then uses aset on it

Jon Olick03:11:56

(instead of aset-int)

Jon Olick03:11:09

or is that just an error?

Ferdinand Beyer07:11:45

It’s an error:

user=>        (def arr (make-array String 8))
#'user/arr

user=>        (aset arr 0 42)
Execution error (ArrayStoreException) at jdk.internal.reflect.DirectMethodHandleAccessor/null (DirectMethodHandleAccessor.java:104).
java.lang.Long

mister_m04:11:21

How can I prevent naming collisions in two different protocols which share a function name that are implemented in two different defrecords ? If I use the same name I get a warning that the second record is redefining the function from the first, which makes sense. Is there some mechanism with protocols that allows me to not clobber a method definition in a different defrecord from a different protocol

dang duomg 19104:11:48

that looks like diamond problem

mister_m04:11:21

They do not implement the same protocols

mister_m04:11:52

defrecord A implements protocol A, defrecord B implements protocol B

mister_m04:11:14

protocol A and B have a same-named function

dpsutton04:11:14

Are protocols A and B in the same namespace?

mister_m04:11:53

Should protocols all be defined in separate namespaces?

dpsutton04:11:00

I don’t believe that is possible. A protocol will end up defining a function in the same namespace. You should be getting a redefinition error

dpsutton04:11:17

Not all protocols. But can’t have the same name in the same ns

mister_m04:11:18

I mentioned that I am, yes

mister_m05:11:50

Well there are a number of associated functions / the entire defrecord it may as well all be in a different namespace 🤷

dang duomg 19105:11:31

is this your problem

Apple05:11:32

this is cljs though. clj might be different.

dpsutton05:11:50

you cannot have multiple vars with the same name in the same namespace

dpsutton05:11:57

user=> (defprotocol P1 (f [_]))
P1
user=> (defprotocol P2 (f [_]))
Warning: protocol #'user/P2 is overwriting method f of protocol P1
P2

dpsutton05:11:22

in the same user namespace, how would you call P1's f on an object vs P2's f?

dpsutton05:11:41

and its giving you the answer right there: you've redefined f

dpsutton05:11:06

user=> (ns-publics *ns*)
{P1 #'user/P1, P2 #'user/P2, f #'user/f}

dpsutton05:11:13

it is not the location of the records

mister_m05:11:27

I am fully grasping the problem thanks

👍 2
dang duomg 19105:11:51

i guess putting all the commons of 2 protocols in another one and then subtype that will work?

Alex Miller (Clojure team)05:11:12

there are no subtypes. you need to separate the protocol definitions into different namespaces

😭 1
dang duomg 19105:11:15

nor is there type composition?

Alex Miller (Clojure team)06:11:32

well I think that depends on what you mean

Alex Miller (Clojure team)06:11:08

one object can extend multiple protocols and/or implement multiple interfaces

dang duomg 19106:11:51

composition as in “composition over inheritance”

Ferdinand Beyer08:11:05

Protocols are different from interfaces (deliberately ignoring that defprotocol creates an interface for different reasons). There is no inheritance. You cannot make a protocol extend another one. When you extend a type to satisfy a protocol, you do not subtype the protocol. In Java, classes/interfaces serve multiple purposes. One of them is namespaces. Two interfaces can have the same method name, since they are namespaced to the interface. In Clojure, these purposes are split into different concepts. Protocols provide polymorphism, but not namespacing. This is what namespaces are for. “Methods” defined by protocols are put in the current namespace. When you extend a protocol, you only register an implementation for the protocol’s dispatch mechanism. You do not “inherit” the functions, they will not be copied to the current namespace. Other than Java, you can extend two protocols that define the same function name unambiguously:

(deftype Impl []
  foo/Protocol
  (example [])

  bar/Protocol
  (example []))
Now Impl satisfies both foo/Protocol and bar/Protocol. To call the “example” method for Impl, you will need to use the respective namespaces. (example impl) will not work (there is no example var in the current namespace), but (foo/example impl) and (bar/example impl) will, without name conflicts.

Abhi Saxena18:11:09

Hi All, a simple question on how to achieve this:

{:metrics [(when some-boolean? {:name "Forecasted"})
           {:aga 39}]}
I want to include the first element conditionally, it's currently including null which I don't want there..... I tried with conj and merge but same behavior the collection is a vector of Maps

Ed18:11:45

(-> []
    (cond-> some-boolean? (conj {:name "Forecasted"}))
    (conj {:age 39}))

Ed18:11:55

Something like that maybe?

Martin Půda18:11:51

And you don't have to start with []:

{:metrics (cond-> [{:age 39}]
                  true (conj {:name "Forecasted"}))}

Abhi Saxena18:11:35

@U01RL1YV4P7 - thanks for your response, will it change the order of the elements in vector I need to keep them in same order

Martin Půda18:11:46

Good catch- so use @U0P0TMEFJ's solution. Anyway, are you sure that a vector of maps with one entry is the best structure for your task?

Abhi Saxena19:11:04

Sure @U01RL1YV4P7 thanks again, the actual code has 200+ elements, I just gave a sample to understand the requirement 🙂

Abhi Saxena19:11:37

@U0P0TMEFJ - thanks much Ed

👍 1
Alex Shulgin22:11:02

(concat (when x? [...]) [...])

🙌 1
Alex Shulgin22:11:22

that's how I normally do that 😉

Alex Miller (Clojure team)18:11:04

it's named so you could potentially use it in expr

Alex Miller (Clojure team)18:11:22

don't know if anyone ever actually does so

Jon Olick19:11:20

yeah i don’t understand the point of ret

Jon Olick19:11:30

seems like a totally unnecessary piece

Alex Miller (Clojure team)20:11:22

this long pre-dates my involvement with Clojure so I am only guessing, but generally if we need a name that the caller of the macro may need to use, we let them name it (otherwise you're in anaphoric macro land). I think proxy is the only exception to this general rule (with this)

Jon Olick18:11:30

seems like it just takes result of last expr as the return value

Jon Olick18:11:36

(as per example)