Fork me on GitHub
#beginners
<
2022-02-04
>
Herman Nurlygayanov11:02:00

I would like to override a method on a reified type, but preserve all other methods. What is the simplest way to do that? For example: I have > (deftype Adapter [] > some.namespace/SomeProtocol > (type-name-get [this] (:Adapter)) > ...) > > (def adapter-instance (Adapter.)) And I want to get > (def modified-adapter-instance > (some-magic-fn adapter-instance type-name-get (fn [this] :ModifiedAdapter))) > > (.type-name-get adapter-instance) => :Adapter > (.type-name-get modified-adapter-instance) => :ModifiedAdapter

emccue13:02:08

delegation. write them all out

emccue13:02:01

so make an instance of Adapter, then reify an instance of the protocol

emccue13:02:34

(def adapter (Adapter.))

(def modified-adapter-instance
  (reify some.namespace/SomeProtocol
    (type-name-get [_] 
      (string/upper-case (type-name-get adapter)))
    (other-method [_]
      (other-method adapter))
    (other-other-method [_]
      (other-other-method adapter))))

emccue13:02:38

you don’t have to, but yeah you can

emccue13:02:15

if you need to do this multiple times for whatever reason you can do the same trick as proxy and pass a map of functions

emccue13:02:10

and do an ((or (:other-method funcs) other-method) this)

Richie15:02:19

https://clojure.org/reference/special_forms#recur > Note that `recur` is the only non-stack-consuming looping construct in Clojure. There is no tail-call optimization and the use of self-calls for looping of unknown bounds is discouraged. Is this saying that it's bad to use recur when I don't know how many times I'll recur? I don't think I understand the advice.

(defn my-fun
  (loop [[a & as] xs]
    (when a
      (println a)
      (recur as))))
Is the quote discouraging code like the above or is it talking about something else?

clj.max17:02:52

I read it differently. It says to use recur because Clojure does not have TCO, which many other functional languages do have. With TCO you can just "self-call" and the compiler will turn it into a tail-call to prevent stack frames from building up. recur should be safe.

clj.max17:02:17

You're right that it could be worded more intuitively

clj.max17:02:16

Self-call I take as meaning that you would e.g. write:

(defn my-fn [x]
  ;; do some things
  (my-fn (inc x)))

clj.max17:02:29

This does work in Clojure, but this comment is saying don't do it, use loop/recur instead

Richie17:02:45

Yea, I think you’re right. The way I read it confused me. Thanks!

noisesmith21:02:37

@U5JPZFFR6 not neccessarily loop (defn my-fn [x] (recur (inc x))) is also non-stack-consuming (though just as much of a silly loop)

clj.max21:02:45

Oh I didn't realize you could recur without loop, that's convenient. Honestly isn't that better than typing the fn name again? If you rename the fn, you only need to change the head, not the call, and its semantically more obvious that you're self-recursing. I suppose you can't multi-recurse but I've honestly never needed that.

noisesmith22:02:10

the two reasons to do a direct self-call instead of recur are for lazy-seqs (the self call gets embedded in a thunk that is returned instead of making the stack deeper), or with the kind of branching recursion where the bookkeeping to turn it all into tail calls isn't worth the complexity

ghadi15:02:17

something else, calling my-fun from within my-fun (without using loop/recur)

Alex Miller (Clojure team)15:02:31

because a self call adds a stack frame, unbounded self calls == possible stack overflows. so use recur instead.

Richie15:02:25

Oh I see, thanks! I think I wasn't reading the docs correctly.

Luis Angel Prado Postigo15:02:43

Hi, how i can make this work? (def [x] (map inc [1 2 3 4 5]))

neilprosser15:02:51

Did you want to create a function with defn rather than def e.g. (defn [x] (map inc [1 2 3 4 5]))

R.A. Porter15:02:28

Or are you trying to set x to the mapped value, perhaps as (def x (map inc [1 2 3 4 5]) or, if you want it as a vector again, (def x (mapv inc [1 2 3 4 5]))?

emccue15:02:57

or are you trying to do a “destructuring def”?

emccue15:02:21

(def x (let [[x] (map inc [1 2 3 4 5])]
         x))

emccue15:02:55

(no syntax for that one i’m afraid

Luis Angel Prado Postigo16:02:31

i want to set the first value of the list returned by map into x

Luis Angel Prado Postigo16:02:32

in that expression i want x= 2

dpsutton16:02:00

(def x (inc (first [1 2 3 4 5])))

Luis Angel Prado Postigo16:02:51

@U11BV7MTK that works, but now i wondering if instead of taking the first i want to take 2, or maybe more

dpsutton16:02:44

if you’re unsure, just set (def x (map inc [1 2 3 4 5])) and then wherever you use x can take as many values as you need

dpsutton16:02:05

but without any kind of use-case or problem statement its hard to give more advice. And we’re in a bit of a contrived domain to begin with

dpsutton16:02:13

If you have a few use cases we can think about those

Luis Angel Prado Postigo16:02:17

well i was trying to use destructuring here

(let [[current-child next-child] (readdir path-string)
      current-child-path (path/join path-string current-child)
       next-child-path (path/join path-string next-child)])

Luis Angel Prado Postigo16:02:48

into

[[current-child-path next-child-path] (map (partial path/join path-string) [current-child next-child])]

emccue16:02:54

yeah - unfortunately not supported. I have wanted something like that though

emccue16:02:50

there is an example in the community docs for this function of doing what you want

emccue16:02:39

so you can copy paste that macro or adjust it to your needs

Luis Angel Prado Postigo16:02:25

i didn't know that you can do destructuring in def,

(def [a] ["a"]) ;this doesn't work

emccue16:02:24

you can’t, but you can write a macro that does

(def+ [a] ["a'])

Luis Angel Prado Postigo16:02:30

i see, i was wrong, but i kind of surprised that this work

(let [[a b] (map inc [1,2]) ] (prn a b))

Luis Angel Prado Postigo16:02:44

btw thanks for the macro

noisesmith21:02:47

@U0322TLEJFK the generic term for what let does is a "binding block" - the same syntax of destructuring works in fn, for , doseq , loop etc., but on the other hand def isn't a binding block, it's much simpler

Rob Haisfield17:02:05

My project.clj file has [babashka/fs "0.1.2"] , but when I run lein deps :tree it shows that I’m using [babashka/fs “0.0.5"]. Why would that be happening? How can I update it to force it to use the most recent version? Right now I’m using Calva

Rob Haisfield17:02:35

My project.clj:

(defproject functions-for-processing-notes "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url ""
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url ""}
  :dependencies [[org.clojure/clojure "1.10.3"]
                 [dk.ative/docjure "1.14.0"]
                 [com.rpl/specter "1.1.3"]
                 [babashka/fs "0.1.2"]
                 [orchestra "2021.01.01-1"]
                 [lambdaisland/deep-diff2 "2.0.108"]
                 [org.clojars.arthurbarroso/lovelace "0.1.2"]]

  :repl-options {:init-ns functions-for-processing-notes.core})

borkdude17:02:53

Do you have ~/.lein/profiles.clj?

Rob Haisfield17:02:27

Nope, nothing in there

hiredman17:02:01

what is the tree output?

Rob Haisfield17:02:13

Output of lein deps :tree

[babashka/fs "0.0.5"]
 [clojure-complete "0.2.5" :exclusions [[org.clojure/clojure]]]
 [com.rpl/specter "1.1.3"]
   [riddley "0.1.12"]
 [dk.ative/docjure "1.14.0"]
   [org.apache.poi/poi-ooxml "4.1.0"]
     [com.github.virtuald/curvesapi "1.06"]
     [org.apache.commons/commons-compress "1.18"]
     [org.apache.poi/poi-ooxml-schemas "4.1.0"]
       [org.apache.xmlbeans/xmlbeans "3.1.0"]
   [org.apache.poi/poi "4.1.0"]
     [commons-codec "1.12"]
     [org.apache.commons/commons-collections4 "4.3"]
     [org.apache.commons/commons-math3 "3.6.1"]
 [lambdaisland/deep-diff2 "2.0.108"]
   [fipp "0.6.23"]
   [lambdaisland/clj-diff "1.1.58"]
   [mvxcvi/arrangement "1.2.1"]
   [org.clojure/core.rrb-vector "0.1.1"]
 [nrepl "0.8.3" :exclusions [[org.clojure/clojure]]]
 [orchestra "2021.01.01-1"]
 [org.clojars.arthurbarroso/lovelace "0.1.2"]
   [cheshire "5.10.0"]
     [com.fasterxml.jackson.core/jackson-core "2.10.2"]
     [com.fasterxml.jackson.dataformat/jackson-dataformat-cbor "2.10.2"]
     [com.fasterxml.jackson.dataformat/jackson-dataformat-smile "2.10.2"]
     [tigris "0.1.2"]
   [clj-http "3.10.0"]
     [commons-io "2.6" :exclusions [[org.clojure/clojure]]]
     [org.apache.httpcomponents/httpasyncclient "4.1.4" :exclusions [[org.clojure/clojure]]]
       [org.apache.httpcomponents/httpcore-nio "4.4.10"]
     [org.apache.httpcomponents/httpclient-cache "4.5.8" :exclusions [[org.clojure/clojure]]]
     [org.apache.httpcomponents/httpclient "4.5.8" :exclusions [[org.clojure/clojure]]]
       [commons-logging "1.2"]
     [org.apache.httpcomponents/httpcore "4.4.11" :exclusions [[org.clojure/clojure]]]
     [org.apache.httpcomponents/httpmime "4.5.8" :exclusions [[org.clojure/clojure]]]
     [potemkin "0.4.5" :exclusions [[org.clojure/clojure]]]
       [clj-tuple "0.2.2"]
     [slingshot "0.12.2" :exclusions [[org.clojure/clojure]]]
 [org.clojure/clojure "1.10.3"]
   [org.clojure/core.specs.alpha "0.2.56"]
   [org.clojure/spec.alpha "0.2.194"]

borkdude17:02:36

My output:

$ lein deps :tree
 [babashka/fs "0.1.2"]
 [clojure-complete "0.2.5" :exclusions [[org.clojure/clojure]]]
 [com.rpl/specter "1.1.3"]
   [riddley "0.1.12"]
...

borkdude17:02:28

Maybe try purging ~/.m2/repository/babashka/fs

borkdude17:02:00

It would surprise me if that helped, but you never know

hiredman17:02:54

are you sure you saved the changes to project.clj?

Rob Haisfield17:02:36

I saved the project.clj and rebooted the REPL and it didn’t work at first, but then I rebooted VS Code and it did! Thank you for helping me with this.

brendnz02:02:05

Afk but I see restarting VS Code will likely explain/be solution to why my project deps.edn did not override my user deps.edn, i.e. I had similar problem newer version of dependency in project deps.edn not overriding version in user deps.edn. Edit: oops, when that happened I was not using VS Code, but clj from the terminal. I noticed the anomaly to follow up some arbitrary time in the future.

Lukas21:02:00

Hey, I use a macro to generate a core.logic expression. A part of that is a very large "db", in this case it's just a big in memory data structure. I wonder is there a way to reference the data by a name/reference (when I generate an intermediate value inside a let clause)?

(defmacro large-ds [ds]
  (let [intermediate-val (mapv identity ds)]
    `(map identity ~intermediate-val)))

(macroexpand-1 '(large-ds ["very" "big" "vector"]))
=> (clojure.core/map clojure.core/identity ["very" "big" "vector"])


;; and what I would like to achieve

(macroexpand-1 '(large-ds ["very" "big" "vector"]))
=> (clojure.core/map clojure.core/identity reference-to-intermediate-val)

hiredman21:02:52

passing large values through the compiler is generally bad

hiredman21:02:11

the core.logic dsl is mostly macros, but it also has functions for most things so you construct goals at runtime using those instead of having to rely so heavily on macros

Lukas21:02:22

Thank you! I guess I should hide access to the data behind function calls then?

Lukas21:02:52

I have some input data and compile it to a core.logic expression. And I have some custom data structures like described here https://tsdh.wordpress.com/2012/01/06/using-clojures-core-logic-with-custom-data-structures/

Lukas21:02:17

> passing large values through the compiler is generally bad I don't know how to mitigate this, since I have to work with the data :thinking_face:

hiredman21:02:27

the blog post in that link doesn't pass large data through the compiler and doesn't create any macros

hiredman21:02:35

so do what it does

Lukas21:02:59

Okay simple. I don't know why but I tried to write "pure" functions