This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-02-23
Channels
- # announcements (2)
- # atom-editor (3)
- # babashka (49)
- # beginners (100)
- # biff (9)
- # calva (78)
- # clj-kondo (18)
- # clojure (143)
- # clojure-europe (13)
- # clojure-germany (1)
- # clojure-nl (2)
- # clojure-spec (5)
- # clojure-sweden (2)
- # clojure-uk (4)
- # clojurescript (58)
- # conjure (1)
- # cursive (4)
- # datascript (11)
- # datomic (63)
- # docker (7)
- # emacs (18)
- # events (1)
- # fulcro (18)
- # graalvm (5)
- # helix (4)
- # improve-getting-started (13)
- # jobs (4)
- # jobs-discuss (3)
- # lsp (15)
- # malli (90)
- # membrane (14)
- # off-topic (12)
- # other-languages (5)
- # pedestal (7)
- # polylith (53)
- # re-frame (15)
- # reitit (23)
- # releases (4)
- # remote-jobs (9)
- # ring (11)
- # shadow-cljs (90)
- # specter (2)
- # testing (3)
- # tools-build (63)
- # vim (2)
- # xtdb (8)
Let’s say I have a binding path
that can either be a vector of primitive values, e.g. [:a "a" 0]
or a vector of similar vectors, e.g. [[:a "a" 0] [:b "b" 1]]
. I want to append a new item to the end of the vector if it is the former, or the end of every sub-vector if it is the latter.
Currently my approach is (if (seqable? (first path) ...))
and just handling each case separately. It works but I’m wondering if there’s a more concise way to do this that I don’t know of.
is it possible to treat the vector of primitives as a collection of vectors or primitives but it only has a single value? Just homogenize into the plural case all the time?
just accept that you're dealing not with a path but paths
even if it might often be only a single path there?
What do you think is the best way to learn clojure? Tutorials or books? Videos or written tutorials? What's the best way of finding them?
I think this depends heavily on an individual’s learning style, so there isn’t one perfect answer.
Personally… I learned Clojure by first learning Scheme through the https://www.youtube.com/watch?v=-J_xL4IGhJA&list=PLE18841CABEA24090. This taught me the fundamentals of programming without mutation. Then I learned about using immutable data structures through https://www.artima.com/shop/programming_in_scala_5ed. And finally, I learned Clojure from the original https://pragprog.com/titles/shcloj3/programming-clojure-third-edition/ by Stuart Halloway, Aaron Bedra, and Alex Miller. (Although, I read the first edition, which was only by Stuart). I liked the book, since it covers all of the elements of the language that might be glossed over or skipped in less comprehensive materials.
I feel like I enjoy tutorials the best, but they are on all sorts of different blogs, and can be a bit hard to find
Books are great but can be outdated quickly
Or is it best to just read documentation? I think I'm almost getting to a point where I can start doing that, but definitely couldn't at the beginning
I would note that Clojure, the language itself, has grown primarily by additions over the years, not by taking things away or modifying them. Thus even several-year-old books tend to have a lot more relevance today than the same age book for a language that changes more rapdily (which is a lot of programming languages).
I have not read it myself, but I have heard glowing reviews of the book "Getting Clojure".
I’m with Andy here: Clojure books tend to stay relevant over time. That said, very old books don’t have all of the newest features of the language. For instance, the first read the first edition of Programming Clojure did not have Protocols in it, and these had just come out as I was reading it
Since then, a lot of things have been introduced. But none of the old stuff has gone away. So even if you read an ancient book, you’ll still learn a lot.
Cool, thanks. That's really good to know
I would say that any book written for Clojure 1.7 and later would be good these days.
I used a combination of resources, including some from https://clojure.org/community/resources I also created some online books and videos at https://practical.li/
Hi I am wondering if it is possible to get the full classname by macro? i.e. for the last line below to return "java.lang.String"
(import '[java.lang String])
(require '[clojure.reflect :as cr])
(defmacro clsname [x]
(cr/typename x))
(cr/typename String) ; returns "java.lang.String"
(macroexpand-1 '(clsname String)) ; returns "String"
the reason i want this is because i am sending a lot of requests like a.b.c.ReqXXX
and getting responses like a.b.c.RespXXX
. The data format is binary, so I need to know what class to cast/deserialize when response arrives, and will like to 'guess' the response class during compile time.The evaluating the symbol resolves it against *ns*
which is going to return the java.lang.String class object
Hard to say, regardless I would step way back from this problem, and reexamine your original goal, and maybe ask about that
Here’s an example I found from stackoverflow.
(def listener
(proxy
;; first vector contains superclass and interfaces that the created class should extend/implement
[KeyAdapter ActionListener]
;; second vector contains arguments to superclass constructor
[]
;; below are all overriden/implemented methods
(keyPressed [event]
(println "Key pressed" event))
(actionPerformed [action]
(println "Action performed" action))))
There are some limitations with proxy
so it'll depend on exactly what you need. See https://ask.clojure.org/index.php/3360/support-abstract-base-classes-with-java-only-variant-reify for example.
@U04V70XH6 Ok, Thanks. In fact I was learning netty from their official documentation. I was told to extend some classes like`ChannelInboundHandlerAdapter` to write a simple “discard server”. So I wondered how to do this kind of stuff in clojure. Or is there any idiomatic way to do things like that?
@U0NCTKEV8 May be able to offer some advice as he's worked with Netty (and I suspect he may have more general insight into extending abstract classes too).
(we have (proxy [io.netty.channel.ChannelInboundHandlerAdapter] [] ...)
in the code at work)
we have the proxy of ChannelInboundHandlerAdapter, but now (and I forget why exactly I decided we needed this instead of the proxy) we also have a defrecord that implements the interface (instead of the abstract class), and implements all the methods by either calling a passed in clojure function, or passing it on through the context
the defrecord in that case basically does the same thing for us a the abstract class does, but lets us override different parts by just passing in different clojure functions when constructing the record
@U0NCTKEV8 Thanks. I’ve tried using the proxy of ChannelInboundHandlerAdapter
and tried to add it to the channel pipeline as an instance of ChannelHandler
. But I got the following error:
>
java.lang.ClassCastException: class clj_netty_demo.core.proxy$io.netty.channel.ChannelInboundHandlerAdapter$ff19274a cannot be cast to class [Lio.netty.channel.ChannelHandler;
I’m getting confused. I’ve thought the proxy is something like Anonymous class In java, but seems it’s not correct.Here’s my code:
(defn- ->handler []
(proxy [ChannelInboundHandlerAdapter]
[]
(channelRead [this ctx msg]
;;(.release msg)
(try
(while (.isReadable msg)
(print (.readByte msg))
(flush))
(finally
(ReferenceCountUtil/release msg))))
(exceptionCaught [this ctx cause]
(.printStackTrace cause)
(.close ctx))))
[Lio.netty.channel.ChannelHandler;
means "array of" so you're passing your proxied object to something that is expecting an array of channel handlers. You'll need to look at the stacktrace and see where exactly that error is coming from @U031NJ4ERUP
Example:
dev=> (class (into-array Long [1 2 3]))
[Ljava.lang.Long;
So that's Long[]
in Java terms: an array of Long
objects.Hi guys I have this map here (def group-by-data {:data [{:_sub-by "leon", :items [{:bags 3, :weapons "Pistols"}]}]})
and I would to transform it to be something this {:data [{:bags 3, :weapons "Pistols", :_sub-by "leon"}]}
any ideas on how to go about this?
Depends on what exactly you're trying to achieve and what your data looks like. Do you just want to extract the contents of :items
to the underlying map? Is the sequence under :items
always going to be exactly of length 1? Are the keys for entries under :items
always going to be the same?
yes I would want to extract the contents of :items
to the underlying map, meaning the sequence under :items
will be of the same length
so that the new map would be something like this {:data [{:bags 3, :weapons "Pistols", :_sub-by "leon"}]}
I hope that makes sense 😅
Makes sense, sure. Even so, how about the two other questions? 1. Is the sequence under `:items` always going to be exactly of length 1? 2. Are the keys for entries under `:items` always going to be the same?
Yes the sequence under :items
will be of length 1 and the keys are always going to be the same
(update group-by-data :data
(fn [data]
(->>
data
(map
(fn [{:keys [:items]
:as datum}]
(->> (first items)
(into (dissoc datum :items))))))))
How should I go about restricting the maximum amount of threads calling a specific function to n? The function I need to call does (potentially blocking) i/o and reports whether it's successful.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/Executors.html#newFixedThreadPool(int) maybe, if I understood correctly?
That looks exactly like what I was looking for. I just realized I used it before too 😅 Thank you.
What would "Invalid token : : " be in context of slurping?
I get a giant string from an API and can't seem to make progress in lieu of read-string
(clojure.edn/read-string "::foo")
Execution error at vault.code/eval5456 (REPL:382).
Invalid token: ::foo
https://clojure.org/guides/weird_characters#autoresolved_keysHow do I pass a java interop function to another function and call it in the function ?
(defn foo [x]
(x 2 3))
(foo +) ;; works
(foo *) ;; works
(foo /) ;; works
(foo -) ;; works
(foo Math/pow) ;; doesn't work
This doesn't work either:
(foo #(Math/pow))
I'd like to be able to pass a function that can be either one of my functions, or a java interop function or a regular clojure function.
So, If I want to use interop functions. I can wrap them ?
(foo (fn [x y]
(Math/pow x y)))
This works?but fyi, in Clojure 1.11, you can pass the new clojure.math/pow
function!
(and we are considering some additional interop that would help in cases like this for 1.12)
@U064X3EF3 what would it take (or is it even possible) to have java functions with a suitable arity “just work” as clojure functions? Tried staring at some decompiled clojure code and wrapping my head around the moving pieces but think I came up a tad short.
mostly wondering whether it falls into “no it’s just not doable” or “yes, in theory but would have horrible performance” kind of bucket
it is doable, but complicated :)
Invoking this fn results in an error at repl
(defn from-file
"Read from file"
[filename]
(->> (with-open [r ( filename)]
(cheshire/parse-stream r))
(map (fn [x] (clojure.walk/keywordize-keys x)))
(map (fn [x] (update x :open-time #(jt/instant %))))
(map (fn [x] (update x :close-time #(jt/instant %))))))
; Error printing return value (IOException) at .BufferedReader/ensureOpen (BufferedReader.java:122).
; Stream closed
I assume this means that the file is already closed when repl tries to print stuff. What should I do here?> If the top-level object is an array, it will be parsed lazily (use > `parse-strict’ if strict parsing is required for top-level arrays. From this and your use of map i’m assuming you have a top level array. Your intuition is correct, you are working on the structure after the file has been closed and the whole structure is not in memory but is lazy.
I'm using spec in my tests via s/valid?. When it fails, I edit it to s/explain to look at the error. A little tedious. Is there a better way?
is
can take an optional docstring. (is (s/valid? spec value) (s/explain spec value))
should print the explanation in the failure case. Caveat as you know is that it can get decently verbose
(s/def ::x (s/keys :req-un [::k]))
(s/def ::k even?)
(s/valid? ::x {:k 3})
(is (s/valid? ::x {:k 3}) (s/explain ::x {:k 3}))
metadata=> (is (s/valid? ::x {:k 3}) (s/explain ::x {:k 3}))
3 - failed: even? in: [:k] at: [:k] spec: :nocommit.metadata/k
false
Trying to base64 encode a string. I've required java.util.Base64 in my source file, but keep getting an error when compiling:
(ns mercator-server.core
(:require
[java.util.Base64 :refer [.encodeToString getEncoder .getBytes]]))
clj꞉user꞉>
; Evaluating file: core.clj
; Syntax error (FileNotFoundException) compiling at (c:\Users\fadrian\Projects\mercator-server\src\mercator-server\core.clj:1:1).
; Could not locate java/util/Base64__init.class, java/util/Base64.clj or java/util/Base64.cljc on classpath.
; Evaluation of file core.clj failed: class clojure.lang.Compiler$CompilerException
I'm running a CLI tools project under Calva. How can I get this to compile without the error message?}java classes must be :imported
rather than required. Require is specific to clojure code
(ns foo
(:import java.util.Base64))
(let [encoder (Base64/getEncoder)
decoder (Base64/getDecoder)]
(String. (.decode decoder (.getBytes (.encodeToString encoder (.getBytes "bob"))))))
Thanks. I found the encoder code already. I was just getting the compilation error. I've checked it out and everything works now. Thanks again.
I have a couple of CLI tools projects structured as follows:
|
|
+-libname +
| |
| +--deps.edn
| |
| +--src/libname +
| +--A.clj (libname.A namespace)
| +--B.clj (libname.B namespace)
| +--C.clj (libname.C namespace)
|
|
+-- server +
| +--deps.edn
| +--src/server-- +
| + core.clj (server.core namespace)
The deps.edn for the two files are as follows:
;; libname/deps.edn
{:paths
["src/libname"]
:deps
{org.clojure/clojure {:mvn/version "1.10.3"}
org.clojure/data.csv {:mvn/version "1.0.0"}
}
:jvm-opts ["-XX:-OmitStackTraceInFastThrow"]
;; server/deps.edn
{:paths
["src/server"]
:deps
{org.clojure/clojure {:mvn/version "1.10.3"}
compojure/compojure {:mvn/version "1.6.2"}
http-kit/http-kit {:mvn/version "2.5.3"}
ring/ring-json {:mvn/version "0.5.1"}
server/A {:local/root "../libname"}}
:jvm-opts ["-XX:-OmitStackTraceInFastThrow"]}
}
My ns declaration in server/core.clj is:
(ns mercator-server.core
(:require [compojure.core :refer [defroutes GET POST]]
[org.httpkit.server :refer [run-server]]
[ring.middleware.json :refer [wrap-json-body]]
[libname.A :refer [translate]])
(:import [java.util Base64]))
Here, I'm attempting to call the translate function from libname/A.clj (which depends on B.clj and C.clj). However, when I attempt to compile the code I get an error:
; Evaluating file: core.clj
; Syntax error (FileNotFoundException) compiling at (c:\Users\fadrian\Projects\server\src\server\core.clj:1:1).
; Could not locate libname/A__init.class, libname/A.clj or libanme/A.cljc on classpath.
; Evaluation of file core.clj failed: class clojure.lang.Compiler$CompilerException
What am I doing wrong in the deps.edn for the server library and why is it not finding libname/A, when I tell it the :local/root for it in the server's deps.edn?I tried that - I'm still getting the same error when I try to compile/load the file server/core.clj.
Thank you. It wasn't just the src thing - it was also some -/_ confusion in a couple of the filenames.
might want to thread this sort of thing in the future