This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-07-24
Channels
How do I turn a RANGE into a LIST? (vec (range 5)) -> [0 1 2 3 4] ;whereas (list (range 5)) -> ((0 1 2 3 4)) ;not what I expected.
(range 5)
is going to produce a sequence (depending on what you do with it). Why do you think you specifically need a list?
In Clojure, the approach is generally to program to the core abstractions and that's often the "sequence" as opposed to a concrete "collection" type @U0395MW13FT
For example:
user=> (range 5)
(0 1 2 3 4)
user=> (list 0 1 2 3 4)
(0 1 2 3 4)
user=> (vector 0 1 2 3 4)
[0 1 2 3 4]
user=> (seq (vector 0 1 2 3 4))
(0 1 2 3 4)
user=>
Even tho' the underlying concrete types are different here, all four results are seqable (or are already sequences).@U04V70XH6 i don’t really need the list. Reading “The joy of Clojure” I was toying with queues and surprised by the different resuls of (pop (vec (range 5))) vs (pop (list (range 5)))
Ah, because vectors are optimized for adding/removing items at the end whereas lists are optimized for adding/removing items at the start.
vec
is to vector
as list*
is to list
:
user=> (vec (range 5))
[0 1 2 3 4]
user=> (vector (range 5))
[(0 1 2 3 4)]
user=> (list* (range 5))
(0 1 2 3 4)
user=> (list (range 5))
((0 1 2 3 4))
user=>
We just don't use list*
much outside of macros, because we would typically use seq
to produce a sequence from a collection.list*
can be useful in macros because of this:
user=> (list* 1 2 3 [4 5])
(1 2 3 4 5)
user=>
(a bit like apply
which is also variadic and unrolls its last argument)
Great hint, list* Tho, (pop (list* (range 5))) fails as (type (list* (range 5))) is also a range. I guess the learning point is to start with the proper type.
yeah, what's the collection that serves best here
vector? map? set?
@U0395MW13FT For a little bit of closure (hehe) even though the conclusion is not to use a list
in this instance, you can use (apply list (range 5))
to get the list type you want and have pop
work on it (also seeing how pop
works differently for lists
and vecs
).
Clojure strings are Java strings, so I would be very surprised if it didn't call .length
https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length() ... The docs for that say
> The length is equal to the number of Unicode code units in the string.
oh I see, thanks. is there any way to get a count of bytes in a string? besides casting it into a byte array
You need to encode a string into a byte array using a specific charset because the number of bytes used for each character is going to be different in e.g. UTF-8 and UTF-16. And in UTF-8 the code units can be encoded as 1-4 bytes so you pretty much have to turn it into a byte array. You can do that in Clojure like this: (alength (.getBytes “Hello World” “UTF-8”))
ah, gotcha. makes sense that different encodings will give different results. thank you :))
Java stores strings in UTF-16 (ignoring under-the hood optimizations). When count
delegates to .length
, you get the number of UTF-16 code points in your string. If somehow lucky enough to be certain all your code points will stay within U+0000-U+D7FF and U+E000-U+FFFD (think Latin-1 charset), then you can consider that the same as counting "chararcters".
More likely, you will need to deal with surrogate pairs, where the the first of two points names a lookup table from which to interpret the second. So the count of code points might be wildly different from your intuitive expectation.
This Applies to all the emojis, to full support of most non-English languages, and to any support at all for most non-European languages. The complication goes even deeper, as many interpreted surrogate pairs still function merely as modifiers for other characters, e.g. diacritics or emoji skin tone colors... plus numerous other complications arising from different writing systems around the world.
As a tiny introduction, this article describes solving a small string problem while at least keeping surrogate pairs intact: https://lambdaisland.com/blog/2017-06-12-clojure-gotchas-surrogate-pairs.
Does anybody know if I can use https://github.com/cognitect-labs/test-runner to run cljc tests, and run both in clj and cljs ? If not, how would a minimal setup look like for testing cljc libraries?
this test runner is for clj only. the best solution i found so far is to use kaocha library. it's is relatively easy to configure two separate test environments. here is one of my libs for the reference - https://github.com/DotFox/matchete
@U6CN6JQ22 Here's a cljc project that has its tests run as clj via Cognitect's test runner and as cljs via clj-test-runner https://github.com/seancorfield/honeysql/blob/develop/deps.edn -- it has GitHub Actions, and auto-builds/deploys JARs to Clojars, uses tools.build
etc.
(I don't do any cljs work so this was the simplest setup for me to ensure my cljc files get tested both ways)
So what is the current simplest way to build an uberjar with deps.edn these days? I'm trying to go off this guide: https://clojure.org/guides/tools_build
I think what is happening is I add a build
alias in my deps.edn
calling in this tools.build
dependency. Then I create a build.clj
and use that example code included under the uberjar section?
I'm also creating a Dockerfile to run all this and package it up so in that Dockerfile I would have RUN clj -T:build uber
? If I'm using FROM clojure:latest
in the same Dockerfile, which I think brings in the latest JDK, will that have the proper clj tools installed? Is that what having that tools.build
dependency in my deps.edn
ensures?
I'm a little biased but I think https://github.com/seancorfield/build-clj is the "simplest" way -- it's a wrapper around tools.build
that has sane defaults and removes (hides) some of the boilerplate code.
I don't have public examples of building uber JARs with it but we use it at work for building all our production artifacts. You can look at some of my other projects to see how I use build-clj
to build library JARs for deployment to Clojars. Happy to answer any follow-up Qs you might have.
I can't answer your Docker Qs (I think using Docker for dev/build stuff just makes life more complicated -- Docker is great for standing up testing services, such as databases and search engines, but I see no benefit in trying to use it to wrap Clojure CLI stuff).
I'll check this out, thanks Sean. I have it building the uberjar but it's not finding my main
class. It's a full stack app, so the backend repo is setup like src/backend/TODO/core.clj
with a -main
function kicking it all off. So in my build.clj
I put the :src-dirs ["src/backend"]
and the main function path as :main 'TODO.core.-main
. That doesn't work and my other tweaks haven't worked.
I don't want or use Docker either and won't be using it during development. But it's the only way to currently deploy Java (clojure) apps on services like
and
which I do use and like.
Make sure you have :gen-class
in your main namespace's ns
form.
is there some config file I can modify to play around with external jars/libraries inside the clj
REPL? Also if that
If so you can follow this handy guide here: https://insideclojure.org/2018/05/04/add-lib/
I was referring specifically to the REPL started by the clj
command outside of a project and not depending on any build tool. But, being a newbie, I'm not sure if that has any value over and above just starting a new project and adding my deps there
but I will check this link out, thanks
you can also pass a literal deps edn:
clj -Sdeps '{:deps {some/lib {:mvn/version "1.2.3"}}}
oh cool, yes this is what I want. thanks!
The user deps.edn in your Clojure config dir is available everywhere. Use aliases for containment, to avoid accidentally polluting the classpath of every project you run. You can use multiple aliases at once.
;; $HOME/.clojure/deps.edn
{:aliases
{:rebel
{:extra-deps {com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}}
:main-opts ["-m" "rebel-readline.main"]}
:spec
{:extra-deps {org.clojure/spec.alpha {:mvn/version "0.3.218"}}}}
$ clj -A:spec
$ clj -A:spec -m my.project.main
$ clojure -M:rebel:spec
and this works for Java code too right? and off any of the repos?
I'm looking to experiment with the Java bluetooth ecosystem
Thanks @U90R0EPHA. I'm still marveling over how Clojure uses maps for so many different things. It makes data structures in other languages feel almost like an afterthought, honestly.
*Also if that's not strictly useful, that's cool too