Fork me on GitHub
#beginners
<
2022-05-18
>
Michael Agres00:05:58

I'm practicing with keywords and maps. I set up a nest map: {:name {:first "John" :middle "Jacob" :last "Jingleheimershmidt" :suffix "Esq."}} and I can get this to work: (:last {:first "John" :middle "Jacob" :last "Jingleheimershmidt" :suffix "Esq."}) ;; "Jingleheimershmidt" But I get a syntax error when I try this: (:last {:name}) ; Syntax error reading source at (REPL:256:15). ; Map literal must contain an even number of forms How do I properly pull up the value for the :last keyword from a nested map? And what other benefits do nested maps offer?

Darin Douglass01:05:10

maps are a key-value structure: so you have to supply (as the error says) an even number of forms

;;             +-- you're missing this
;;             V
(:last {:name "John"})
when you’re dealing with nested maps you can:
;; chain multiple calls
(:inner (:outer {:outer {:inner 42}}) ;; 42
;; use `get-in`
(get-in {:outer {:inner 42}} [:outer :inner]) ;; 42

👍 1
kennytilton09:05:38

I am not a fan of Clojure threading macros, but this is one good use case:

(let [m {:name {:first "John" :middle "Jacob"
                  :last "Jingleheimershmidt" :suffix "Esq."}}]
    (-> m :name :last))

practicalli-john10:05:47

There are some simple examples of creating and accessing maps here https://practical.li/clojure/data-structures/hash-maps/

Michael Agres00:05:03

@U02EA2T7FEH 1. I tried your first example, but it yielded nil 2. Why do I need to restate a value from the nested map if I'm trying to output it?

manas_marthi04:05:56

Hi All, which library should I use for TCP or UDP socket communication setup . Besides, is there any library as a wrapper for vert.x in clojure?

1
Ferdinand Beyer06:05:07

Not sure about vert.x One option for asynchronous TCP + UDP server/client is Aleph: https://github.com/clj-commons/aleph

Chris Clark08:05:24

I'm also trying to make a socket server! I'm starting with the minimal example from this article: https://github.com/clojure-cookbook/clojure-cookbook/blob/master/05_network-io/5-10_tcp-server.asciidoc. I'm interested in what you end up using, and what others suggest. aleph looks interesting.

Rambabu Patina10:05:28

Hi, How we can include and consume JavaScript library(which is available through CDN) in Clojure? do we need to make the library compatible prior to include?

practicalli-john10:05:42

http://cljsjs.github.io/ has a number of JavaScript libraries than can be used with any CojureScript project without any specific tooling. They are added and required as any other dependency. Additional Libraries and new versions can be added by including an externs file for the library. More details on that website. Otherwise, JavaScript can also be used from npm packages, using figwheel-main or shadow-cljs projects

zakkor13:05:27

How can I kill a long running backgroudn program in the REPL, like a http server for example? Also additional question, but how can I get better REPL feedback for functions that take a long time to complete. There is no feedback given until the command ends

practicalli-john15:05:29

You could use a def to hold a reference to the server instance and then call .stop with that reference. https://practical.li/clojure-web-services/app-servers/simple-restart.html Http-kit allows for a gracious timeout before shutdown Or use an atom to hold the reference to the server, using defence https://practical.li/clojure-web-services/app-servers/atom-based-restart.html When other services within the application also need to be restarted, then mount, component or integrant projects could be used to manage the lifecycle of services and state

practicalli-john15:05:47

Adding printlln, tap> or a logging framework (e.g. mulog) could be used to give feedback in long running processes

jumar16:05:38

You can also use future to run a long running process in another thread so it doesn't block the repl

ghadi13:05:26

generally, save a reference/handle to that http server somewhere (like in a var) then you can call whatever that server's "stop" functionality is

👍 1
sheluchin15:05:15

I have some state management functions that I call from my nREPL using requiring-resolve. It seems a bit buggy, I guess because definitions don't get updated in the REPL after I change some code. Is there a better way to call those functions than with requiring-resolve?

delaguardo15:05:27

why you need requiring-resolve?

sheluchin15:05:10

I can't remember exactly how I arrived at this TBH. I think I was trying to make the call as short as possible. It looks like this:

(defn start-app []
  (nrepl-eval 9000 "((requiring-resolve 'development/start))"))
Can you suggest a better approach? I know use with :reload-all might be helpful, but I'm not sure how to improve this.

delaguardo15:05:56

I don't know what nrepl-eval is.

delaguardo15:05:16

is it to execute some code on remote jvm?

sheluchin15:05:36

It's just a primitive nREPL client that accepts a string to execute in a running nREPL instance. Basically yes, close enough to executing some code on a remote JVM.

delaguardo16:05:33

so you run nrepl instance somewhere, start separate repl and start your app using start-app function and then you change code that runs on that nrepl instance and try to start your app again and it uses old definitions, right?

dorab16:05:13

The following seems to work

clojure
myorg.example> (defn f [] 10)
#'myorg.example/f
myorg.example> (f)
10
myorg.example> 
user> ((requiring-resolve 'myorg.example/f))
10
user> 
myorg.example> (defn f [] 42)
#'myorg.example/f
myorg.example> 
user> ((requiring-resolve 'myorg.example/f))
42
user> 
So, my guess is that the new definitions are not being updated in the remote nrepl server.

sheluchin16:05:07

• run nrepl • start separate repl > start-app • change code • start new repl > restart-app => definitions are not updated But when I do it manually by going to the new code in my editor and requiring it, it works as I expect (with new definitions). I would like to script this manual process.

delaguardo16:05:56

@U0AT6MBUL it works because you "load" definition if you change the file it wouldn't

sheluchin16:05:14

(editor connected to same nREPL)

delaguardo16:05:58

@UPWHQK562 it sounds like you run everything in one jvm, then why you need restart repl after editing the code?

hiredman16:05:27

require doesn't reload a namespace that is already loaded

hiredman16:05:41

and requiring-resolve uses require

delaguardo16:05:56

(defn start-app []
  (nrepl-eval 9000 "(require 'development :reload-all) (development/start)"))
try this

delaguardo16:05:23

but from my point of view your workflow sounds way overcomplicated than it could be. obviously I miss a lot, just thinking "if I have to maintain the project with such workflow"

sheluchin16:05:10

@U04V4KLKC my repl that I use to issue the commands is ephemeral. To really get into the weeds on what I'm doing: I'm using babashka tasks to create a project command pallet in my editor. Stuff like restart app, create backup, etc.. So when I pull up the pallet and pick a task, it executes the babashka task in a short-lived repl and then that's done.

sheluchin16:05:58

The tasks use that nrepl-eval thing to connect to the running nREPL and execute stuff.

delaguardo16:05:52

normaly I would run those tasks directly from my editor connected to the same repl

delaguardo16:05:02

at the end it is exactly what happen with nrepl-eval, but without babashka as a middleman.

delaguardo16:05:18

and when the code is stable and ready for release - wrap the script to execute those functions, probably with babashka

sheluchin16:05:44

Yeah, but I like having a command pallet I can pull up from anywhere without having to navigate around my codebase. And it keep the editor configuration lean and allows me to reuse those tasks in different environments. For sure there are other ways to do it, but I'm generally happy with it. I'll give your snippet a shot when I'm back at the keyboard. Thank you!

delaguardo16:05:24

There is a good trick in clojure. Add somewhere in your class path file user.clj It will be loaded automatically right after repl start. And you can keep all operational code snippets inside.

seancorfield17:05:46

If you are changing code in a file, I would recommend always evaluating each top-level form as you make changes so the connected REPL is always up to date. Just changing code on disk without updating what is in your running REPL is always going to get you into states where you're out of sync. When I'm editing code, I don't even bother saving it very often -- I just eval each top-level form as I'm making changes (so my REPL has the latest version of each function and the on-disk version may be behind that -- which doesn't matter to me since I will eventually save the file once I've finished making changes).

👍 1
sheluchin19:05:08

Thanks for the tips @U04V70XH6 and @U04V4KLKC. @U04V70XH6 that workflow makes me wonder if there's some way to configure an editor to highlight forms that aren't in state. Like the git gutter plugins that show you which lines are changed in the working copy.

lepistane15:05:23

Ultra noob question incoming as i have failed to find answer to this online. Is it possible to compile small Clojurescript namespace and use it from plain javascript? Are there any examples of this?

delaguardo15:05:55

datascript is a great example

lepistane16:05:21

@U04V4KLKC i check it out but i am failing to understand how it all fits together... 😞 thanks for recommendation i am probably missing knowledge

delaguardo16:05:32

I have a library where I made release as js package based on datascript https://github.com/xapix-io/axel-f/blob/master/.github/workflows/publish.yml#L102-L123 maybe you find it a little bit simpler to understand