Is there a way to “de-string” a string? I have a string that looks like a hash-map "{:foo \"foo\" :bar \"bar\"}"
, and I need it to just be the hash map. str
makes a string, but is there an opposite function that just gets rid of the string?
you can check out clojure.edn/read-string
As a Clojure beginner I feel like the language makes a lot of sense and is easy to grok and get going with. But sort of opposing that is the complexity that is the ecosystem. As someone with zero experience of the JVM that of course is some degree of complexity but even larger to me is understanding how things are done, what libs are actually used, how you are supposed to deploy and run your Clojure code etc. How do people approach this? I get that all languages with some history have a degree of “you just have to learn this as you go” but to me it feels like Clojure has more so than many other languages I’ve seen. I really love the language but I feel like this complexity of ecosystem makes it hard for me to see a path forward.
@anders152 What type of projects do you want to approch? Web development? Other?
Back-end / front-end?
@anders152 yes, agree, I learned the clojure from http://braveclojure.com but up until now, I still don't have idea how to compile & deploy the code? I'm using the code for fun right now, but I've also done it to clean some data in csv to be feed into power bi. then I'm asking to myself, if i want to run it automatically, how to do that? it's still my homework to figure out... a bit slow progress than anyone else, but I'm enjoying the process
@admin055 everything to be honest. But I’m fine with putting off frontend for a bit.
Yeah that mirrors my journey somewhat. I’ve read a number of books and I’m trying to focus on the “real world” stuff I can find. But the truth is I have a hard time even knowing if I’m learning the way or just a way of doing stuff. Which goes for exploring libraries as well.
I think it’s just an effect of Clojure being 1) highly community-driven and 2) situated in the JVM ecosystem which I have no experience in.
@anders152 Not to discount the issue, but isn’t that an issue with any new language/environment? For example, I was learning about Machine Learning a few months back quite actively, and just learning anything around python like setting up the environment, etc felt very foreign and complex. And in some ways it is way more complex than the JVM, because Python suffers the worst case of “works on my machine” - almost everything is related to how your environment is setup and can just break in a version upgrade of MacOS for example (which it did for me). So there’s tools/setups to mitigate that problem but you need to learn those… I spent a day or two learning those tools and my experience improved. If you have any specific question, feel free to ask. You mentioned deployment. One straightforward approach for deployment which I’ve used is: 1. make an uberjar 2. put it in a docker container 3. deploy Now each step has complexity within, but I would say that’s equivalent to any other language/ecosystem.
Perhaps you’re right that Clojure has less step-by-step tutorials how to do common things. Or that you need to assemble the knowledge/steps from different library README’s . For example here’s a guide I’ve used to make an uberjar out of a deps.end project: https://github.com/tonsky/uberdeps
Do you have any previous experience in a language/ecosystem? I came to Clojure with zero Java/JVM experience (was writing OOP PHP before Clojure) so I can relate 🙂.
@anders152 what I've always relied on is
• learning how to turn a clojure project into a vanilla fat jar (`lein uberjar` or depstar
are the right choice for 99% of projects IMHO)
• following instructions for java project deployment
java is very well documented
(there are some gotchas - eg. gen-class with your own main is a default, but using clojure.main is often better, but this is a good 80% approach to get what you need)
@adrianimanuel the first chapter of braveclojure shows how to build a JAR and run it, but you mention running it automatically. If you mean to run it as a restartable service your might want to run it using systemd for Linux, here is a simple guide: https://computingforgeeks.com/how-to-run-java-jar-application-with-systemd-on-linux/ If you prefer Windows you can try https://nssm.cc to setup a windows service. Then of course you can put the JAR in a Docker image and run the container in Kubernetes or Nomad if you need plenty of features. https://hub.docker.com/_/clojure - a good starting point might be this
and there is also this: https://www.braveclojure.com/quests/deploy/ (jar on a linux VPS configured using Ansible)
@raspasov I have about ten years experience in .net/C# development, and I could see how someone coming to that ecosystem today would be quite overwhelmed with all the history of the language and all its kinks and quirks, but its also quite easy to follow a beaten path with clear "this is the modern way of doing stuff"-type tutorials. But .net has millions of Microsoft dollars behind it and I can see the differences in the whole community and culture of course.
But if Clojure was running on the CLR as a first-class citizen I would also feel zero stress about "getting the ecosystem" since I have all the experience of that already. And that is what I think many coming from the JVM to Clojure have.
(And yes, I know about the clojure CLR implementation but that hardly seems a viable real-world choice)
@anders152 re:CLR, yes… (I have no experience with it)
@anders152 the only thing that makes clr clojure not seem like a real world choice is that it relies on clr tooling instead of having a build tool like lein or deps.edn
it's mature, and up to date with jvm clojure, you are just expected to use the existing dependency and build tools with it
(there's less community libraries to be sure but IMHO for most libraries interop will be the best choice anyway)
@raspasov Regarding it being an issue for all languages... yes - of course, to an extent. But I am very interested in exploring different languages and have done so for a long time. I find Clojure to be an extremely refreshing and interesting language but I have a hard time recalling when I ever felt as lost in terms of understanding the ecosystem and everything else around the actual language. Maybe elixir, which has a few commonalities.
Way less community libraries 🙂 (not discounting the quality of Clojure CLR itself)… it really depends on what you’re doing with it… if you don’t need interop-heavy libs + you have a ton of experience with C# development, perhaps it’s worth trying it out! (sounds like a good fit for someone like @anders152 with a ton of experience in C#)
Interesting!
But to be honest I want to get away from .net 😄
But once you need an HTTP library in Clojure… you might be back to object interop with whatever is in C#? (I have no idea about Clojure CLR ecosystem)
Yeah I mean assuming it's running on the CLR it has access to all of .net framework (aka "the standard library" and then some) so that's not a problem.
For somebody with experience in C# I bet it’s not 🙂 But coming to Clojure some years ago with zero Java experience, it was definitely nice to use idiomatic Clojure library wrappers around Java libs/frameworks to start with
Yep, can definitely see that. And it would honestly feel sad to just use clojure as a glue language between .net dependencies.
The main things are HTTP clients and HTTP server libraries/frameworks… The mature/established ones are usually wrappers around existing libraries. And most database drivers, those also.
Nice to have idiomatic wrappers around those… Many other things should be re-usable in Clojure CLR (But again… you need to check…) if the library is doing even a bit of Java interop in, I assume it will fail to load in CLR
Yes, 100% guaranteed 😄
Even something like this (super nice logging library IMO): https://github.com/ptaoussanis/timbre/blob/master/src/taoensso/timbre.cljc
… depends on [io.aviso.exception …]
And if you look in that library, it’s doing Java interop
So it won’t work… it seems like you’ll be doing a ton of extra work on CLR, or at least lose a ton of great Clojure libraries… Doable, but definitely “you’re on your own” kind of experience
that's chicken/egg though - there's no libraries until people write them, they don't write them until they use it
The zuper big win in Clojure for me, for example, is the fact that 90% of the modern Clojure code works exactly the same in Clojure and ClojureScript (and most libraries that are useful in both are designed to “just work” in both)
juxt/time , timbre
I was SO excited when I got juxt/time working … the fact you can have a date time library work 99% the same across both platforms is just so nice.
@noisesmith absolutely… it just requires a much bigger initial commitment to be among the first people on the island 🙂
Yeah the ”full stack Clojure” promise is really enticing.
Yes… also sharing code across both is now so simple and easy via deps.edn https://github.com/raspasov/alexandria-clj
I have this big repo which I just require from both CLJ and CLJS
And require the namespace which I need… that’s all.
Perpetual, ever-expanding code re-use! 🙂
Talking about dates… https://github.com/raspasov/alexandria-clj/blob/main/src/ax/time.cljc
Works 100% the same, CLJ + CLJS
@anders152 What languages and ecosystem are you comfortable with. This will perhaps allow us to give some clues on the Clojure equivalents (libraries, etc.).
C#, F#, Python and ”modern JavaScript” i feel fairly at home with.
Hello! I'm trying to use the https://docs.sentry.io/platforms/java/ from Clojure, but I'm hitting interop problems. This is the java example from the docs:
import io.sentry.Sentry;
Sentry.init(options -> {
options.setDsn("<https://examplePublicKey>@o0.ingest.sentry.io/0");
});
Here's what I'm trying in Clojure:
(comment
(import '[io.sentry Sentry])
;; source: <https://docs.sentry.io/platforms/java/>
(Sentry/init (fn [options]
(.setDsn options "<https://examplePublicKey>@o0.ingest.sentry.io/0")))
;; =>
;; 1. Unhandled java.lang.IllegalArgumentException
;; No matching method init found taking 1 args
;; Can we use reify? Is my problem that Clojure functions arent valid java lambdas?
(Sentry/init (reify java.util.function.Consumer
(accept [this options]
(doto options
(.setDsn "<https://examplePublicKey>@o0.ingest.sentry.io/0")))))
;; =>
;; 1. Unhandled java.lang.IllegalArgumentException
;; No matching method init found taking 1 args
;;
)
Any advice?@dharrigan You’ve worked with the Sentry stuff, yes?
When I inspect a ring request map on a server which is using the ring-anti-forgery
middleware, I'm seeing this in the REPL:
{:session #:ring.middleware.anti-forgery{:anti-forgery-token "Some-big-long-CSRF-token"}}
What's up with the #:ring.middleware.anti-forgery
piece that's in front of the session object? At first I thought it might be metadata or something, but I'm not sure why it's there, or whether I need to care about/can interact with it or not. Or if it might trip me up in subtle ways!@teodorlu I look after the sentry-clj (for the moment)
strange but there is no init static method which is taking a lambda https://getsentry.github.io/sentry-java/
The documentation shows how to use it, along with some examples in the examples directory
<https://cljdoc.org/d/io.sentry/sentry-clj/4.3.143/doc/readme>
Thanks, I realize I didn't look very hard. Still want to learn what I did wrong above, I'd like to learn a bit more about Java interop.
No problem, have a look at the source code of the library. Maybe that will help, as it's all interop 🙂
It's shorthand for namespace qualified keywords used as keys in maps.
Thanks! Now I've got something to google.
A bit terse response, I was on my phone. Does this help?
(= {:foo/bar 1}
#:foo{:bar 1})
;; => true
the #:key{}
notation is present to simplify maps with namespaced keys.
{:person/name "Teodor"
:person/age "Not too old"
:person/preferred-pet :dog}
#:person{:name "Teodor"
:age "Not too old"
:preferred-pet :dog}
The latter lets you avoid repeating person
for each key 🙂Here's the official docs: https://clojure.org/guides/weird_characters#_and_namespace_map_syntax
If you have a file like this:
param1: 1
param2:
subparam1: 1
subparam2: 2
param3: 3
...
and you wnat to convert that into a nested map {"param1" 1 "param2": {"subparam1" 1, "subparam2": 2 }, "param3": 3}. How would you do this in an efficient way in clojure? Im experimenting with partition-all, but cannot really get it right.i thought keywords couldn't start with numbers, but the clj
repl lets me type it in no issue
They are not officially documented as supported, but due to legacy code bases that used them, they are allowed.
should i avoid them?
https://michaeldadams.org/papers/layout_parsing/LayoutParsing.pdf
That might depend on what you want to do with them, but certainly seems like you would hit fewer issues overall by avoiding them.
e.g. use cases like using them as keys in maps that you write to JSON, and expect to read back? Using them as keywords to database APIs that might convert them in varying ways to SQL table field names? etc. If you just use them inside of your own Clojure program and they never become visible outside, then should be no issues.
i'm storing data in mongodb, and using numbered keys, which are converted to keywords when pulled out
I'm giving generic advice/cautions here. Someone who has worked with mongodb (I haven't) could say more about their experience, perhaps.
i could turn off "convert keys to keywords", but this is nested in other stuff that i want to have keyworded
cool, thanks
@teodorlu the fn
macro creates an object of type clojure.lang.IFn, which methods like call, invoke, and applyTo for usage as a first class function
so yes, clojure functions are not java lambdas (they do not implement interfaces like Consumer - this is easy to check in a repl by the way
user=> (supers (class (fn [])))
#{java.lang.Runnable java.util.Comparator clojure.lang.IFn clojure.lang.Fn java.util.concurrent.Callable java.io.Serializable clojure.lang.IMeta clojure.lang.AFunction clojure.lang.AFn clojure.lang.IObj java.lang.Object}
and yeah, you could do this by reifying Consumer (or using the wrapper)
👍
you can not use a clojure fn as a lambda, but you can of course use one in the implementation of a lambda
and if my memory serves, "lambda" is a syntax, it compiles into an anonymous class implementing the implied method signature
and clojure has macros for adding syntax, but out of the box it has no such syntax, and the way clojure works with types, it would not look as streamlined as the java version...
I suspect I'd have to dig a bit deeper into how the Java code works to find out what kinds of types it was expecting. sentry-clj used SentryOptions.
yeah, I did a search for the javadoc but all I found was api docs for a REST endpoint - if that means Sentry is a REST service and the java classes are a wrapping of that into java world, I'd skip that nonsense and use something like clj-http
(eg. similar to ,the way cognitect made a AWS API lib that uses REST / JSON directly, instead of making a clojure flavored wrapper over a java flavored wrapper of a data oriented API)
OK for begin, let's take NodeJS for eg. To which libraries do you want to have the equivalents? Express ?
Ahh, ok, really appreciate the followup. Not terse at all 🙂
It would be straightforward to write a recursive descent parser for this grammar.
I would also simplify the problem and write a parser for only a single param, as they are layed out linearly it is no problem to adapt.
Just finished the simple parser, if anyone is interested
https://gist.github.com/jensb1/f33c8512b66dfdf4d84f55603a654a05