Fork me on GitHub

Does :use only to import java classes?

delaguardo07:05:29 No, it is only for clojure namespaces.


@U04V4KLKC I referred few documents , and I did not get when to use :require and :use


the only difference is that use also refer to each function from namespace.

(use 'clojure.string)
(join "," ["a" "b" "c"]) ;; => "a,b,c"
but with require you have to use fullyqualified function name
(require 'clojure.string)
(clojure.string/join "," ["a" "b" "c"])


what about require ?


usually, best practices of clojure suggesting to not use use but use require with :as alias modifier

🙌 4
☝️ 4

i have 42 lines in my :require and i would really like to use circular dependencies

Elliot Stern13:05:40

What’s the most idiomatic way to thread a function if it exists - something like

(-> foo
  #(if sorter (sort sorter %) (identity %))


I made some-as-> (like some-> and as-> combined). It will short-circuit on nil


the "else" above is (identity %). My imagination fails me: how will that be different than %? Otherwise, your approach seems fine.

Elliot Stern13:05:03

Is there something like when for this kind of usecase?


In a world like Common Lisp where sort is destructive we could use when sorter sort X knowing X will either get sorted or sail on untroubled as is, but not so with clojure.

Alex Miller (Clojure team)13:05:57

well, kind of depends on the whole thing

Elliot Stern14:05:28

this is the only conditional item, but there’s only like 4 things in the macro

Alex Miller (Clojure team)14:05:57

could switch to as-> too

Alex Miller (Clojure team)14:05:30

or lift it out into let

Alex Miller (Clojure team)14:05:35

(let [f (if sorter (sort sorter %) (identity %))]
  (-> foo

☝️ 4

not sure if i asked this before, but is there a way to name a reify-produced class?


just asking because when i have multiple things reified in the same namespace, it is impossible to tell from the stacktrace which one of them caused trouble


would be nice if they could be named optionally like fns


you can customize toString and you can put it inside a named parent

user=> ((fn foo [] (reify Object (toString [_] "a foo"))))
#object[user$eval142$foo$reify__144 0x7fab4be7 "a foo"]


notice that foo shows up in the class name, and "a foo" shows up as the second half of the #object data


i don't see anything in a stacktrace that helps though


reify is by definition unnamed


well... uncontrolled classnames


(defprotocol Foo (foo [_]))
(foo (reify Object (toString [_] "custom") Foo (foo [_] (throw (ex-info "boom" {})))))
doesn't have that tostring message in the stacktrace, nor would i expect it


the stacktrace however should exactly pinpoint any fault


@dpsutton the wrapping named function addresses the stack trace identifiability


that's why I used both the fn and toString


(ins)user=> (def frobber ((fn frobber [] (reify Object (toString [_] "a frobber") clojure.lang.IFn (invoke [_] (:frobbing-error))))))
(ins)user=> frobber
#object[user$frobber$reify__153 0x432034a "a frobber"]
(ins)user=> (frobber)
Execution error (IllegalArgumentException) at user/frobber$reify (REPL:1).
Wrong number of args passed to keyword: :frobbing-error
(ins)user=> *e
#error {
 :cause "Wrong number of args passed to keyword: :frobbing-error"
 [{:type java.lang.IllegalArgumentException
   :message "Wrong number of args passed to keyword: :frobbing-error"
   :at [clojure.lang.Keyword throwArity "" 98]}]
 [[clojure.lang.Keyword throwArity "" 98]
  [clojure.lang.Keyword invoke "" 110]
  [user$frobber$reify__153 invoke "NO_SOURCE_FILE" 1]
@dpsutton @vale more complete example, showing how both the toString and the wrapping thunk help with readability


and accidentally even showing how it is especially useful in the repl where there's no source file or line number


it's taking advantage of the fact that reify inside an fn is an inner class of that fn (which we already established can be named)


gotta focus on the problem statement


"I can't tell which of the reifies is implicated in this stack trace"


that should be determinable from the line numbers appearing in the trace


right, so if the desired thing is a readable name (like with fn), using a wrapping fn addresses that


I agree that line numbers help too, but as a workflow issue, I find it easier to go by human readable names I can search rather than line numbers


yes you are of course right


it is not impossible


but it would be way more simple to parse and understand if they were nameable even for such cosmetic purposes


a macro can make this approach easier to read


i don't want to refer to the generated class by its name or anything

Joni Hiltunen18:05:37

I wonder if it's possible to solve a circular dependency between 2 functions somehow? I'm trying to do this:


Huhu, I wrote a macro, and I get an error when try to put a number in a form

Unexpected error (ClassCastException) macroexpanding q at (src/lhrb/engine.clj:327:3).
class java.lang.Long cannot be cast to class clojure.lang.Named (java.lang.Long is in module java.base of loader 'bootstrap'; clojure.lang.Named is in unnamed module of loader 'app')
for some reason it works when I substitute the number with a symbol
;; does not work
   '(q {:find [?num ?loc]
       :where [(gr-th ?num 1000)
               [?b :battle/attacker_size ?num]]}

;; does work
(def n 100)
   '(q {:find [?num ?loc]
        :where [(gr-th ?num n)
               [?b :battle/attacker_size ?num]]}
I figured that this is probably a silly beginner mistake, so could maybe a wise person please enlighten me? 😋 Any help is greatly appreciated background: I wrote a micro-kanren implementation and try to give it a datomic flavored query api with the macro


wild stab, but i guess you look at each form to determine if it begins with a ??


(defn compile-where-clauses
  "transforms vector clauses into q-db queries
  e.g. [?a :age 10] => (q-db db ?a :age 10)"
  [clauses db]
  (->> clauses
       (map (fn [clause]
              (if (vector? clause)
                `(q-db ~db ~@clause)

(defn find-lvars
  "finds and returns all unique logic-variables.
  A logic var begins with an '?'"
  [find where] ;; maybe decouple from concrete impl?
  (->> (into find where)
        (fn [s]
          (str/starts-with? (name s) "?")))

(defmacro q [{:keys [find where]} db]
  (prn &form)
  (prn &env)
  (let [;; test if vars in find clause are also in where clause
        lvars (find-lvars find where)
        where-compiled (compile-where-clauses where db)]
    `(let [~@(interleave
               (fn [sym]
                 `(gensym ~(name sym)))
         (reify-var ~@find)


always look at your full stack trace *e


Show: Project-Only All 
  Hide: Clojure Java REPL Tooling Duplicates  (0 frames hidden)

2. Unhandled clojure.lang.Compiler$CompilerException
   Error compiling src/lhrb/engine.clj at (331:3)
   #:clojure.error{:phase :macroexpansion,
                   :line 331,
                   :column 3,
                   :source "/home/lukas/projects/datahog/src/lhrb/engine.clj",
                   :symbol q}
    7023  clojure.lang.Compiler/macroexpand1
                  core.clj: 4012  clojure.core/macroexpand-1
                  core.clj: 4014  clojure.core/macroexpand
                  core.clj: 4014  clojure.core/macroexpand
                      REPL:  331  lhrb.engine/eval10264
                      REPL:  331  lhrb.engine/eval10264
    7181  clojure.lang.Compiler/eval
    7136  clojure.lang.Compiler/eval
                  core.clj: 3202  clojure.core/eval
                  core.clj: 3198  clojure.core/eval
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn/fn
          152  clojure.lang.AFn/applyToHelper
          144  clojure.lang.AFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj: 1977  clojure.core/with-bindings*
                  core.clj: 1977  clojure.core/with-bindings*
       425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  458  clojure.main/repl/fn
                  main.clj:  458  clojure.main/repl
                  main.clj:  368  clojure.main/repl
       137  clojure.lang.RestFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj:  662  clojure.core/apply
                regrow.clj:   20  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
      1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
           22  clojure.lang.AFn/run
               session.clj:  202  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  201  nrepl.middleware.session/session-exec/main-loop
           22  clojure.lang.AFn/run
       832  java.lang.Thread/run

1. Caused by java.lang.ClassCastException
   (No message)


by default, the REPL presents a one or two line summary, but fuller information is available in the trace, including which line of your source file threw an exception


so, I am already going to qualify this ^ In the specific case of ClassCastExceptions and NullPointerExceptions, sometimes the JVM elides traces 🙂


(that is controllable)


this is the output from *e

#error {
 :cause nil
 [{:type clojure.lang.Compiler$CompilerException
   :message "Unexpected error macroexpanding q at (/home/lukas/projects/datahog/src/lhrb/engine.clj:331:3)."
   :data #:clojure.error{:phase :macroexpansion, :line 331, :column 3, :source "/home/lukas/projects/datahog/src/lhrb/engine.clj", :symbol q}
   :at [clojure.lang.Compiler macroexpand1 "" 7023]}
  {:type java.lang.ClassCastException
   :message nil}]


right, elided -- normal traces are not empty vectors []


somewhere in your macro you're asking for the name of a symbol, but calling it on a number (which are Longs in clojure)


okay thank you


That helps I guess I can track it now down (there is one part where I call name)


you can pass -XX:-OmitStackTraceInFastThrow to your REPL


which would fill out the empty :trace []


it's a speed thing. Prod code never throws ClassCastExceptions, so the JVM optimizes for not filling out full stack traces.


🙏 ty soo much, very good input


could you help and tell my how I pass -XX:-OmitStackTraceInFastThrow` to my repl? 🙈

Joni Hiltunen19:05:48

good parsing library? I searched online and found but it hasn't been updated in a while. is it abandoned or is it just so finished that it hasn't needed any updates recently? I wanna parse a simple imperative language (for moving a turtle)


In clojurespace libraries do not get updates when they are done


your fine using this library

Joni Hiltunen19:05:41

okay, thank you


@UQDFC6V4Z You’ll find a lot of Clojure libraries that haven’t been updated in ages — Clojure folks value stability and also tend to like libraries that solve one problem “completely” and therefore can be “done” and not need constant updates. It always looks strange to folks coming from language backgrounds where there is always a lot of “churn” on libraries.


We use Instaparse heavily at work for our custom search rules (driving 40+ online dating sites).

❤️ 2
Joni Hiltunen19:05:24

@U04V70XH6 thank you! should be good for my toy program then 😄


I am really happy now to see a library with an old Last commit. I only have a doubt with dependencies. I guess an ideal library have very few dependencies but in most cases there are. For instance version of clojure clojurescript and reader. So what is your practise concerning these dependencies ? Do you update them manually ?


I usually don’t bother much about whatever version of tools.reader is pulled in these days. I have a top-level dependency for Clojure (or ClojureScript) so that takes precedence over whatever any libraries bring in (I’m using the CLI / deps.edn).


We’re still here and generally respond to important bug reports 🙂 Also I answer questions in #instaparse sometimes


just typing in does not work


Anyways you guys rock, and thanks a lot for helping strangers on the internet you are great :hugging_face:

Alex Miller (Clojure team)19:05:32

in the repl, (clojure.repl/pst *e) is often more readable than *e (and does some other useful things like eliding top frames related to error throwing)

💡 6

And -XX:-OmitStackTraceInFastThrow is a jvm option. You start a jvm with this option

💡 3

🙏 Thanks a lot

Rob Haisfield22:05:24

Any great libraries or repos for beginners to play around with to learn, particularly through projects?

Rob Haisfield22:05:15

I’d be very curious about any libraries that analyze quantitative data. Statistics is super interesting to me, but I’m interested in just about anything that’s fun to play with


Is it preferable to use all and conde or *and and *or in core.logic ?


Hey all, I was wondering if there is a way in Clojure to convert a function back into it's source string, as in

user=> (defn foo [] (println "foo"))
user=> (clj->str foo)
"(defn foo [] (println \"foo\"))"


sometimes you can look up the source (if it is still around via a file somewhere) via metadata on foo

🙏 2

I tend to prefer conde and usually use fresh with no lvars, but likely should be using all


user=> (doc source)
  Prints the source code for the given symbol, if it can find it.
  This requires that the symbol resolve to a Var defined in a
  namespace for which the .clj is in the classpath.

  Example: (source filter)