Fork me on GitHub
#beginners
<
2023-05-28
>
Uli06:05:03

Hi there. I followed https://practical.li/blog/posts/clojure-web-server-cli-tools-deps-edn/ to get my app bootstraped. To to html stuff I'm using hiccup. I start my repl and the webapp like this:

ฮป ยฑ clojure -M:repl/rebel
nREPL server started on port 35173 on host localhost - 
[Rebel readline] Type :repl/help for online help info
user=> (require '[de.schinz.webtw-backend])
nil
user=> (in-ns 'de.schinz.webtw-backend)
#namespace[de.schinz.webtw-backend]
de.schinz.webtw-backend=> (-main)
INFO: Starting httpkit server on port: 4040
#function[clojure.lang.AFunction/1]
de.schinz.webtw-backend=>

noonian07:05:40

Hello ๐Ÿ™‚ Typically people re-evaluate modified code by sending code to the repl from their editor (https://clojure.org/guides/repl/enhancing_your_repl_workflow#editor-integrations) For a webserver, there are a few tricks to make the server pick up the changes, like referring to your handler function using var syntax #'handler . Basically, as you write functions or modify existing ones, place your cursor on the form and hit a key binding to evaluate the form in the repl. There is also the "reloaded" workflow, and libraries that implement the pattern (e.g. integrant). If you are new to Clojure, I highly recommend getting comfortable sending forms to the repl from your editor for evaluation.

Uli08:05:20

@U052PH695 thank you for that. I'm already using my editor integration, it just shows not perfectly, how the image is placed in relation to the text or something, for that i need the browser... Im gonna give a hit to the var syntax, maybe this helps, thank you again โค๏ธ

๐Ÿ‘ 2
noonian10:05:29

With the var syntax, after you re-define your handler function the server should use the new code. You still have to remember to re-evaluate the handler function (and any changed functions it depends on) to see your changes

Uli06:05:08

what I'm missing now is the hot-reload option. While templating my hiccup stuff, I always have to stop my repl and start over again. is there a way to get this "hot-reloaded"?

Andrew Carlile17:05:21

hi, I'm trying to build a Reitit server/reagent client from scratch. I had this working last night, but had to start over due to PEBCAK, and now neither the server nor the client respond to requests. Expected Behavior: run 'lein run' and in another terminal 'curl 127.0.0.1:3000' to see 'Hello World!; Actual MisBehavior: curl command hangs indefinitely Expected Behavior: run "lein fig" and navigate in browser to http://localhost:9500 and see Welcome Message Actual MisBehavior: the browser window never actually loads any page at all https://github.com/jollyblondgiant/StrEats What am I missing?

hiredman17:05:30

Oh, you have join false, so the main thread isnt waiting for jetty to exit, so main thread stops after starting jetty, and depending the jvm may just exit after that

hiredman17:05:39

So you want join true

Andrew Carlile17:05:28

I think there may have been some issue with my Java cache, because I restarted my host machine and tried again and everything works. Thanks @U0NCTKEV8 for the replies

James Amberger19:05:22

core.async: a channel you got by evaluating a goblock will only ever give you zero or one val, is that right?

โœ… 1
hiredman19:05:11

Complicated

hiredman19:05:54

It is just a regular channel, so after launching the go block you can hand it off to some other code that writes other values to it

๐Ÿ™Œ 1
hiredman19:05:08

But that is a crazy thing to do

hiredman19:05:26

But the only thing the go block does with the channel is write the return value of the go block (if the return is not nil) then close the channel

๐Ÿ‘ 2
xbrln19:05:56

Question about extracting away try catch (please see ๐Ÿงต for more details)

xbrln19:05:35

When I write this I get nil as response.

(try
   (/ 10 0)
   (catch Exception e
     )) 
But when I extract the try catch away and call it like this I get
(defn my-try-catch
   [f]
   (try
     f
     (catch Exception e
       )))

 (my-try-catch (/ 10 0))
Execution error (ArithmeticException) at user/eval43293 (user.clj:1). Divide by zero Any idea why I do not get nil here ? (Reason for doing this. To extract away try catch and to have one place where try catch is executed with logging vs it being repeated throughout the code.)

delaguardo20:05:20

every function must evaluate it's arguments before the call. so, at first (\ 10 0) called throwing an exception that you see.

jpmonettas20:05:00

that is one of the uses of macros, to control argument evaluation. So for that you would have to use a macro like this :

(defmacro my-try-catch
  [& body]
  `(try
     ~@body
     (catch Exception e#)))

(my-try-catch (/ 10 0))

xbrln15:05:19

Thank you for the answers ๐Ÿ™‚ I am not experienced with macros and I prefer to avoid it if I can, so I tried it with higher order functions.

(defn my-try-catch
    [f]
    (try
      (f)
      (catch Exception e
        ;; log exception and return nil
        )))

  (my-try-catch (fn [] (/ 10 0)))

jpmonettas16:05:46

Hey, yeah, macros take some time to wrap your head around, but this are good opportunities to start playing with them. A Clojure macro is just a normal Clojure function, that will be called at compile time with the arguments without being evaluated. So if my-try-catch is a function, it will be called with the result of (/ 10 0), while if it is a macro it will be called with a list containing the / symbol, the 10 and the 0. Whatever the my-try-catch macro returns will be used as code instead of (my-try-catch (/ 10 0)) You can also write a similar macro without all the fancy symbols, which could look like this :

(defmacro my-try-catch
  [form]
  (list
   'try
   form
   '(catch Exception e
      )))
So you give it a form (could be anything) and it will just create a list containing the try symbol, then the provided form, and then another list with the catch, Exception and e symbols. you can see what the macro expands to by doing :
=> (macroexpand '(my-try-catch (/ 10 0)))

(try (/ 10 0) (catch Exception e))
I hope that helps

xbrln17:05:22

Wow! Thanks a lot for taking your time to explain ๐Ÿ™‚ I will definitely try them out. Are there any pitfalls one has to be aware of while using macros?

jpmonettas18:05:23

nothing special! they are just functions, they get the code as argument (just data) and the returned data will be used as code instead of the original call. Learning about the backquote(`) is not mandatory for macros, but pretty useful since you can use them as "templates" when generating code

Michael Agres22:05:12

I'm trying to create a Fibonacci Sequence function for this 4clojure problem: https://4clojure.oxal.org/#/problem/26 I saw the lazy-seq function on http://clojuredocs.org. But how do I adapt it to fit the format that 4clojure's looking for? (I really prefer not to look at the answers. And I don't know whether the answer for his entails using lazy-seq or not. I tried multiple things from using range to map to apply and nothing worked.)

Bob B22:05:22

I'd say using lazy-seq directly is not necessary in this case, but it's a possible solution... if you make the sequence (trying not to give too much away because I'm not sure how much spoiling you do or don't want), you can wrap that in a one-arg function and take from that sequence

Bob B22:05:51

you might also like a function like iterate

Michael Agres23:05:33

Thanks. iterate provided a Fibonacci sample that was easier to adapt for http://4clojure.org.

hiredman23:05:43

the really clever fib lazy sequences tend to implicitly rely on the fact that top level defs are mutable reference cells that are deref'ed every time a function is invoked, and lazy sequences are constructed out of thunks (functions)

hiredman23:05:34

so generally non-starters for producing anything other than a def'ed infinite sequence, not very usefl

Michael Agres14:05:20

I was wondering why this problem was in the Easy category.