This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-11
Channels
- # announcements (4)
- # aws (6)
- # babashka (40)
- # beginners (318)
- # biff (4)
- # bootstrapped-cljs (9)
- # calva (19)
- # chlorine-clover (1)
- # cider (3)
- # clj-on-windows (25)
- # cljdoc (8)
- # cljfx (1)
- # cljs-dev (30)
- # cljss (2)
- # clojure (62)
- # clojure-chile (9)
- # clojure-europe (11)
- # clojure-finland (17)
- # clojure-italy (1)
- # clojure-kc (1)
- # clojure-nl (3)
- # clojure-spec (27)
- # clojure-uk (40)
- # clojuremn (1)
- # clojurescript (51)
- # conjure (6)
- # cursive (8)
- # data-science (9)
- # datahike (4)
- # datascript (1)
- # datomic (31)
- # emacs (10)
- # emotion-cljs (1)
- # events (1)
- # figwheel-main (16)
- # find-my-lib (1)
- # fulcro (30)
- # graalvm (3)
- # graphql (12)
- # helix (16)
- # honeysql (5)
- # jobs (1)
- # jobs-discuss (10)
- # juxt (3)
- # kaocha (26)
- # lambdaisland (3)
- # leiningen (15)
- # malli (7)
- # off-topic (100)
- # pathom (8)
- # pedestal (15)
- # protojure (24)
- # re-frame (2)
- # reagent (7)
- # reitit (22)
- # remote-jobs (1)
- # shadow-cljs (140)
- # spacemacs (17)
- # spire (2)
- # tools-deps (23)
- # uix (11)
- # vim (5)
- # xtdb (3)
- # yada (3)
How do I drop :email map from [{:name '(:value-required)} {:email ()}]
since its value is empty?
(update-in
[{:name '(:value-required)} {:email ()}]
[1]
(fn [m] (dissoc m :email)))
=> [{:name (:value-required)} {}]I believe u can do drop-last
as well. As email is second element of your vector :
(def m (drop-last 1 [{:name '(:value-required)} {:email ()}]))
=> ({:name (:value-required)})@somedude314 dissoc
will remove a key from a map.
maybe you're looking for something like this?
(defn any-present?
[data]
(let [values (vals data)]
(not-every? empty? values)))
(let [value [{:name '(:value-required) :foo ()} {:email () :bar ()}]]
(->> value
(filter any-present?)
(into [])))
One thing that i find kind of tedious is specifying the latest version of a dependency. Coming from a js background where we can do something like npm i react
and it will automatically create a package.json
with the latest version of react in it ... is there something similar for clj/cljs?
@coetry It's not recommended -- because of reproducibility concerns -- but you can use "RELEASE"
as the version and you'll get the latest stable release of a library.
As an example
seanc@DESKTOP-QU2UJ1N:/mnt/c/Users/seanc/clojure$ clj -Sdeps '{:deps {selmer {:mvn/version "RELEASE"}}}'
Downloading: selmer/selmer/maven-metadata.xml from clojars
Downloading: selmer/selmer/1.12.27/selmer-1.12.27.pom from clojars
Downloading: json-html/json-html/0.4.7/json-html-0.4.7.pom from clojars
Downloading: com/fasterxml/jackson/core/jackson-core/2.9.6/jackson-core-2.9.6.jar from central
Downloading: json-html/json-html/0.4.7/json-html-0.4.7.jar from clojars
Downloading: selmer/selmer/1.12.27/selmer-1.12.27.jar from clojars
Clojure 1.10.1
user=>
1.12.27 is the current stable release of Selmer.Do clojure devs mainly do lookups on clojars to determine the latest version and only upgrade as needed?
But there's a preference for reproducible builds so it's OK to use RELEASE
for dev tools sometimes but not for builds you actually want to take to production -- we value stability.
FWIW, I use "RELEASE"
a lot for quick dev exploration and testing, and most of my "dot clojure" file uses "RELEASE"
deliberately to always pull in the latest versions of dev/test tooling.
Depot is an equivalent for the Clojure CLI / deps.edn
Related question... I've tried this several ways to no avail:
(ns test.core
(:gen-class))
(defn -main []
(load-string (slurp "/Users/hlodowig/stuff.clj"))
(println stuff))
stuff.clj
(def stuff {:a 1 :b 2 :c 3})
I'm getting Syntax error compiling at (test/core.clj:6:3). Unable to resolve symbol: stuff in this context
Either I'm misunderstanding read-string completely or I'm making a very basic mistake. TIA.
But I do wonder if you could just define stuff with a stand in value, and then let stuff.clj override it
At the same time I'm not sure if this is best practice. I can't say for sure though cause I don't know your goal.
I imagine something like load-string
is best used in the REPL.
Use EDN instead of trying to write config-as-code.
Configuration should be "just" a data structure. In your example, stuff.edn
would contain {:a 1 :b 2 :c 3}
and you would use clojure.edn/read-string
-- https://clojure.github.io/clojure/clojure.edn-api.html#clojure.edn/read-string -- to turn it into Clojure data
https://clojuredocs.org/clojure.core/read-string https://clojuredocs.org/clojure.core/eval
Related question... I've tried this several ways to no avail:
(ns test.core
(:gen-class))
(defn -main []
(load-string (slurp "/Users/hlodowig/stuff.clj"))
(println stuff))
stuff.clj
(def stuff {:a 1 :b 2 :c 3})
I'm getting Syntax error compiling at (test/core.clj:6:3). Unable to resolve symbol: stuff in this context
is there a way to alias a macro? (i'd want to alias cljs.core.async.interop/<p!
as await
)
cljs.user=> (require '[clojure.core.async.interop :as interop :refer [<p!] :rename {<p! await}])
nil
cljs.user=> (source await)
(defmacro <p!
"EXPERIMENTAL: Takes the value of a promise resolution. The value of a rejected promise
will be thrown wrapped in a instance of ExceptionInfo, acessible via ex-cause."
[exp]
`(let [v# (cljs.core.async/<! (cljs.core.async.interop/p->c ~exp))]
(if (and
(instance? cljs.core/ExceptionInfo v#)
(= (:error (ex-data v#)) :promise-error))
(throw v#)
v#)))
nil
cljs.user=>
What's the idiomatic way of doing something like this idea, where I need to select the function to apply for next loop iteration? Should I put the test+function selection in a separate let before recur not to break tail call optimization?
(loop [fn-to-apply 'fn1
items items-to-process]
(let [[item & remaining-items] items
apply-result (fn-to-apply item)]
(if (apply-ok? apply-result)
(recur 'fn1 remaining-items)
(recur 'fn2 remaining-items))))
Beware, I just banged this out on the keyboard, haven't checked for syntax errors etc. Just as an idea illustration. :)You do not need quotes before fn1
or fn2
in that code.
The Clojure compiler will always tell you if recur
cannot be compiled because it is not in tail position. Those example should both be in tail position.
That particular code is an infinite loop, unless something throws an exception, by the way, since all cases recur
You could also replace the entire (if ...)
with something like this, if you like: (recur (if (apply-ok? apply-result) fn1 fn2) remaining-items)
Yeah, thanks. I wasn't sure of the "right" way to do something like this 🙂
And yes, I need a base case for sure 🙂
hi, how would you do your schema migrations in a clojure-app? i'm familiar with https://flywaydb.org/ which has java api, anyone used https://github.com/weavejester/ragtime or https://github.com/yogthos/migratus
I see it is not maintained for a while, does it have any audit feature? to see all db executions
so what are your main usages of ragtime? in workplace*
uh, migrate the database without having to manually run sql. we don't have strict audit requirements regarding database schema (yet)
I see it's not possible to rollback in the free-edition
how do you handle that?
One is never 100% confident with software. It could fail at any point. However, I ensure that I've tested to an inch of its life locally.
I see that the other lib's deal with rollback just as they perform the opposite-execution
those libs do up-down with create-drop
an 'undo' of 'flyaway' isn't really a rollback then
you have to write the .sql file yourself
you don't
i'm just saying that the 'undo' in flyway is not a rollback
sql migrations, no matter the tech, are always fraught with the potential of scrwing your db up tremendously 🙂
youv'e been using the 'undo' then?
what's the clojurescript equivalent of import Foo from 'bar'
? i can't seem to get it working
umm i still can't get it working. i'm trying to use this react component from re-frame: https://github.com/jakezatecky/react-checkbox-tree#render-component
i :require ["react-checkbox-tree" :default CheckboxTree]
but then
(def checkbox-tree
(reagent/adapt-react-class CheckboxTree))
yells at me saying "Component must not be null c". what am i doing wrong?Hey. I was facing the same error too. Try this
(:require
["react-checkbox-tree" :as CheckboxTree])
(defn checkbox-component []
[:> CheckboxTree
{:nodes [{:value "a" :label "b"}]}])
It should be defn
and not def
'cos when I used def, it said expecting a function. Also the react-checkbox-tree
expects :nodes
as required property.
figured it out so made an example out of it too https://github.com/valerauko/checkbox-tree-example
How do I test a function is returning a specific map in (testing ... (is (= (func args) {:key :val} doesn't seem to work
Sorry false report. My function had some problems. I got confused because (is) wasn't giving me the actual output.
Is there anything that could help me get vector elements out of it?
for example if I (conj [1 2 3] [4 5])
the result would be [1 2 3 [4 5]]. while what i want from conj
is [1 2 3 4 5]
but the phrase "what i want from conj" sounds strange. conj can do it in this case though
to me this looks like a classic use case for into
thank u all. concat, into
and apply
all work out.
but then can i use them in reduce on characters of a string?( i want to analyze characters.
but i get Don't know how to create ISeq from: java.lang.Character.
on following code:
(defn stack [one two]
(if-let [oneLast (last one)]
(if-not (and (= oneLast \() (= two \)))
(into [] (concat one two))
(into [] (drop-last 1 one)))
[two]))
(defn reduceStack []
(let [reducedStack (reduce stack (seq string))]))
and then i use this "stack" to reduce a string.(and findout if it used the right parentheses.)(concat one two)
makes no sense if two could be equal to \)
you can use (conj one two)
if one
is a vector and two
is an element for the vector
also you can replace (into [] (drop-last 1 one))
with (pop one)
if one
is a vector
also, the last arg to reduce
is always processed via seq
, you don't need to do that by hand
@U014CTZJK2S how could one
be a character if above you call last
on it?
I think you need to step back and think more clearly about the data representation here
@U014CTZJK2S a subtle and easy to miss error: you use reduce without the optional init
arg, which means that on the first iteration, you get a Character
as your "one", and on all further iterations you would get a Vector
that way the data type provided to stack
remains consistent
also, you can simplify your code with the stack oriented functions (which work on vectors) peek
(gets the last item of a vector) pop
(gets the vector without the last element)
@noisesmith Yes u are right. but still i get "Don't know how to create ISeq from: java.lang.Character" from :
(defn stack [one two]
(let [lastOne (last one)]
(if (and (= lastOne \{) (= two \}))
(pop one)
(conj one two))))
(defn reduceStack []
(let [reduced (reduce stack [(first string) (rest string)])]
reduced))
Am I doing something wrong with string?you want (reduce stack [(first string)] (rest string))
and then the rest should just work
you are using an extra arg to reduce here (one which many of us wish was mandatory...)
@noisesmith Thank you so much. saved me hours ....
Does anyone have a bibtex for https://download.clojure.org/papers/clojure-hopl-iv-final.pdf ?
what is that?
is that like a latex file
it's a file used to make latex bibliographies http://www.bibtex.org/
source for the paper is latex so I can ask Rich if it's somtehing he might already have
A bibtex entry looks something like this:
@inproceedings{hickey2008clojure,
title={The Clojure programming language},
author={Hickey, Rich},
booktitle={Proceedings of the 2008 symposium on Dynamic languages},
pages={1},
year={2008},
organization={ACM}
}
It's what you need to cite one paper in another paper.so are you looking for the list of references in the paper?
or the reference for this paper itself?
No, I'm interested in citing This new clojure paper in another paper i'm submitting to Dynamic Languages Symposium in one month.
the info you need is in the footer isn't it?
this is a pre-print, I don't think the proceedings have actually been published yet
Yes, I can reconstruct it. But normaly one uses the official bibtex entry provided by the author or the publisher. But yes, it's not so difficult to construct one from scratch.
ACM Reference Format:Rich Hickey. 2020. A History of Clojure.Proc. ACM Program. Lang.4, HOPL, Article 71 (June 2020), 46 pages.
Is that a journal, or a conference preceedings. I think it is a journal.
conference proceedings
ahh. good, I guessed wrong. HOPL is History of Programming Languages?
see links
Nice article by the way.
I'm wanting to make a chatroom ... I thought about using Chord but the example project is not compiling... Sente is great but a little bit of overkill. Ideally I want: A) way to refer to each user connected and B) back-end server so I can serve static html as well
some kind of websockets connection will undoubtledly be needed. sente sounds right up your alley and correct-amount-of-kill
if you’re interested in an example. I recently made a simple web app that let’s you play a networked board game with friends. It’s uses websockets to sync data between the open tabs: https://github.com/phronmophobic/wavelength_helper/tree/networking webserver code: https://github.com/phronmophobic/wavelength_helper/blob/networking/src/wavelength_server/core.clj single file html/css/js: https://github.com/phronmophobic/wavelength_helper/blob/networking/resources/public/index.html
all messages sent to the server on the websocket are broadcast to all the other users in the same “room”. there’s not a chat room, but it would be pretty straightforward to adapt for that use case
I've combined websockets and coreasync, which has some pubsub capabilities. I thought they were a nice combo. I also felt sente was kinda heavy for my modest needs.
Often a site which lets you download a paper, also lets you download the bibtex.
Any suggestions for extremely lightweight two-way comms with subscriptions?
Maybe https://github.com/jarohen/chord or https://github.com/lynaghk/jetty7-websockets-async

figured it out so made an example out of it too https://github.com/valerauko/checkbox-tree-example
I don't understand how to use set!
to change the value of a global variable. Is this deprecated now? https://clojuredocs.org/clojure.core/set!
What is the correct way to write a macro which registers a global resource. e.g., a top level defsomething
macro ?
Here's what I tried with swap! but it doesn't work
(def supported-nontrivial-types
"Which types are currently supported? This list denotes the
type names which appear as (something maybe-args), which are
supported by RTE. The goal is to support all those supported
by typep, but that's not yet implemented."
(atom #{}))
(defmacro register-type [type-name]
`(swap! supported-nontrivial-types
(fn [_] (conj @supported-nontrivial-types '~type-name))))
(register-type rte)
(register-type =)
(register-type member)
at (register-type rte)
i get the following error
Show: Project-Only All
Hide: Clojure Java REPL Tooling Duplicates (23 frames hidden)
2. Unhandled clojure.lang.Compiler$CompilerException
Error compiling src/clojure_rte/rte.clj at (126:1)
#:clojure.error{:phase :macro-syntax-check,
:line 126,
:column 1,
:source
"/Users/jimka/Repos/clojure-rte/src/clojure_rte/rte.clj",
:symbol clojure.core/fn}
Compiler.java: 6971 clojure.lang.Compiler/checkSpecs
Compiler.java: 6987 clojure.lang.Compiler/macroexpand1
Compiler.java: 7092 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6789 clojure.lang.Compiler/analyze
Compiler.java: 6745 clojure.lang.Compiler/analyze
Compiler.java: 3888 clojure.lang.Compiler$InvokeExpr/parse
Compiler.java: 7108 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6789 clojure.lang.Compiler/analyze
Compiler.java: 6745 clojure.lang.Compiler/analyze
Compiler.java: 6120 clojure.lang.Compiler$BodyExpr$Parser/parse
Compiler.java: 5467 clojure.lang.Compiler$FnMethod/parse
Compiler.java: 4029 clojure.lang.Compiler$FnExpr/parse
Compiler.java: 7104 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6789 clojure.lang.Compiler/analyze
Compiler.java: 7173 clojure.lang.Compiler/eval
Compiler.java: 7131 clojure.lang.Compiler/eval
core.clj: 3214 clojure.core/eval
core.clj: 3210 clojure.core/eval
main.clj: 414 clojure.main/repl/read-eval-print/fn
main.clj: 414 clojure.main/repl/read-eval-print
main.clj: 435 clojure.main/repl/fn
main.clj: 435 clojure.main/repl
main.clj: 345 clojure.main/repl
RestFn.java: 137 clojure.lang.RestFn/applyTo
core.clj: 665 clojure.core/apply
core.clj: 660 clojure.core/apply
regrow.clj: 20 refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 79 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 55 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 142 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 171 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 170 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 834 java.lang.Thread/run
1. Caused by clojure.lang.ExceptionInfo
Call to clojure.core/fn did not conform to spec.
#:clojure.spec.alpha{:problems
({:path [:fn-tail :arity-1 :params],
:reason "Extra input",
:pred
(clojure.spec.alpha/cat
deref of the thing you swap! on inside swap! is an error
the value of the thing is passed to the swapping function, that's the value you need to use
`(swap! supported-nontrivial-types
conj '~type-name)
also, this is symbol in / symbol out, you can just use '
in the initial call and use a function instead of a macro
finally, the compilation error is because (fn [x] ...)
is invalid inside ` - the transform turns x into ns/x which is an invalid binding
Ahh I've had this problem many times. what is the correct way to put an anonymous function inside a quasiquote?
but you don't want that here, for reasons already described
great that works.
so this works as well.
(defmacro register-type [type-name]
`(swap! supported-nontrivial-types
(fn [_#] (conj @supported-nontrivial-types '~type-name))))
but as you pointed out this is simpler:
(defmacro register-type [type-name]
`(swap! supported-nontrivial-types
conj '~type-name))
the fn is not needed, and the deref inside swap! is a race condition
not just simpler - actually correct
if you need the anon-fn in the future, use the value passed in instead of calling deref inside the body:
(fn [v#] (conj v# ...))
Used to set thread-local-bound vars, Java object instance
fields, and Java class static fields.
set! is specifically for thread local (`^:dynamic`) vars, and java interopto create a var, you can use def
or intern
cautious in what sense?
no, its a global definition whose value needs to change as the program loads. In the same sense that defmulti
defines a global resource and defmethod
updates it. Or defn
defines a global function. These are not generally seen as something to avoid.
an example of a common pattern is the spec registry.
that's an atom
that gets swapped: (swap! registry assoc key some-spec)
I was trying to use atom and swap. but couldn't make it work.
that was a macro error, described in the thread under that code
but there are multiple problems before hitting the macro error
Yes I already put that in a thread. https://clojurians.slack.com/archives/C053AK3F9/p1591892827089000
it doesn't need to be a macro, doesn't need an anon fn even if it was a macro, and shouldn't be derefing inside swap!
@ghadi, would you rather write a call to swap!
or a (defmethod ...)
? of course defmethod
doesn't have to be a macro, but it is friendlier.
you need to clarify the higher level goal to choose between a simple set containing values or open dispatch (a multimethod)
are you associating different behavior with the different registered things? then multimethod
if you must declare something before using it, but all things are handled the same way, then a set is sufficient
Yes, depends on the situation. But in general the correct way to manage global resources in clojure has been unclear to me.
i think you might need something like mount https://github.com/tolitius/mount
the best answer is to not have a global resource, but instead to instantiate your resource when the program starts and give it to the code that needs it
if it's stateful, wrap it in an atom
based on the example code, I think "resource" is being used loosely here. in clojure itself, there are multiple examples of a central registry that gets appended as you develop - defmethod, defprotocol, ns, spec
where the registry itself is an implementation detail, but the behavior offered is the same variety as @jimka.issy is trying to implement
so a first hint might be not making the registry part of the public api, if you do need one
Yes this is what I'm calling a global resource. i.e., the global set of multi methods, or the global set of name spaces.
and yes, one reason for the macro is to hide the implementation using atom
and swap!
after various experiments and designs, my current heuristic is to avoid things that are not referentially transparent, whether implemented by myself or clojure, and if I can prove I need something that's spooky (eg. driven by a hidden mutable registry), I stick to the thing that's already in clojure itself unless I can prove I need a new one whose behavior clojure can't do properly
I need a small amount of spookiness in order to do normal repl dev, of course. But beyond that I can keep it pretty minimal.
Does that mean you make your implementation details apparent to the user of the API? Isn't that limiting if you want to change the implementation later?
if my implementation is value focused and referentially transparent, there are no details to leak
but for a case like yours - you could use a multimethod and then dispatch on a symbol, where a simple false is the default method output, and true is set for anything you extend
I'm not sure what referentially transparent means in this context. normally it means you can replace a reference with the implementation. right?
right - so you aren't using mutation of some other location in application logic
isn't defining a method a mutating operation?
so a defmulti version of what you had above:
(defmulti registered? dispatch)
(defmethod registered? :default [_] false)
(defmethod registered? '= [_] true)
right - as I said, I avoid those things, but when I need them, I prefer something already in the language
And how do I get the set of registered symbols, to iterate over them, or to print them in a diagnostic message?
I picked defmulti because it looked like the set of registered things would be extended arbitrarily by client code
I guess it would use the method reflection api?
explicitly throwing away :default?
that makes it uglier, I didn't realize you needed the registered items for iteration
In my case each symbol registered adds a new syntactical element to a DSL.
when the DLS is parsed, and an unregistered symbol is encountered, I print the valid symbols as part of the error message.
(remove #{:default} (keys (methods m)))
seems like it would do that
frankly, even though I was skeptical, its not a bad suggestion.
it's a bit of a forced fit sadly - you could wrap the fact that it's a multi with a simple set of functions
Here is where it is used https://gitlab.lrde.epita.fr/jnewton/clojure-rte#how-to-extend-the-type-system
in case you're interested
anyway, you don't need a "reflection api"
(ins)user=> (doc methods)
-------------------------
clojure.core/methods
([multifn])
Given a multimethod, returns a map of dispatch values -> dispatch f
ns
nil
Hi friends! 👋 I’ve been working through the https://exercism.io/tracks/clojure using Emacs with Cider and Paredit. I struggle with the ergonomics of Clojure. For a while I had problems with wrapping a form in another form but I’m gradually getting used to slurping with Paredit and that’s ok now. A thing which hasn’t cleared up so much is how to investigate how a program works. Like evaluating some part of a bigger form in order to see what I get, or just dropping in some logging. Does anyone have experience with https://github.com/clojure/tools.trace/https://github.com/clojure/tools.trace/? I think pairing with, or just watching a seasoned Clojurist work for a while might help me discover good techniques. I’d be grateful for any advice or links to videos or other material. Thanks! :)
If you are already using CIDER, you are in luck. https://docs.cider.mx/cider/debugging/debugger.html
There are a bunch of other things there, apart from the debugger. I have not used those, but looks super helpful.
also consider that if you are coding idiomatically (using immutable data) you can use swap!
or def
to capture data in a function, and then use it as you like in the repl
eg.
(def debug-data (atom []))
(add-tap (fn [x] (swap! debug-data conj x)))
(defn f [x y x]
(tap> {:context ::f :x x :y y :z z})
...)
where f
is some existing functionthere are a few corner cases where a proper debugger like in CIDER is still clearly better (when using volatile state / ephemeral objects that lose meaning outside one narrow context), but good clojure code minimizes such things, and the technique using tap> and an atom works everywhere (no matter your editor or run environment)
a variant for code you don't control:
(alter-var-root #'some-lib/foo (fn [f] (fn [& args] (tap> {:context :some-lib/foo :args args}) (apply f args)))
So for example when I want to tap some data I’d replace (existing-form)
with (do (tap> a) (existing-form))
pretty much - you can send whatever you want to tap> - note that defn, let, when etc. all have implicit do already
So the “variant for code you don’t control” is like wrapping a function and tapping function args?
yeah - the basic template is (alter-var-root #'foo/bar (fn [f] (fn [& args] (apply f args)))
- that's the no-op version, but you can fill in any other logging / inspection / alteration of args or return value as needed for debugging
And that’s something you’d do in a REPL? Some (in-ns 'x)
and then do the thing with a symbol?
you don't need to change namespace - it takes a fully qualified var
yes, this is something you'd set up via a repl or scratch buffer
(ins)user=> (alter-var-root #'clojure.core/subs (fn [f] (fn [& args] (println "subs:" args) (apply f args))))
#object[user$eval208$fn__209$fn__210 0x1ab6718 "user$eval208$fn__209$fn__210@1ab6718"]
(ins)user=> (subs "hello" 1 3)
subs: (hello 1 3)
"el"
(cmd)user=> (subs "hello" 3)
subs: (hello 3)
"lo"
A scratch buffer is just a place to evaluate some forms from? Can you use Emacs normal scratch buffer for this?
there are gotchas (like you need to require / reload the entire namespace to get the old def back), but it is a useful trick
yeah, by scratch buffer I just meant code that isn't part of your project that you can send to your repl, some people find that preferable to typing into a repl directly
there's a special cider-scratch buffer iirc (I haven't used emacs in years)
exactly
I'll often have a separate file, not in project source control, where I combine links to places in the project code, exploratory repl snippets, and a to-do list, with the work ticket in the file name oh, and I'll put sample data captured in the functions I'm interested in the file too
in emacs org-mode is perfect for this sort of thing IMHO
vim - but any editor would work with this workflow (I do have plugins that run a repl in a buffer, and send a selection to that repl etc. but could copy/paste the normal way...)
Ok! I have years of experience with vim but figured I try some Emacs with Clojure. Tried vim-fireplace in vim. Are you using some sexp editing tools as well?
vim-clojure-static, vim-sexp, neoterm and fireplace in neovim
I start nrepl in a neoterm terminal, use neoterm to send selections to that terminal buffer (I like this as it gives me a trace of things I tried and outputs as the repl scrollback), and then I use fireplace for :Require
which just reloads the whole file, and sometimes the jump-to-def and show-docs features of fireplace
I like vim-sexp because I use text-objects heavily in editing, and that maps perfectly to clojure forms
I should make a blog post, but so much of what I do is just copied from talks / posts by others in the community most of the work would be in collecting and properly citing references
Is there a reason I keep seeing
java.lang.IllegalAccessException: class clojure.lang.Reflector cannot access class jdk.internal.loader.BuiltinClassLoader (in module java.base) because module java.base does not export jdk.internal.loader to unnamed module @5aa6da2
Which JDK ought I be using?
Any jdk will work
Many reflective calls will be reported this way now unfortunately, even though a type hint is really needed in the Clojure code
https://clojure.org/guides/faq#illegal_access has more detail on this
does it make any sense to ask the upstream java people to put it back? lol
complecting at a distance
Missing a typehint... hmm
if you use the debug flag it's usually pretty clear where the issue is
--illegal-access=debug
I don't know where to add that flag. Is it a jvm-opts? I'm using lein to run a project
What is "^:journal" here? Not "^", I get that's meta. https://clojuredocs.org/clojure.core/comment#example-5d28745ae4b0ca44402ef783
nothing special, just an example of a meta keyword
(ins)user=> (meta ^:journal {})
{:journal true}
various tools / libs use metadata, it's kind of a grab bag
oh 😆 that example is incorrect
(ins)user=> (meta ^:journal 'foo)
nil
(ins)user=> (meta '^:journal foo)
{:journal true}
someone should edit that page
well the example showing it doesn't work still doesn't work so that part's not wrong :)
but the example claiming it works - while irrelevant to the thing being documented - is still incorrect
could just use a []
that's likely clearer, yes
haha, thanks, I didn't have login handy or I would have done it myself
What's the common way to break long string literals to keep line width reasonable? Do people just use something like (str "long string 1" <line break here> "long string 2")
?
also you can put it in a file and load it with io/resource
of course
Living Clojure and Getting Clojure are good books for that. Can't remember when they came out but they're relatively recent.
Online, there's a version of Clojure for the Brave and True -- some people find it too quirky, and it starts out assuming you're going to learn Emacs which some people think is a bit much if you're trying to learn both Clojure and Emacs at the same time.
And there's the official Getting Started material https://clojure.org/guides/getting_started
That has a lot of links to books, tutorials, and so on.
Thanks @seancorfield ... guess I am on the right track, just got started with Living Clojure
👍
be sure not to miss this (linked from the page @seancorfield shared) https://clojure.org/guides/learn/syntax
it's a really good "learn how to fish" intro that relies on built in documentation and discoverability in the language itself
@noisesmith Thanks, will take a look at that too 👍
http://clojure.org also has a books page https://clojure.org/community/books