Fork me on GitHub
#beginners
<
2021-03-12
>
Audy05:03:04

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?

dpsutton05:03:12

you can check out clojure.edn/read-string

👀 3
3
💯 6
andarp14:03:15

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.

raspasov15:03:23

@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.

raspasov15:03:30

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

raspasov15:03:37

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 🙂.

noisesmith15:03:48

@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

👆 3
👍 3
noisesmith15:03:55

java is very well documented

noisesmith15:03:39

(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)

andarp16:03:06

@U050KSS8M 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.

andarp16:03:59

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.

andarp16:03:17

(And yes, I know about the clojure CLR implementation but that hardly seems a viable real-world choice)

raspasov16:03:47

@anders152 re:CLR, yes… (I have no experience with it)

noisesmith16:03:33

@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

noisesmith16:03:54

it's mature, and up to date with jvm clojure, you are just expected to use the existing dependency and build tools with it

noisesmith16:03:36

(there's less community libraries to be sure but IMHO for most libraries interop will be the best choice anyway)

andarp16:03:08

@U050KSS8M 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.

raspasov16:03:32

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#)

andarp16:03:57

Interesting!

andarp16:03:14

But to be honest I want to get away from .net 😄

raspasov16:03:59

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)

andarp16:03:39

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.

raspasov16:03:47

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

andarp16:03:03

Yep, can definitely see that. And it would honestly feel sad to just use clojure as a glue language between .net dependencies.

raspasov16:03:07

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.

raspasov16:03:24

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

andarp16:03:54

Yes, 100% guaranteed 😄

raspasov16:03:03

… depends on [io.aviso.exception …]

raspasov16:03:13

And if you look in that library, it’s doing Java interop

raspasov16:03:47

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

noisesmith16:03:54

that's chicken/egg though - there's no libraries until people write them, they don't write them until they use it

raspasov16:03:55

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)

raspasov16:03:36

juxt/time , timbre

raspasov16:03:15

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.

raspasov16:03:44

@U051SS2EU absolutely… it just requires a much bigger initial commitment to be among the first people on the island 🙂

andarp16:03:37

Yeah the ”full stack Clojure” promise is really enticing.

raspasov16:03:55

Yes… also sharing code across both is now so simple and easy via deps.edn https://github.com/raspasov/alexandria-clj

raspasov16:03:14

I have this big repo which I just require from both CLJ and CLJS

raspasov16:03:26

And require the namespace which I need… that’s all.

raspasov16:03:45

Perpetual, ever-expanding code re-use! 🙂

raspasov16:03:40

Works 100% the same, CLJ + CLJS

Michaël Salihi14:03:02

@anders152 What type of projects do you want to approch? Web development? Other?

Michaël Salihi14:03:37

Back-end / front-end?

Adrian Imanuel14:03:05

@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

andarp14:03:51

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.

andarp14:03:40

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.

andarp14:03:18

@admin055 everything to be honest. But I’m fine with putting off frontend for a bit.

Dimitar Uzunov16:03:37

@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

🎯 4
Adrian Imanuel04:03:25

I must've slept during that lecture... thanks a lot, I missed on that.

Dimitar Uzunov16:03:42

and there is also this: https://www.braveclojure.com/quests/deploy/ (jar on a linux VPS configured using Ansible)

Michaël Salihi16:03:07

@anders152 What languages and ecosystem are you comfortable with. This will perhaps allow us to give some clues on the Clojure equivalents (libraries, etc.).

andarp17:03:40

C#, F#, Python and ”modern JavaScript” i feel fairly at home with.

Michaël Salihi19:03:12

OK for begin, let's take NodeJS for eg. To which libraries do you want to have the equivalents? Express ?

teodorlu17:03:00

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("@o0.ingest.sentry.io/0");
});
Here's what I'm trying in Clojure:
(comment
  (import '[io.sentry Sentry])

  ;; source: 

  (Sentry/init (fn [options]
                 (.setDsn options "@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 "@o0.ingest.sentry.io/0")))))
  ;; =>
  ;; 1. Unhandled java.lang.IllegalArgumentException
  ;;    No matching method init found taking 1 args

  ;;
  )
Any advice?

delaguardo17:03:50

strange but there is no init static method which is taking a lambda https://getsentry.github.io/sentry-java/

3
dharrigan17:03:45

👀 3
👍 3
teodorlu17:03:30

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.

dharrigan17:03:38

No problem, have a look at the source code of the library. Maybe that will help, as it's all interop 🙂

💯 3
noisesmith18:03:11

@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

noisesmith18:03:06

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}

noisesmith18:03:20

and yeah, you could do this by reifying Consumer (or using the wrapper)

noisesmith18:03:47

you can not use a clojure fn as a lambda, but you can of course use one in the implementation of a lambda

👍 3
noisesmith18:03:21

and if my memory serves, "lambda" is a syntax, it compiles into an anonymous class implementing the implied method signature

👍 3
noisesmith18:03:15

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...

👍 3
teodorlu18:03:02

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.

noisesmith18:03:31

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

noisesmith18:03:51

(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)

👍 4
seancorfield17:03:24

@dharrigan You’ve worked with the Sentry stuff, yes?

afry17:03:50

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!

teodorlu17:03:23

It's shorthand for namespace qualified keywords used as keys in maps.

👍 3
afry18:03:36

Thanks! Now I've got something to google.

teodorlu18:03:04

A bit terse response, I was on my phone. Does this help?

(= {:foo/bar 1}
     #:foo{:bar 1})
  ;; => true

teodorlu18:03:41

the #:key{} notation is present to simplify maps with namespaced keys.

teodorlu18:03:11

{: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 🙂

afry19:03:29

Ahh, ok, really appreciate the followup. Not terse at all 🙂

👍 4
dharrigan17:03:26

@teodorlu I look after the sentry-clj (for the moment)

👍 3
dharrigan17:03:59

The documentation shows how to use it, along with some examples in the examples directory

👍 3
Jens18:03:39

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.

Henri Schmidt21:03:52

It would be straightforward to write a recursive descent parser for this grammar.

Henri Schmidt21:03:27

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.

Noah Bogart18:03:33

i thought keywords couldn't start with numbers, but the clj repl lets me type it in no issue

andy.fingerhut18:03:01

They are not officially documented as supported, but due to legacy code bases that used them, they are allowed.

Noah Bogart18:03:12

should i avoid them?

andy.fingerhut18:03:52

That might depend on what you want to do with them, but certainly seems like you would hit fewer issues overall by avoiding them.

andy.fingerhut18:03:14

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.

Noah Bogart18:03:08

i'm storing data in mongodb, and using numbered keys, which are converted to keywords when pulled out

andy.fingerhut18:03:51

I'm giving generic advice/cautions here. Someone who has worked with mongodb (I haven't) could say more about their experience, perhaps.

👍 3
Noah Bogart18:03:52

i could turn off "convert keys to keywords", but this is nested in other stuff that i want to have keyworded

Jens23:03:33

Just finished the simple parser, if anyone is interested

😁 4